I am trying to implement Oauth2 in my existing application.Initially I have added spring security and then tried to add oauth2, After adding configuration I am able to gener
You should use hasRole
directly on your antmatcher instead of a string inside the access()
function. This will evaluate the hasRole
correctly and correctly determine that the user has access to the requested resource.
This will result in the following code for ResourceServer.java
:
@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.anonymous().disable()
.requestMatchers().antMatchers("/patients/**").and().authorizeRequests()
.antMatchers("/patient/**").hasRole('USER')
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
I suspect the problem might be the way you save/load roles. In spring security there is a default prefix for roles: ROLE_
. So in your DB (storage) you need to save them as ROLE_FOO
for example and then you can use hasRole('FOO')
I found the same problem here, and my answer seemed to solve the problem: https://stackoverflow.com/a/43568599/4473822
The person that got the issue also had 403 - Forbidden
and saving the roles correctly in the DB solved the problem.
You can also change the default prefix but I would not recommend it unless you want to mess with spring a bit.
Please change the code like below in ResourceServer
:
Have a look at this line:
http.anonymous().disable()
.requestMatchers().antMatchers("/patients/**","/patient/**")
Since "/patient/"**, is not added as part of request matcher, the request is actually was handled by other configuration
package project.configuration;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.anonymous().disable()
.requestMatchers().antMatchers("/patients/**","/patient/**").and().
authorizeRequests().antMatchers("*/patient/**").hasRole("USER")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
In the example, I have the same problem, after so much search and try, I solved it by adding the below one.
After added
@Order(10)
onOAuth2AuthorizationServer
,@Order(20)
onOAuth2ResourceServer
,@Order(30)
onSecurityConfig
,
I finally could get resources via an access token. in @Order, Lower values have higher priority, so the reason why we can’t get resources via access token must be that SecurityConfig has higher priority than OAuth2ResourceServer.
So try to add @Order(30) on SecurityConfiguration, @Order(10) on SecurityOAuth2Configuration, and @Order(20) on ResourceServer.
First off, you have two similar methods that modify the AuthenticationManagerBuilder
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
and
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
Is there a reason they both are there? I do not have this in my config set up.
Furthermore, your query might not be working properly. You should follow some guidelines into how to set up a user service to handle the loaduserbyusername call and the auth
object with one. As a note: I do not have the same AuthenticationManagerBuilder
set up as you, I have mine configured to use a userdetails service, along with a password Encoder like so.
auth.userDetailsService(securityUserService)
.passwordEncoder(passwordEncoders.userPasswordEncoder());
If that doesn't help, here's an alternative way of configuring:
Change the class that extends WebSecurityConfigurerAdapter
to only concern itself with the token endpoint.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/oauth/**").permitAll()
.and()
.csrf()
.disable();
}
Now in your ResourceServerConfigurerAdapter
, have the configuration worry about the stuff in the resource server. Please note, this will work only if your AuthenticationManagerBuilder
configuration is properly loading the Role correctly. As other's have noted, Spring has the prefix ROLE_
. Which for some reason you are retrieving using a query, and they're authorities.
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requestMatchers()
.antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers("/api/**").access("hasRole('USER')")
.and()
.exceptionHandling()
.accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
In my AuthServerConfig
file I Do not have the following annotations:
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(SecurityConfiguration.class)
I configure the AuthorizationServerSecurityConfigurer
differently than the tutorial you followed, mine is the following:
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
My ClientDetailsServiceConfigurer
is still in memory so that's different as well. My AuthorizationServerEndpointsConfigurer
is slightly different too, I only add a tokenstore, an enhancer chain (Don't worry about this, it's extra), and an authenticationManager
endpoints
.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain)
.authenticationManager(authenticationManager);