Spring SSO and account creation - spring

So I'm working on a university project in which my group needs to create an android application that talks to a backend build with spring. So far we've been using JWT's for user authentication/authorization and everything was fine and dandy. However, our client wants to have single sign-on with Google and Facebook and of course to still be able to create an account, just like this form (but on android, not a browser).
I have spent the last month researching and googling how to do this and especially how it's supposed to integrate with the android app. I feel like I'm missing a key point because I see this everywhere, so I assume that is not that hard to do. As much as I understand, I can have two endpoints: login/google, login/facebook to get authorised with their authorisation server. That I have, I followed this guide and I understand 70-ish% of it.
Then my idea is to have users that are logging in for the first time to be saved in our database. I'm not entirely sure how to do that (because I'm not entire sure how the SSO spring code works..). My main questions tho are:
How to have both social login with google/fb and the ability to make an account/login with credentials.
If the user was to make an account, do I have my own authorisation server where I store credentials or do I manage that on the main server.
How do I handle that from the android app? Do I store the refresh token or do I do something else?

There are a couple of things
You want to integrate with spring-social for any social providers such as google/fb. Add the dependency and configure by following the tutorials
See https://github.com/spring-projects/spring-social/wiki/quick-start
If you also want users to create their own account, u do not need an authorization server. What u need is spring security vanilla form setup with a configuration
Something like
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login/")
.loginProcessingUrl("/j_spring_security_check")
.usernameParameter("j_username")
.passwordParameter("j_password")
.successHandler(authenticationSuccessHandler())
.failureHandler(authenticationFailureHandler())
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler())
.invalidateHttpSession(true)
}
Yes but i recommend u find an oauth library you can just plug in.. and hopefully it will handle the refresh_token logic for you.. you should not need to implement these things yourself.
I hope this helped some, these questions you asked are very broad.. but hopefully it will get you somewhere.

Related

Is there any implementation of OIDC Session Management and Logout mechanism in Spring Authorization Server for implementing Single Sing On?

I am trying to implement Single Sing On using Spring Authorization Server which is based on oAuth2 and OIDC for Authorization and Authentication respectively, but as per the Spring Authorization Server feature list OIDC support is not fully integrated. Mainly the session management and logout part, I couldn't find. Also if there's any workaround for implementing sso and logout?
Feature List URL: https://docs.spring.io/spring-authorization-server/docs/current/reference/html/overview.html
These features are still on the backlog but are not scheduled yet (as of the time of this writing). See #58 and #266 respectively to follow progress on these features.
Given that there are a number of pieces to the specifications for both of these features, I imagine it would be a bit of a hassle to attempt a fully spec-compliant implementation of them as extensions to SAS (though I'm sure it's possible). Instead, you might pick a minimal subset of the logout feature as a way to get started.
Using Spring Security configuration, you can configure a logout endpoint in a custom way. Here's some pseudocode to get you started:
#Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults())
.logout((logout) -> logout
.logoutRequestMatcher(new OrRequestMatcher(
new AntPathRequestMatcher("/logout", "GET"),
new AntPathRequestMatcher("/logout", "POST")
))
.addLogoutHandler((request, response, authentication) -> {
// Logic to validate an id_token_hint, client_id, etc.
// Throw exception in case of invalid request
})
.logoutSuccessHandler((request, response, authentication) -> {
// Get state and calculate redirect for logout success back to client
// http://127.0.0.1:8080/logout?success&state=...
// new SimpleUrlLogoutSuccessHandler()...
})
);
return http.build();
}
This assumes validation of some kind is implemented to prevent CSRF, denial of service, etc. You might also choose to add a logout confirmation page as a separate endpoint of the auth server that redirects to the logout endpoint when the user clicks a "Confirm" button, etc.
To use this, you simply redirect from your client application to the logout confirmation page, which redirects to the logout endpoint on confirm, which then redirects back to the client (which can then log out of the client automatically).

Make Keycloak authentication work with own JWT tokens generation

There's a Keycloak (KC) server in my company, and I'm working on some app.
The Backend is Spring Boot 2.6.6, Front-end is AngularJs.
When user presses 'Log In' button, user gets redirected to KeyCloak login page and enters
credentials. This part is implemented already and working fine.
But then comes a tricky part: I need to return to front-end JWT token with some granted authorities, and those authorities will depend of what application gets from it's DB for every particular user. All other endpoints will have #PreAuthorize with needed authority.
So, I can't get JWT from KC, because KC doesn't know anything about app's vision to user's granted authorities.
Can you please help with some ideas how to achieve this? Because I'm trying to implement this and getting doubts about possibility to achieve this.
One of the errors I'm getting is:
Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.
Thank you
Keycloak is OAuth2 and OpenID Connect(OIDC) protocol complaint. Which means you can use already defined patterns of authorization flows in OAuth2.
Auth2 has implementation of a step by step authorization logic called Authorization Code Flow -which is one of many but I believe is the most suitable one for your use case-. RFC docs of this flow explain it pretty well and you can find them here. You should also look at how Keycloak implementations are done.
Learning and implementing this flow on your project will provide an industry standard solution.

Why does setting sessioncreation policy to stateless break my oauth2 app

#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
Why does setting SessionCreationPolicy to STATELESS break oauth2 login?
After authenticating with facebook, the app goes on a never ending loop that eventually leads to "localhost redirected you too many times".
The loop goes like this:
Authenticate with facebook and redirect to:
Redirect-Uri - //login/oauth2/code/facebook?code=&state=
Back to facebook authorization-Uri - /oauth2/authorization/facebook
Repeat
This all happens with the SessionCreationPolicy being STATELESS. Can someone explain to my why this happens?
That's expected behavior. OAuth2 Clients need to store the tokens somehow for using them in later requests. By using a stateless session creation policy, every time you call the application, it won't find any token (i.e. it doesn't know you've already authenticated yourself in the previous request), so it will trigger again the authentication flow.
On the other hand, OAuth2 Resource Servers can be stateless, since they don't rely on any session state. Every request sent to an OAuth2 Resource Server from an OAuth2 Client provides an Access Token in the HTTP request header (which is possible because the client stores the tokens in the session).

Bypassing Full authentication is required - Spring

I have an issue. I built a Spring(+REST, AngularJS, Java and that's about the most important technologies used) application(using JHipster), but I have some difficulties testing it. I try to run requests using Postman(http://localhost:8080/api/users, for example, which is a URI generated by default when you build your JHipster application), but I get the "Full authentication is required to access this resource error". Now I imagine that this could be bypassed by using some sort of token, but I was wondering if there was something I could do to get rid of this. I mean, for example, if I wanted http://localhost:8080/api/users to be accessible without having to log in, you know, display the whole list of users on a website page to everyone, not only to those that have an account, what would I need to do?
Thank you
If you use microservices with JHipster, each microservice has MicroserviceSecurityConfiguration. There you have an overriden configure method which usually has a part like:
.and()
.authorizeRequests()
.antMatchers("/api/profile-info").permitAll()
.antMatchers("/api/**").authenticated()
You can define /api/users similar to api/profile-info. You can also play with permissions in this file and so on.
And something like this surely exists for a monolith app.

Client, Auth Server and Logout

So, i have a standalone OAuth2 auth server and client app (web-based), all using Spring OAuth2.
I have a login form host on the Auth server with redirection etc from the client app using Spring setup (via the login form).
All good so far.
I added a logout setup on the client:
.and()
.logout()
.addLogoutHandler(oauth2LogoutHandler())
.logoutSuccessUrl("/")
.clearAuthentication(true)
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.permitAll()
That all 'seems' to be fine.
However, if i then hit the 'login' link on my client, when it redirects to the Authorisation app i dont get the login screen, but simply the redirection handshake occurs and i'm back in the client app.
So, the question is, what is it need to 'clear' in the Auth server when i logout on the client app? Somehow session info is persisting on the auth app but i cant find how that session is being picked up when i hit login? is there a clean way to propagate a 'logout' to the Auth Server?
Many Thanks
Martin
https://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v#the-logout-experience describes essentially the same problem for a notoriously tricky problem.
The Logout Experience
If you click on the “logout” link you will see that the home page changes (the greeting is no longer displayed) so the user is no longer authenticated with the UI server. Click back on “login” though and you actually don’t need to go back through the authentication and approval cycle in the authorization server (because you haven’t logged out of that). Opinions will be divided as to whether that is a desirable user experience, and it’s a notoriously tricky problem (Single Sign Out: Science Direct article and Shibboleth docs). The ideal user experience might not be technically feasible, and you also have to be suspicious sometimes that users really want what they say they want. “I want ‘logout’ to log me out” sounds simple enough, but the obvious response is, “Logged out of what? Do you want to be logged out of all the systems controlled by this SSO server, or just the one that you clicked the ‘logout’ link in?” We don’t have room to discuss this topic more broadly here but it does deserve more attention. If you are interested then there is some discussion of the principles and some (fairly unappetising) ideas about implementations in the Open ID Connect specification.
Here's a PR I submitted on github for an Spring-based OpenID Connect (an extention of OAuth2) project to implement an "End Session Endpoint" on the Authorization Server: https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/pull/972. It implements part of the https://openid.net/specs/openid-connect-session-1_0.html#RPLogout spec for RP-initiated (or client-initiated) logout.
I don't think Spring has a built-in mechanism for this. There are other specifications, other than the one I partially implemented, for logout. Whichever you chose, it's probably a good idea to follow a documented spec.
You should enable the logout extending the WebSecurityConfigurerAdapter and create a logout page that send a post to /logout in the Authorization App
Logout page: (resources/templates/logout.ftl)
<html>
<head>
<title>Logout Page</title>
</head>
<body>
<form role="form" action="logout" method="post">
Logout
<input type="hidden" id="csrf_token" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<input type="hidden" id="redirect" name="redirect" value="${RequestParameters['redirect']!'/login'}"/>
<button type="submit">Logout</button>
</form>
</html>
The redirect input hidden will redirect to the client application after logout

Resources