Showing posts with label spring-security-oauth2. Show all posts
Showing posts with label spring-security-oauth2. Show all posts

Monday, October 8, 2018

Spring secure endpoint with only client credentials (Basic)

Leave a Comment

I have oauth2 authorization server with one custom endpoint (log out specific user manually as admin) I want this endpoint to be secured with rest client credentials (client id and secret as Basic encoded header value), similar to /oauth/check_token.

This endpoint can be called only from my resource server with specific scope.

  1. I need to check if the client is authenticated.
  2. I would like to be able to add @PreAuthorize("#oauth2.hasScope('TEST_SCOPE')")on the controller`s method.

I could not find any docs or way to use the Spring`s mechanism for client authentication check.

EDIT 1

I use java config not an xml one

1 Answers

Answers 1

@PreAuthorize("#oauth2.hasScope('TEST_SCOPE')") On the controller method should be sufficiënt. If the client is not authenticated, no scope is available and the scope check will fail.

If you want, you can use the Spring Security expression @PreAuthorize("isAuthenticated()") to check if a client is authenticated: https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#el-common-built-in

You could also configure the HttpSecurity instead of working with @PreAuthorize

Read More

Saturday, September 8, 2018

Using multiple OAuth2 clients in single browser session using Spring boot

Leave a Comment

We have Multi tenant WebApp designed using Spring Boot + Spring Security. This app is used to manage certain resources in Azure. User login into our WebApp using OAuth2.0 and can access Azure resources through our app.

Now we need to allow multiple users to login into our app in single browser session. So basically user (user 1) will use credentials1 to login to access resources allowed by these credentials. Then user will use credentials2 (basically another users credentials lets call it user2) to login into same browser page. There will be two active users in same session. User should be able to switch between these accounts.

Once user login into our app, we instantiate RestTemplate (using credentials entered) to access Azure resources.

Either we can have single JSession id mapped to multiple RestTemplate or multiple JSession ID (within single JSession cookie) to mapped to individual RestTemplate. We can have request parameter indicating which RestTemplate to use.

We have used SpringSecurity to get access token. This access token is then used in RestTemplate and used for accessing Azure resources.

1 Answers

Answers 1

"Now we need to allow multiple users to login into our app in single browser session"

Is this approach secure, at all? I mean, having two users using the same browser and sharing information isn't recommended.

"Either we can have single JSession id mapped to multiple RestTemplate or multiple JSession ID (within single JSession cookie) to mapped to individual RestTemplate"

I never saw this kind of approach. Get Google as an example -- you can switch profiles, but need to log in.

If you really need to do it, there's an out of the box solution for Chrome, Firefox and Opera called SessionBox, that enables session switch within the same browser. Otherwise, two common solutions are:

  • Use two different browsers (e.g. Chrome and Firefox)
  • Use incognito mode
Read More

Wednesday, July 11, 2018

How to configure Resource Server in Spring Security for it to use additional information in JWT token

Leave a Comment

I have an oauth2 jwt token server configured to set additional info about the user authorities.

@Configuration @Component public class CustomTokenEnhancer extends JwtAccessTokenConverter {      CustomTokenEnhancer(){         super();     }      @Override     public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {         // TODO Auto-generated method stub         MyUserDetails user = (MyUserDetails) authentication.getPrincipal();         final Map<String, Object> additionalInfo = new HashMap<>();         @SuppressWarnings("unchecked")         List<GrantedAuthority> authorities= (List<GrantedAuthority>) user.getAuthorities();         additionalInfo.put("authorities", authorities);          ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);          return accessToken;     }  } 

I am not sure how to configure my resource server to extract the user authorities set by the oauth2 server and use that authority to be used for @Secured annotated controllers in Spring Security framework.

My Auth server configuration looks like this:

@Configuration @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter {      @Value("${config.oauth2.privateKey}")     private String privateKey;      @Value("${config.oauth2.publicKey}")     private String publicKey;      @Value("{config.clienturl}")     private String clientUrl;      @Autowired     AuthenticationManager authenticationManager;      @Bean     public JwtAccessTokenConverter customTokenEnhancer(){          JwtAccessTokenConverter customTokenEnhancer = new CustomTokenEnhancer();         customTokenEnhancer.setSigningKey(privateKey);          return customTokenEnhancer;     }      @Bean     public JwtTokenStore tokenStore() {         return new JwtTokenStore(customTokenEnhancer());     }       @Override     public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {         oauthServer                 .tokenKeyAccess("isAnonymous() || hasRole('ROLE_TRUSTED_CLIENT')") // permitAll()                 .checkTokenAccess("hasRole('TRUSTED_CLIENT')"); // isAuthenticated()     }       @Override     public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {         endpoints           .authenticationManager(authenticationManager)         .tokenStore(tokenStore())         .accessTokenConverter(customTokenEnhancer()) ;     }      @Override     public void configure(ClientDetailsServiceConfigurer clients) throws Exception {          String url = clientUrl;          clients.inMemory()           .withClient("public")          .authorizedGrantTypes("client_credentials", "implicit")         .scopes("read")         .redirectUris(url)          .and()           .withClient("eagree_web").secret("eagree_web_dev")         //eagree_web should come from properties file?         .authorities("ROLE_TRUSTED_CLIENT")          .authorizedGrantTypes("client_credentials", "password", "authorization_code", "refresh_token")         .scopes("read", "write", "trust")          .redirectUris(url).resourceIds("dummy");     } } 

And my Resource Server configuration looks like this:

@Configuration @EnableResourceServer public class ResourceServerConfiguration  extends ResourceServerConfigurerAdapter {        @Value("{config.oauth2.publicKey}")     private String publicKey;      @Autowired     CustomTokenEnhancer tokenConverter;      @Autowired     JwtTokenStore jwtTokenStore;      @Bean     public JwtTokenStore jwtTokenStore() {         tokenConverter.setVerifierKey(publicKey);         jwtTokenStore.setTokenEnhancer(tokenConverter);         return jwtTokenStore;     }      @Bean     public ResourceServerTokenServices defaultTokenServices() {         final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();         defaultTokenServices.setTokenEnhancer(tokenConverter);         defaultTokenServices.setTokenStore(jwtTokenStore());         return defaultTokenServices;     }       @Override     public void configure(HttpSecurity http) throws Exception {         super.configure(http);         // @formatter:off         http                 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)                 .and()                 .requestMatchers()                 .antMatchers("/**")                 .and()                 .authorizeRequests()                 .antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll()                 .antMatchers(HttpMethod.GET, "/api/**").access("#oauth2.hasScope('read')")                 .antMatchers(HttpMethod.PATCH, "/api/**").access("#oauth2.hasScope('write')")                 .antMatchers(HttpMethod.POST, "/api/**").access("#oauth2.hasScope('write')")                 .antMatchers(HttpMethod.PUT, "/api/**").access("#oauth2.hasScope('write')")                 .antMatchers(HttpMethod.DELETE, "/api/**").access("#oauth2.hasScope('write')")                 .antMatchers("/admin/**").access("hasRole('ROLE_USER')");          // @formatter:on     }      @Override     public void configure(ResourceServerSecurityConfigurer resources) throws Exception {         System.out.println("Configuring ResourceServerSecurityConfigurer ");         resources.resourceId("dummy").tokenServices(defaultTokenServices());     }  } 

My test case is failing miserably saying:

{"error":"invalid_token","error_description":"Cannot convert access token to JSON"}

How do I get the Authentication object out of the JWT. How do I authenticate the client, with client credentials. How do I use @Secured annotation on my resource controllers.

What code is used on the resource server side to decode the token in order to extract client credentials and what code gets to user role verified?

Please help, as I already spent 2 days banging my head on this seemingly easy task.

Note: I receive the token from Auth server as: {access_token=b5d89a13-3c8b-4bda-b0f2-a6e9d7b7a285, token_type=bearer, refresh_token=43777224-b6f2-44d7-bf36-4e1934d32cbb, expires_in=43199, scope=read write trust, authorities=[{authority=ROLE_USER}, {authority=ROLE_ADMIN}]}

Please explain the concepts and point out if anything is missing from my configuration. I need to know the best practices in configuring my resource and auth server please.

1 Answers

Answers 1

In the following I'm referring to this Baeldung tutorial that I already implemented successfully: http://www.baeldung.com/spring-security-oauth-jwt

First at all: The CustomTokenEnhancer is used on the AuthorizationServer side to enhance a created token with additional custom information. You should use the so called DefaultAccessTokenConverter on the ResourceServer side to extract these extra claims.

You can @Autowire the CustomAccessTokenConverter into your ResourceServerConfiguration class and then set it to your JwtTokenStore() configuration.

ResourceServerConfiguration:

@Autowired private CustomAccessTokenConverter yourCustomAccessTokenConverter;  @Bean public TokenStore tokenStore() {     return new JwtTokenStore(accessTokenConverter()); }  @Bean public JwtAccessTokenConverter accessTokenConverter() {     JwtAccessTokenConverter converter = new JwtAccessTokenConverter();     converter.setAccessTokenConverter(yourCustomAccessTokenConverter);     converter.setSigningKey(yourSigningKey);     return converter; } 

The CustomAccessTokenConverter can be configured, so that the custom claims get extracted here.

CustomAccessTokenConverter:

@Component public class CustomAccessTokenConverter extends DefaultAccessTokenConverter {      @Override     public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {         OAuth2Authentication authentication = super.extractAuthentication(claims);         authentication.setDetails(claims);         return authentication;     }  } 

(see: https://github.com/Baeldung/spring-security-oauth/blob/master/oauth-resource-server-1/src/main/java/org/baeldung/config/CustomAccessTokenConverter.java )

Read More

Friday, June 8, 2018

How to secure a MVC application with OAuth2 using Spring?

Leave a Comment

Sorry my english.

I have an application I can login in usual way.

@Configuration @EnableWebSecurity public class LoginSecurityConfig extends WebSecurityConfigurerAdapter {      @Override     protected void configure(AuthenticationManagerBuilder auth) throws Exception {         System.out.println("LoginSecurityConfig :: configure");          auth.jdbcAuthentication().dataSource( getDataSource() )             .passwordEncoder( new BCryptPasswordEncoder(16) )             .usersByUsernameQuery(                 "select user_name as username,password,enabled from users where user_name=?")             .authoritiesByUsernameQuery(                 "select user_name as username, role_name from users_roles ur join users u on ur.user_id = u.user_id and u.user_name = ?");      }      @Override     protected void configure(HttpSecurity http) throws Exception {           http         .csrf().disable()         .authorizeRequests()         .antMatchers("/login*").anonymous()         .antMatchers("/resources/**").permitAll()         .antMatchers("/fotos/**").permitAll()         .antMatchers("/users").access("hasRole('ROLE_ADMIN')")         .antMatchers("/user").access("hasRole('ROLE_ADMIN')")         .anyRequest().authenticated()         .and()          .formLogin()         .loginPage("/loginPage")         .defaultSuccessUrl("/home", true)         .failureUrl("/loginPage?error=true")         .loginProcessingUrl("/login")         .usernameParameter("username")         .passwordParameter("password")         .and()          .logout()         .logoutSuccessUrl("/loginPage")         .invalidateHttpSession(true);         }      } 

Using this I can try to access any secured resource and the system sends me to the loginPage where I can post username and password to the internal login controller then I have the Principal and can access the secured resources ( home, users, user ). Working fine.

But... I need to remove the user control database stuff and use OAuth2 to allow same kind of access. I don't want to have any users in my database anymore. I need a login screen and then a token request like http://myserver/oauth/token?grant_type=password&username=admin&password=admin passing client_id and client_secret in Basic. I know how to do the "get token" part and my server is working fine and give me the token and refresh token but only using Postman because I have no idea how to use it in my web application code. All tutorials I've found are using both Server and Client in same application and actually don't show how to consume an OAuth2 remote server.

Already try to use this. It is an excelent tutorial and very near to what I need but too complex to me.

I have this code and understand it can use the server and issue a token using the client credentials, but don't know how to give to the user a login screen and take his credentials to complete the request (the GET part).

@Configuration @EnableResourceServer public class OAuth2ResourceServerConfigRemoteTokenService extends ResourceServerConfigurerAdapter {      @Override     public void configure(final HttpSecurity http) throws Exception {                 http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)                     .and()                     .authorizeRequests().anyRequest().permitAll();                   }      @Primary     @Bean     public RemoteTokenServices tokenServices() {         final RemoteTokenServices tokenService = new RemoteTokenServices();         tokenService.setCheckTokenEndpointUrl("http://myoauthserver/oauth/check_token");         tokenService.setClientId("clientid");         tokenService.setClientSecret("password");         return tokenService;     }  } 

so... how can I secure my system, take login and password from the user and use this code to controll credentials like I were using usual database method?

Or OAuth2 is only for secure REST API?

enter image description here

Please be newbie friendly because I'm not very confortable using Spring.

2 Answers

Answers 1

Simple as 1,2,3 ...

Just change a little my OAuth2 server to accept oauth/authorize method.

@Override protected void configure(HttpSecurity http) throws Exception {      http         .requestMatchers()         .antMatchers("/login", "/oauth/authorize")     .and()         .authorizeRequests()         .anyRequest()         .authenticated()     .and()         .formLogin()         .permitAll();        } 

and create a custom login form. Now all clients (web applications) can login into it.

Here you can find a sample client and a more details: http://www.baeldung.com/sso-spring-security-oauth2

Answers 2

I’ve been working on this myself recently, and I wish I could say I have a simple answer, but I don’t. I would have to start by asking questions like, is this a web application (JSP etc) or a REST API used by a web application, or a REST API used by a mobile app, etc etc. The reason this is important is that you first have to select one of the OAuth2 profiles and grant types, and they all have different requirements and configuration in Spring. Also, are you trying to integrate with a third party OAuth2 authentication provider (e.g. Facebook) or is your application acting as both the authentication provider (where login and password validation occurs) and the protected resource (where the web page requests or API calls go to)? So I guess the best I can do is assign you some homework: (1) Read about the various OAuth2 profiles and determine which one best fits your application, and learn all the terminology (like, what is a client secret?). This is definitely NOT one of those cases where you can just cut and paste example code without understanding it. If you don’t have a reasonable understanding of how OAuth2 works you are going to have a lot of difficulty. Also: we’re talking about SECURITY here so doing stuff without understand it is a very bad idea. If you aren’t careful, you may think it’s working but in fact you’re leaving yourself wide open to attacks. (2) if you are not familiar with Spring Framework Security you’ll need a basic grounding in that to understand what you’re doing, (3) Once you have an idea which profile you’ll use, use that in a google search, e.g. “Spring oauth2 implicit grant” to find an example tailored for that profile. There are a few out there and that’s a good place to start though I found I was not able to take any of the examples directly over to my application because of subtle differences in their assumptions and my application. The Spring reference guide is helpful also but doesn’t necessarily give all the details for all the issues you may encounter. Finally, try to implement with your application. You’ll want some good tools to send requests to your app (I like PostMan for that purpose) so you can inspect the data going back and forth. OAuth2 involves a complex series of HTTP redirects so testing can be a bit difficult. Also, be patient. I consider myself a Spring expert and it still took me a few days to get things fully working the way I wanted. Note that there is actually VERY LITTLE code you end up writing, but getting the small amount of code exactly right is what’s difficult.

Read More

Monday, December 4, 2017

Spring oauth: Why resource server is authorising instead of authorisation server

Leave a Comment

What i found while using spring oauth framework is resource server making check_token?token=T_O_K_E_N request to authorisation server, and authorisation server is just returning CheckTokenEndPoint map with authorities something like below.

{     "exp": 1511471427,     "user_name": "idvelu",     "authorities": [         "FUNCTION_GET_USERS",         "FUNCTION_AUTHORITY_1",         "FUNCTION_AUTHORITY_2",         "FUNCTION_AUTHORITY_3",         "FUNCTION_AUTHORITY_4",         "FUNCTION_AUTHORITY_5",         "FUNCTION_AUTHORITY_6",         "FUNCTION_AUTHORITY_7",     ],     "client_id": "c1",     "scope": [         "read",         "write"     ] } 

Just visualise this with oauth service and resource service is running in two different machines/jvm.

I think now resource server has to authorise the request against configured valid authorities in ResourceServerConfiguration::configure(HttpSecurity) with the authorities from the authorisation server.

@Override public void configure(HttpSecurity http) throws Exception {  http.anonymous().disable().requestMatchers().antMatchers("/**").and().authorizeRequests()          .antMatchers(HttpMethod.GET, "/myproject/users").hasAnyAuthority("FUNCTION_GET_USERS")         .antMatchers(HttpMethod.POST, "/myproject/users").hasAnyAuthority("FUNCTION_POST_NEW_USER")         .anyRequest().denyAll()         .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler()); } 

In this case authorisation server may return all the hundreds of user authorities to resource server. Instead why not authorisation server itself can take the few of the permission required for authorisation as query params
check_token?token=T_O_K_E_N&authorities=FUNCTION_GET_USERS,FUNCTION_AUTHORITY_2,..
from the resource server and validate it against the user's functions through DB?

And finally my problem is; i have different services like java, node.js, NGINX... All these have to verify its authentication and authorization against one spring Authorisation server. Because of the above stated problem all my service has to implement the authorisation (resource server) part. Means comparing all the authorities of user against the API acess authorities.
Java side this comparison is fine with spring resource server implementation. But all other non-java (resource) services needs authorisation/resourceServer implementation. Instead if my spring authorisation server accepts the authorities and validates then my problem is solved as single point of authorisation/comparison implementations. I just need to pass it as part of check_token.

How to implement this new check_token endpoint along with accepting the authorities?

1 Answers

Answers 1

The authorization server is responsible for authenticating the user/client (depending on the oauth type you use). When this is done, a token is given.

When a user/client presents themselves to the resource server, wanting to consume a service, they must provide the token. Now the resource server has a token and needs to validate that this token was generated by the authorization server. There are two options:

  1. The token itself does not contain any information. The resource server calls the authorization server and asks if the token is valid. The authorization server will respond that the token is valid and gives some additional information (user/client, roles/scopes, etc).
  2. The token does contain the necessary information (JWT tokes for example). This enables the resource server to extract the needed info without contacting the authorization server. In this case, the authorization server has signed the token and the resource server can validate the signature to be sure that it was the autorization server that has issued the token.

At the moment, you are using the first scenario. Every resource server you write, must verify tokens and extract additional info. How the verification is done depends on the authorization server.

Part2:

Your question is not clear to me. I presume you are using the OAuth2 authorization code scheme with non JWT tokens?

In that case, you have an authorization server that is only responsible for authentication, a resource server that is exposing some services and a client that consumes the resource server.

If i'm not mistaking, you have different resource servers (api's)?

You did not share your authorization server configurations, but normaly you use @EnableAuthorizationServer. This will create an endpoint /oauth/check_token. By default this endpoint is not accassible. You need to do something like this:

@Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {    oauthServer.checkTokenAccess("permitAll()"); // authenticated is better } 

You can use this endpoint to validate tokens.

All this is described in the oauth2 developer guide.

Part3:

On the authorization server, you can create an endpoint like this :

@RequestMapping("/user") public Principal user(Principal principal) {      if(principal instanceof OAuth2Authentication) {         return (OAuth2Authentication) principal;     } else {         return principal;     } } 

You can modify it to your needs.

Read More

Wednesday, August 2, 2017

Enabling Oauth2sso on Google App Engine

Leave a Comment

I am trying to get spring security oauth2 setup on my application in Google app engine. Everything seems to work fine locally but when i deploy to app engine things start to break down. After I authenticate through google its forwarding me to a Whitelabel error page. In the console I see this error:

http://my-application.appspot.com/login?state=t…m&session_state=8b67f5df659a8324430803973b9e1726e39fd454..1ae3&prompt=none  401 (Unauthorized) 

I setup my auth with this application.yml file:

security:   oauth2: client:   clientId: client-key   clientSecret: secret-key   accessTokenUri: https://www.googleapis.com/oauth2/v4/token   userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth   clientAuthenticationScheme: form   scope:     - openid     - email     - profile     - https://www.googleapis.com/auth/cloud-platform resource:   userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo   preferTokenInfo: true 

My security config looks somethign like this:

@Override protected void configure(HttpSecurity http) throws Exception {     http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())         .and()             .authorizeRequests()             .antMatchers("/static/**").permitAll()             .antMatchers("/**").hasAuthority("ROLE_ADMIN")             .anyRequest().authenticated()         .and()             .exceptionHandling()             .accessDeniedPage("/403"); } 

I have configured the Oauth ID on the google credential pages to allow authorized javascript origins to be:

http://my-application.appspot.com https://my-application.appspot.com http://localhost:8080 

And the authorized redirect URIs to:

http://my-application.appspot.com/login https://my-application.appspot.com/login http://localhost:8080/login 

Any ideas why i might be getting unauthorized errors once I deploy to GAE?

Thanks,

Craig

1 Answers

Answers 1

Your problem is about Authorization, maybe missed step on fully authorizing application, such as moving your client_secret.json to your working directory.

https://developers.google.com/drive/v3/web/quickstart/java#step_1_turn_on_the_api_name

Step 1: Turn on the Drive API

  1. Use this wizard to create or select a project in the Google Developers Console and automatically turn on the API. Click Continue, then Go to credentials. On the Add credentials to your project page, click the Cancel button.

    1. At the top of the page, select the OAuth consent screen tab. Select an Email address, enter a Product name if not already set, and click the Save button. Select the Credentials tab, click the Create credentials button and select OAuth client ID.

    2. Select the application type Other, enter the name "Drive API Quickstart", and click the Create button.

    3. Click OK to dismiss the resulting dialog.

    4. Click the file_download (Download JSON) button to the right of the client ID.

    5. Move this file to your working directory and rename it client_secret.json.

helpful link : GCM http 401 authorization error

Read More

Saturday, July 15, 2017

Spring Security OAuth - Provider Manager is Not Configured for Null Resource

Leave a Comment

Am trying to use Spring Secruity's OAuth API to obtain an access token from an externally published API.

This curl command works (and its contents are all that I need to obtain an access token):

curl -X POST \ https://api.app.com/v1/oauth/token \   -H 'content-type: application/x-www-form-urlencoded' \   -d'grant_type=client_credentials&client_id=bcfrtew123&client_secret=Y67493012' 

Am able to obtain an access token from the external service after running this curl command.

When using Spring Security OAuth API:

<dependency>    <groupId>org.springframework.security.oauth</groupId>      <artifactId>spring-security-oauth2</artifactId>      <version>2.1.1.RELEASE</version> </dependency> 

Setup my SpringMVC Controller's method like this:

@RequestMapping(value = "/getAccessToken", method = RequestMethod.POST, consumes="application/x-www-form-urlencoded") public OAuth2AccessToken getAccessToken(@RequestParam(value="client_id", required=true) String clientId, @RequestParam(value="client_secret", required=true) String clientSecret) throws Exception {     String tokenUri = "https://api.app.com/v1/oauth/token";      ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails();      resourceDetails.setAccessTokenUri(tokenUri);     resourceDetails.setClientId(clientId);     resourceDetails.setClientSecret(clientSecret);     resourceDetails.setGrantType("client_credentials");     resourceDetails.setScope(Arrays.asList("read", "write"));      DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();      oauth2RestTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);      OAuth2AccessToken token = oauth2RestTemplate.getAccessToken();     return token; } 

When I invoke the getAccessToken call from my local tomcat instance:

access_denied  error_description=Unable to obtain a new access token for resource 'null'.  The provider manager is not configured to support it. 

Question(s):

  1. What am I missing here? Is there some annotation required for this? Is there a property that is not set or is needed?

(Please notice that the content-type needs to be "application/x-www-form-urlencoded"...)

  1. How can I mimic the working curl command using Spring Security OAuth API?

  2. Could it be the default values that I have set in the RequestParameters?

  3. If successful, how can I set it up so that access token is always preloaded before any request made?

2 Answers

Answers 1

This could be oocured beacuse server doest not recognize the content type you posting to that specific url. In your CURL request try include the 'content-type: application/x-www-form-urlencoded' for custom conrtroller using http headers. Http headers

Also you have not set username and password for resourceDetails. resourceDetails.setUserName("user"); resourceDetails.setUserName("password");

if those does not work try to extract the request that Encoded with application/x-www-form-urlencoded and pass it as a string via RestTemplate and you can get the token.

Let me know any if you need additional support.

Try the code below that is giving token as and string response.

enter image description here

Answers 2

This is what i use:

@Bean public RestTemplate oAuthRestTemplate() {     ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();     resourceDetails.setId("1");     resourceDetails.setClientId(oAuth2ClientId);     resourceDetails.setClientSecret(oAuth2ClientSecret);     resourceDetails.setAccessTokenUri(accessTokenUri);      OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, oauth2ClientContext);      return restTemplate; } 

The correct headers will be set bij the framework, but the username/password will be base64 encodes as Authorization header (basic authentication). This is the OAuth2 spec for a client_credentials grant.

Check if the api supports the spec:

curl -X POST \ 'https://api.app.com/v1/oauth/token' \ -i -u 'client:secret' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=client_credentials' 

If you need to send the username & password as data instead of authorisation header, you can add resourceDetails.setAuthenticationScheme(AuthenticationScheme.form); this should set de username & password as data

Read More

Tuesday, May 9, 2017

hasRole always return 403

Leave a Comment

I can't seem to get my security configuration right. No matter what I do when using hasRole my endpoints always return 403.

Also I can't get anything to work unless I duplicate my antMatchers under both .requestMatchers() and .authorizeRequests(). I'm clearly missing something here.

Basically I want everything to require authentication but a few endpoints only to be accessable if the user is member of certain groups (for now just admin).

My security configuration is as follows. Everything beside hasRole works.

@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableWebSecurity @Configuration public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {     @Override     protected void configure(HttpSecurity http) throws Exception {         http             .csrf().disable()             .requestMatchers()                 .antMatchers(HttpMethod.GET, "/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html")                 .antMatchers(HttpMethod.GET, "/users")                 .and()             .authorizeRequests()                 .antMatchers(HttpMethod.GET, "/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html").permitAll()                 .antMatchers(HttpMethod.GET, "/users").hasRole("ADMIN")                     .anyRequest().authenticated();     }      // Inspiration: https://spring.io/blog/2015/06/08/cors-support-in-spring-framework#comment-2416096114     @Override     public void configure(WebSecurity web) throws Exception {         web             .ignoring()                 .antMatchers(HttpMethod.OPTIONS, "/**");     } } 

My AuthenticationConfiguration is as follows

@Configuration @EnableResourceServer public class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {     private final UserDetailsService userService;     private final PasswordEncoder passwordEncoder;      public AuthenticationConfiguration(UserDetailsService userService, PasswordEncoder passwordEncoder) {         this.userService = userService;         this.passwordEncoder = passwordEncoder;     }      @Override     public void init(AuthenticationManagerBuilder auth) throws Exception {         auth                 .userDetailsService(userService)                 .passwordEncoder(passwordEncoder);     } } 

My AuthorizationServerConfiguration is as follows

@Configuration @EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {     private final AuthenticationManager authenticationManager;      public AuthorizationServerConfiguration(AuthenticationManager authenticationManager) {         this.authenticationManager = authenticationManager;     }      @Override     public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {         endpoints.authenticationManager(authenticationManager);     }      @Override     public void configure(ClientDetailsServiceConfigurer clients) throws Exception {         clients                 .inMemory()                 .withClient("html5")                 .secret("password")                 .authorizedGrantTypes("password")                 .scopes("openid");     } } 

I'll happily post my user service and other stuff. But everything seems to work beside hasRole and Principal is loaded with the right authorities (roles). But please let me know if I should post any more code.

The entire source code can be found here.

1 Answers

Answers 1

Have you tried with "ROLE_ADMIN" rather than just "ADMIN"? Take a look at this for reference:

Spring security added prefix "ROLE_" to all roles name?

Read More

Thursday, March 17, 2016

Protecting REST API with OAuth2: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active

Leave a Comment

I've been working for a few days to attempt to implement oauth2 protection on a REST API. I've tried a ton of different configurations but still haven't managed to get it to work.

I'm proving the code that I have right now, but I'm in no way married to this implementation. If you can show me some radically different way to accomplish what I want to accomplish, great.

My flow looks like this:

  1. Client checks Auth Server, gets token.
  2. Client sends token to Resource Server.
  3. Resource Server uses Auth Server to make sure that token is valid.

The Auth Server works fine. I'm having trouble configuring the Resource Server.

Configs on Resource Server

Here's some of my configs. I have this bean:

Ouath Rest Template

@EnableOAuth2Client @Configuration @Import({PropertiesConfig.class}) //Imports properties from properties files. public class OauthRestTemplateConfig {     @Bean     public OAuth2RestTemplate oAuth2RestTemplate(OAuth2ClientContext oauth2ClientContext) {         OAuth2RestTemplate template = new OAuth2RestTemplate(oauth2ResourceDetails(), oauth2ClientContext);         return template;     }      @Bean     OAuth2ProtectedResourceDetails oauth2ResourceDetails() {         AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();         details.setId("theOauth");         details.setClientId("clientID");         details.setClientSecret("SecretKey");         details.setAccessTokenUri("https://theAuthenticationServer.com/oauthserver/oauth2/token");         details.setUserAuthorizationUri("https://theAuthenticationServer.com/oauthserver/oauth2/token");         details.setTokenName("oauth_token");         details.setPreEstablishedRedirectUri("http://localhost/login");         details.setUseCurrentUri(true);         return details;     } } 

Security Config

I use that bean in my main security config in Resource Server:

@Slf4j @Configuration @EnableWebSecurity @EnableOAuth2Client @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true, proxyTargetClass = true) @Import({PropertiesConfig.class, OauthRestTemplateConfig.class}) public class SecurityConfig extends WebSecurityConfigurerAdapter {      @Autowired     @Qualifier("oAuth2RestTemplate")     private OAuth2RestTemplate oAuth2RestTemplate;      @Override     protected void configure(HttpSecurity http) throws Exception {          http                 .authorizeRequests()                 .accessDecisionManager(accessDecisionManager()) //This is a WebExpressionVoter. I don't think it's related to the problem so didn't include the source.                     .antMatchers("/login").permitAll()                       .antMatchers("/api/**").authenticated()                 .anyRequest().authenticated();         http                 .exceptionHandling()                 .authenticationEntryPoint(delegatingAuthenticationEntryPoint());         http                 .addFilterBefore(new OAuth2ClientContextFilter(), BasicAuthenticationFilter.class)                 .addFilterAfter(oauth2ClientAuthenticationProcessingFilter(), OAuth2ClientContextFilter.class)         ;     }      private OAuth2ClientAuthenticationProcessingFilter oauth2ClientAuthenticationProcessingFilter() {         OAuth2ClientAuthenticationProcessingFilter                 daFilter = new OAuth2ClientAuthenticationProcessingFilter("/api/**");         daFilter.setRestTemplate(oAuth2RestTemplate);         daFilter.setTokenServices(inMemoryTokenServices());         return daFilter;     }       private DefaultTokenServices inMemoryTokenServices() {         InMemoryTokenStore tok = new InMemoryTokenStore();         DefaultTokenServices tokenService = new DefaultTokenServices();         tokenService.setTokenStore(tok);          return tokenService;     } } 

Extra stuff in Security Config

Aaand, some of the beans which I believe are less relevant, but here they are in case you need them:

@Bean public DelegatingAuthenticationEntryPoint delegatingAuthenticationEntryPoint() {     LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> matchers =             Maps.newLinkedHashMap();      //Match all HTTP methods     matchers.put(new RegexRequestMatcher("\\/api\\/v\\d+\\/.*", null), oAuth2AuthenticationEntryPoint());     matchers.put(AnyRequestMatcher.INSTANCE, casAuthenticationEntryPoint());      DelegatingAuthenticationEntryPoint entryPoint = new DelegatingAuthenticationEntryPoint(matchers);     entryPoint.setDefaultEntryPoint(casAuthenticationEntryPoint());      return entryPoint; } @Bean(name = "casEntryPoint") public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {     CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();     casAuthenticationEntryPoint.setLoginUrl(casUrl + "/login");     casAuthenticationEntryPoint.setServiceProperties(serviceProperties());      return casAuthenticationEntryPoint; } 

Error

Resource Server starts up just fine. Client gets its auth token from theAuthenticationServer.com and sends it in the request header to an api url. And I get the following error:

HTTP Status 500 - Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

Exception report

Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

The server encountered an internal error that prevented it from fulfilling this request.

        org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.     org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355)     org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)     org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)     org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)     com.sun.proxy.$Proxy26.getAccessToken(Unknown Source)     org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)     org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:94)     org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)     org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)     org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)     org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)     org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)     org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)     org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)     org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)  root cause         <pre>java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.     org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)     org.springframework.web.context.request.SessionScope.get(SessionScope.java:91)     org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340)     org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)     org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)     org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)     com.sun.proxy.$Proxy26.getAccessToken(Unknown Source)     org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)     org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:94)     org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)     org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)     org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)     org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)     org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)     org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)     org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)     org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)     org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)     org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) 

I've tried a lot of different configs, looked up a ton of resources online, and I've gotten nowhere. Am I using the right classes? Any idea what configs I might need to change?

3 Answers

Answers 1

I ended up resolving this thing after looking into Spring documentation.

It turned out that the scope context didn't actually exist in my app, because I hadn't initialized it.

I initialized it by adding this listener:

<listener>  <listener-class>         org.springframework.web.context.request.RequestContextListener  </listener-class> </listener> 

Answers 2

I'm proving the code that I have right now, but I'm in no way married to this implementation. If you can show me some radically different way to accomplish what I want to accomplish, great

If your main problem is implementing the Resource Server and also, you are open to totally different solutions, you can use Spring Boot's resource server auto configurations. This way you would have a ResourceServerConfiguration such as following:

@Configuration @EnableResourceServer public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {     @Override     public void configure(HttpSecurity http) throws Exception {         http                 .authorizeRequests()                     .anyRequest().authenticated();         // you can put your application specific configurations here         // here i'm just authenticating every request     } } 

With an application.yml config file in your src/main/resources:

security:   oauth2:     client:       client-id: client       client-secret: secret     resource:       token-info-uri: http://localhost:8888/oauth/check_token 

You should add your client-id, client-secret and token-info-uri there. token-info-uri is the endpoint on Authorization Server that our resource server is going to consult about the validity of passed Access Tokens.

With these arrangements, if the client fire a request to, say, /api/greet API:

GET /api/greet HTTP/1.1 Host: localhost:8080 Authorization: bearer cef63a29-f9aa-4dcf-9155-41fb035a6cdb 

Our resource server will extract the Bearer access token from the request and send the following request to the authorization server to validate the access token:

GET /oauth/check_token?token=cef63a29-f9aa-4dcf-9155-41fb035a6cdb HTTP/1.1 Host: localhost:8888 Authorization: basic base64(client-id:client-secret) 

If token was valid, authorization server send a 200 OK response with a JSON body like following:

{"exp":1457684735,"user_name":"me","authorities":["ROLE_USER"],"client_id":"client","scope":["auth"]} 

Otherwise, it will return a 4xx Client Error.

This was a maven project with a pom.xml like following:

<parent>     <groupId>org.springframework.boot</groupId>     <artifactId>spring-boot-starter-parent</artifactId>     <version>1.3.3.RELEASE</version> </parent>  <dependencies>     <dependency>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-web</artifactId>     </dependency>     <dependency>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-security</artifactId>     </dependency>     <dependency>         <groupId>org.springframework.security.oauth</groupId>         <artifactId>spring-security-oauth2</artifactId>     </dependency> </dependencies> 

And a typical Application class:

@SpringBootApplication public class Application {     public static void main(String[] args) {         SpringApplication.run(Application.class, args);     } } 

You can check out the spring boot documentation on resource server auto configurations here.

Answers 3

I believe that the root of issue is that you create the OAuth2ClientAuthenticationProcessingFilter and OAuth2ClientContextFilter with new operator.

If you look at the stacktrace

org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131) org.springframework.web.context.request.SessionScope.get(SessionScope.java:91) org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340) org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35) org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187) com.sun.proxy.$Proxy26.getAccessToken(Unknown Source) org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169) org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:94) 

there's a chain how it goes from OAuth2ClientAuthenticationProcessingFilter to JdkDynamicAopProxy and tries to get the bean. And I can assume because of that bean was created out of Spring container, it can't get the bean from the session scope.

Try to wrap your filters into @Bean annotation so to put them into context. Also, i believe it worth being set the correct scope: the request would match best here.

Read More