How to get google logged in user's details in spring boot app - spring

I am implementing google login using oauth2 in spring boot app. Now I am stuck, as I don't know how to get user details. Using Authentication or Principal object I can only get username(which is some random number) with method princial.getname() method and there are no other relevant methods to get the details.

Since the OAuth2 framework is designed to be generic, you will not find methods for anything other than the principal name.
Instead, the OAuth2User class has a getAttributes method which returns the attributes from the user info uri of the specific provider as a map.
This is how you get the user object of the current request:
#GetMapping("/user/me")
public Map<String, Object> userDetails(#AuthenticationPrincipal OAuth2User user) {
return user.getAttributes();
}
Try this and you will see which exact attributes google supports.

Related

Spring: Why is it bad to return a whole OAuth2User in an endpoint?

I'm building an OAuth2 authenticated app using Spring Boot, following this tutorial: https://spring.io/guides/tutorials/spring-boot-oauth2/
At one point, the endpoint /user sends back the currently logged in user.
The guide warns by saying:
"It’s not a great idea to return a whole OAuth2User in an endpoint since it might contain information you would rather not reveal to a browser client."
But it doesn't give any more information - what type of information should I not be revealing to a browser client?
Thanks!
In Spring Security 5.x, the OAuth2User is a specific OAuth2AuthenticatedPrincipal (very similar to a UserDetails but without any notion of a password). Even without a password, exposing it can (and often will) leak sensitive information, implementation details of your authentication scheme, etc. You can expose it if you choose, but the warning in the guide is suggesting that care should be taken so as not to expose anything considered sensitive, and you should consider alternatives before exposing it directly.
For example, you might consider creating a CustomUser class that is populated from claims on the OAuth2User using a custom OAuth2UserService (various examples in the advanced configuration section of the docs). You can also take various steps to decouple the representation of an oauth2 user in Spring Security from the representation of a user in your application (e.g. by using #AuthenticationPrincipal to resolve your own custom user or access claims). If the application itself does not need a custom user, you can simply map claims of the OAuth2User to a response in your custom endpoint, as demonstrated in the guide.
Finally, you can combine all of these techniques to make your /user endpoint a "one liner" again, as in:
#Target({ElementType.PARAMETER, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#AuthenticationPrincipal(expression = "customUser")
public #interface CurrentUser {}
#GetMapping("/user")
public CustomUser user(#CurrentUser CustomUser customUser) {
return customUser;
}

How do I extract the Oauth2 access token in a Spring application using code grant flow?

I have followed this guide.
I have a simple Oauth2 webapp using code grant authorization flow. I have a #GetMapping endpoint (as per the tutorial) that returns user information retrieved from a service provider I'm using. Since this correctly returns my information to the webapp, I can tell the code grant flow has worked. Code for working endpoint:
#GetMapping("/user")
public Map<String, Object> user(#AuthenticationPrincipal OAuth2User principal) {
return principal.getAttributes();
}
Now I want to create a new #GetMapping where I use the access token to query the API of the service provider that just authorized us.
The problem is that the example above somehow magically makes the request for me based solely on configuration and only returns user info. Now I want to get the access token for this session that Spring stores somewhere to access the API however I like "manually".
How can I extract the access token in my new #GetMapping?
I have been searching a lot, but I am new to both Oauth2 and Spring, and there is so much spring classes and tutorials that I "can't see the forest because of all the trees".
I appriciate any help.
Cheers.
I solved it.
Add the following:
#Autowired
private OAuth2AuthorizedClientService authorizedClientService;
private String getSessionBearerToken() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient client =
authorizedClientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(),
oauthToken.getName());
return client.getAccessToken().getTokenValue();
}
This method will get you the access token when you call it.

Spring Security: How to use a UserDetailsService with JwtAuthenticationProvider?

I have a REST service, written using Spring MVC. The server is an OAuth2 resource server and I am using the JwtAuthenticationProvider to have the JWT parsed and turned into the Principal. This all works fine.
However, what I really want to do is to load user details from a database, using the username provided from a Claim in the JWT. Then that new Principal should replace or (ideally) wrap the Jwt so that it is available directly from the SecurityContext.
I am really struggling to see how to do this. The JwtAuthenticationProvider does not seem to work with a UserDetailsService. I also looked at doing this with a Converter - but it is not easy to extend JwtAuthenticationConverter because the convert method is final (why?).
So to be very clear, here is what I ideally want to happen:
Bearer token is presented to service.
Parse Jwt and extract claims
Use one of these claims as a key to my user database, where I can look up attributes, entitlements etc
Turn these into a new Principal object which is available in the SecurityContext's Authentication object.
The configure method in my WebSecurityConfigurerAdapter has this:
http.authorizeRequests().antMatchers("/api/*").authenticated().and().oauth2ResourceServer().jwt();
I cannot be the only person who wants to use a user database along with OAuth2, so I must be missing something fundamental? I am using Spring Security 5.2.0.
The JwtAuthenticationProvider does not support an UserDetailsService because in theory you are not supposed to have UserDetails in an application that does not manage credentials. I'm not saying that you cannot have any type of user, but the UserDetailsService will not be used or autowired by Spring Security.
You could register a bean of type JwtAuthenticationConverter, do whatever you need in the convert method and return your custom authentication token, like so:
#Component
public class JwtAuthenticationConverterAdapter implements Converter<Jwt, AbstractAuthenticationToken> {
private JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
#Override
public AbstractAuthenticationToken convert(Jwt jwt) {
var token = this.jwtAuthenticationConverter.convert(jwt);
// build your custom token with the properties from the token above
return customToken;
}
}
I agree with your concerns - and I have found it useful to override Spring's default processing. There is a claims extensibility pattern I use with some providers, where JWT handling is only one part.
I have a Spring Boot code sample that you can run - it uses a custom filter and Connect2Id classes - OAuth integration is described here. Happy to answer any follow up questions if it helps

Custom principal and scopes using Spring OAuth 2.0

I am using SpringBoot 2.0.5 and Spring Security OAuth to implement an OAuth 2.0 server and a set of client microservices.
In the AuthServer:
I have implemented the UserDetailsService so I can provide my custom enriched principal.
For the userInfoUri controller endpoint, I return user (my principal) and authorities as a map.
In the Client:
I have implemented PrincipalExtractor to extract and create my custom principal.
For each of the methods I require the principal, I use the following notation:
public List<Message> listMessages(#AuthenticationPrincipal MyPrincipal user)
This works (and I hope it's the right way) but now I'm having an issue to secure methods using scopes.
For example, if I want to have a controller method which is only accessible by another server (using client_credentials), I mark the method with the following annotation:
#PreAuthorize("#oauth2.hasScope('trust')")
But this results in an access error as I think the scope is not being transferred. I have added the scope to the userInfoUri endpoint but am unsure what I need to do on the client side so the scope is picked up.
Any pointers or example code would be very much appreciated.

get user role in resource server from authorization server

I have an authorization server which on the basis of username and password fetches the user details from the DB along with the roles.
Now while accessing the protected resource in the resource server (passing the access_token), I want to authorize the rest call on the basis of role.How do I do that ?
Because, while I am checking the Principal user in resource server, its getting the default [ROLE_USER]
//Will #preAuthorize() work here ?
#RequestMapping(value="/pinaki", method=RequestMethod.GET)
public String home(Principal principal) {
return "Hello World";
}
Please guide..Thanks in advance
AFAIK spring-security-oauth2 only supports getting the user details (including roles) for a Authorization Server/Ressource Server that share a common data store (either database or in memory)out of the box.
If you do have a common data store you can use the InMemoryClientDetailsService or JdbcClientDetailsService.
However it should not be too hard to extend this by yourself if in your setup there is no common data store. The key interfaces for this task are ClientDetailsService and ResourceServerTokenServices.
A ResourceServerTokenServices implementation returns a OAuth2Authentication including roles. So you could call the tokeninfo endpoint from the authorization server here.
Implementing a ClientDetailsService and using that would be more elegant. Here also you would need to call the tokeninfo endpoint.
In XML configuration you can setup the beans to use in the oauth:resource-server tag in the parameters token-services-ref and auth-details-source-ref.
Details on the Java config can be found on page http://projects.spring.io/spring-security-oauth/docs/oauth2.html
(My info refers to version 2.0.8 of spring-security-oauth2)

Resources