get user role in resource server from authorization server - spring-boot

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)

Related

Spring Authorization Server - Configure User Info Endpoint - Spring Roles in Resource Server

I have an existing resource server that is configured to use Spring user rules as security methods. I am trying to migrate onto the Spring Authorization server and trying to figure out how these roles can be accessed in the resource server.
When the user is authentication, I can see in debug logs that my roles are part of the authorized user details. But in the resource server, I am getting default roles from OidcService and scopes as granted authorities.
I know Spring Authorization server 0.21 has implemented the User Info endpoint, but there seems to be no sample or documentation available on how to configure that, and I am sure implementing it will solve my issue.
Another option that I am thinking about is to configure oauth2TokenCustomizer in the server and then add roles in JWT's claims. Then in the resource server think about overriding default OidcService and parse claims to add roles as granted authorities. But issue is with OidcUserService i don't see any code which can give me access to JWT claims.
public class CustomOAuth2Token implementsOAuth2TokenCustomizer<JwtEncodingContext> {
#Override
public void customize(JwtEncodingContext context) {
// Load user details and add roles to claims
}
}
Probably will have to provide a custom extension for OidcAuthorizationCodeAuthenticationProvider and then modify authenticated principal details.
I was facing the same issue.
Customizing the response of the "well-known" openid-configuration endpoint is somewhat tricky because the filter handling this endpoint has hardcoded mappings for which field go and do not go in the response.
I worked around this by:
copying this class into my codebase and giving it another name, in my case CustomOidcProviderConfigurationEndpointFilter
using my custom class as an objectPostProcessor for OidcProviderConfigurationEndpointFilter replacing it entirely instead of just customizing it.
This means your custom filter will supply the OidcProviderConfiguration object from now on.
You could then call the claim method on this object to add properties such as "userinfo_endpoint".
Note: I was unable to properly format the code snippet in the second link inside this post. If someone with administrative rights could edit this in, this would be nice.

OAuth2 Open ID client authentication followed by LDAP user details & authorities

Our app is currently set up with OAuth OpenID connect authentication with an external (third-party) server. The requirement is to use user details service that loads the user from LDAP (along with the authorities/roles) to complete the authentication. So authentication.getPrincipal() should be returning the custom UserDetails object we use that gets generated by querying LDAP using the username obtained from the Open ID authentication.
I have tried the following:
Followed Similar Issue but it seems like in the answer it's setting up the server-side and it doesn't work either
Tried adding custom UserDetailsService in WebSecurityConfig
#Configuration
public class OAuth2Config extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.oauth2Login().and().userDetailsService(myCustomUserDetailsService());
}
}
where myCustomUserDetailsService() handles the call to LDAP and fetches the user details info, including the authorities.
I'm not too familiar with the spring oauth2 framework, correct me if I'm wrong: I'm guessing I need to implement my own user info endpoint to make a call to LDAP, and not the user info endpoint provided to me by the OpenID service?
You could add a new filter in the security filter chain right after that one. The second filter could retrieve the principal/name from authentication and query for users.
Like a two steps authentication
Not as clean as I hoped, but I registered an application listener on InteractiveAuthenticationSuccessEvent and manually updated the authentication after login (similar post's answer https://stackoverflow.com/a/10747856/11204609)
If anyone has better suggestions?
UPDATE: The identity provider agreed to include LDAP info in their claims so I can directly obtain via the token without having to do a call-back (still an on-going discussion at the moment). That being said, having a auth success callback app listener is only way I could solve the problem.

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.

Spring oauth2 Remotetokenservice

I have 2 microservices that I have created with spring boot. 1 microservice has a oauth2 authentication service and the other is an oauth2 resource server.
The resource server uses RemoteTokenService to check if the access token is valid. This works and when I create a rest endpoint and supply a Principal parameter the principal of the logged in user is supplied. Example:
#RequestMapping(method = RequestMethod.GET, value = "/api/user/{id:[0-9]+}")
#PreAuthorize("hasAnyAuthority('ROLE_USER')")
public User getUser(#PathVariable("id") long id, Principal principal) {
}
The thing is that the Principal contains the username and authorities of the logged in user and I also need the user info like id of the user.
I don't want to do an extra rest call to get the user data so I was wandering is there anyway to get the remotetokenservice to return more information?
The RemoteTokenServices makes nothing but calling CheckTokenEndpoint of Spring Security and return back the map values to the resources server.
If you want to get more information then you have to implement CheckTokenEndpoint::checkToken method in the Authentication server.
We managed to solve your problem by having spring-oauth2 with JWT integration. So the Authentication Server generates an access token as a claim (after authentication the user) which can hold more information that could be useful at the Resource server. The resource server in this case didn't need to have a remote call to check the token, but it verify the signature of the JWT to accept the claim.

How does Spring Security/OAuth figure out the AuthenticationPrincipal

I have a spring project that uses spring-oauth2 and spring-security for authentication using an LDAP auth provider.
In controllers I can access the current principal's UserDetails using the #AuthenticationPrincipal annotation.
However, when I hit the endpoint with a client_credential token the #AuthenticationPrincipal is a String which is the OAuth client id. I understand that there's no notion of user when you authenticate with client_credentials, but I would like to have my Principal be a richer datatype. How does spring decide to set my principal as a String and can I override that behavior?
From the Oauth2 specs
The client credentials (or other forms of client authentication) can
be used as an authorization grant when the authorization scope is
limited to the protected resources under the control of the client,
or to protected resources previously arranged with the authorization
server. Client credentials are used as an authorization grant
typically when the client is acting on its own behalf (the client is
also the resource owner) or is requesting access to protected
resources based on an authorization previously arranged with the
authorization server.
because client can also be a resource owner, therefore spring will create authentication based on your client information.
I assume that you have setup org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter which is used to create authentication for the client.
You can create your own custom org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService or create your own org.springframework.security.authentication.AuthenticationProvider to override how the authentication object is created, but I prefer to use org.springframework.security.oauth2.provider.token.TokenEnhancer to add additional information to the token generated.

Resources