Now that WebSecurityConfigurerAdapter has been deprecated I am trying to update my code to use the new ways to set up authentication based off : https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter
I currently use ldap authentication as well as in memory authentication. In my app I need to expose the AuthenticationManagers as beans for each. My old code this was done aby creating two separate WebSecurityConfigurerAdapter:
#Configuration
#Order(1)
public class APIWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser(ApiRolesUsers.API_VIEW_ALL).password("{noop}" + apiKeyStore.getKeyByUserName(ApiRolesUsers.API_VIEW_ALL)).roles(ApiRolesUsers.API_VIEW_ALL)
.and()
.withUser(ApiRolesUsers.API_UPDATE_ALL).password("{noop}" + apiKeyStore.getKeyByUserName(ApiRolesUsers.API_UPDATE_ALL)).roles(ApiRolesUsers.API_UPDATE_ALL)
.and()
.withUser(ApiRolesUsers.API_EDL_UPDATE).password("{noop}" + apiKeyStore.getKeyByUserName(ApiRolesUsers.API_EDL_UPDATE)).roles(ApiRolesUsers.API_EDL_UPDATE);
}
...
#Bean( name = "apiAuthenticationManager")
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
...
}
and
#Configuration
#Order(2)
public class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Autowired
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userSearchBase(ldapUserSearchBase)
.userSearchFilter(ldapUserSearchFilter)
.groupSearchBase(ldapGroupSearchBase)
.contextSource(ldapContextSource);
...
#Bean( name = "authenticationManager")
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
...
}
From there I could then autowire both "authenticationManager" and "apiAuthenticationManager". I am able to recreate the "authenticationManager" part without WebSecurityConfigurerAdapter in the new format with:
#Bean(name = "authenticationManager")
AuthenticationManager ldapAuthenticationManager(
LdapContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory =
new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserSearchBase(ldapUserSearchBase);
factory.setUserSearchFilter(ldapUserSearchFilter);
return factory.createAuthenticationManager();
}
Based off new spring documentation I am able to create the in memory part with:
//How do I expose AuthenticationManager for this???
public InMemoryUserDetailsManager inMemoryUserDetailsManager(AuthenticationConfiguration providerManager) {
UserDetails apiViewAll = User.builder()
.username(ApiRolesUsers.API_VIEW_ALL)
.password("{noop}" + apiKeyStore.getKeyByUserName(ApiRolesUsers.API_VIEW_ALL))
.roles(ApiRolesUsers.API_VIEW_ALL)
.build();
UserDetails updateAll = User.builder()
.username(ApiRolesUsers.API_UPDATE_ALL)
.password("{noop}" + apiKeyStore.getKeyByUserName(ApiRolesUsers.API_UPDATE_ALL))
.roles(ApiRolesUsers.API_UPDATE_ALL)
.build();
UserDetails edlUpdate = User.builder()
.username(ApiRolesUsers.API_EDL_UPDATE)
.password("{noop}" + apiKeyStore.getKeyByUserName(ApiRolesUsers.API_EDL_UPDATE))
.roles(ApiRolesUsers.API_EDL_UPDATE)
.build();
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(apiViewAll, updateAll, edlUpdate);
return manager;
}
In the above I need to expose the related AuthenticationManager that WebSecurityConfigurerAdapter was able to do before they deprecated it.
Doing something like this only returns the ldap authentication...
#Bean(name = "apiAuthenticationManager") {
public AuthenticationManager authenticationManager(AuthenticationConfiguration
authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
Does anyone know how I can implement and expose both AuthenticationManagers without the use of WebSecurityConfigurerAdapter
You can construct the AuthenticationManager yourself, for example:
#Bean
AuthenticationManager apiAuthenticationManager(InMemoryUserDetailsManager users) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(users);
return new ProviderManager(provider);
}
Related
I'm trying to setup a simple Oauth2 Server with Spring Boot with only client_credentials flow for now, using in memory users and clients etc. Basically the most basic project so I can build on it. Haven't used Oauth2 with Spring for some time so I'm a bit stuck. I can get access tokens but it seems Spring does not actually validate the username/password sent by the client. Here are the two config classes (AuthorizationServerConfigurerAdapter, WebSecurityConfigurerAdapter):
#Configuration
#EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final PasswordEncoder passwordEncoder;
private final UserDetailsService userService;
#Value("${jwt.signing-key}")
private String jwtSigningKey;
#Value("${jwt.accessTokenValidititySeconds}")
private int accessTokenValiditySeconds;
#Value("${jwt.refreshTokenValiditySeconds}")
private int refreshTokenValiditySeconds;
public OAuthConfiguration(AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder, UserDetailsService userService) {
this.authenticationManager = authenticationManager;
this.passwordEncoder = passwordEncoder;
this.userService = userService;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("test-client-id")
.secret(passwordEncoder.encode("test-client-secret"))
.accessTokenValiditySeconds(accessTokenValiditySeconds)
.refreshTokenValiditySeconds(refreshTokenValiditySeconds)
.authorizedGrantTypes("client_credentials")
.scopes("read", "write")
.resourceIds("api");
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.accessTokenConverter(accessTokenConverter())
.userDetailsService(userService)
.authenticationManager(authenticationManager);
}
#Bean
JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(jwtSigningKey);
return converter;
}
}
and:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
public WebSecurityConfiguration(CustomAuthenticationEntryPoint customAuthenticationEntryPoint) {
this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
}
#Bean
public DaoAuthenticationProvider authenticationProvider(UserDetailsService userDetailsService) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1")
.password("$2a$10$sWszOXuTlN0amQi8vXp4cerb.tJUQo.4FzLAnTCsSqChsYhlLdQWW")
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().disable().csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint).accessDeniedHandler(new CustomAccessDeniedHandler());
}
}
So I can call the "/oauth/token" endpoint with any username/password I get an access token. However the client ID and client secret are being validated.
Any help is appreciated
It's the default behaviour with grant_type client_credentials. So, you don't need to pass the username and password to the token endpoint with this grant_type. In this flow, AuthorizationServer will only validate the client Id and client secret.
POST /token
Host: authorization-server.com
grant_type=client_credentials
&client_id=xxxxxxxxxx
&client_secret=xxxxxxxxxx
I currently have a microservices architecture secured by an authentication server and a resource server using Oauth2 protocol with my users stored in a database. To authenticate I use spring-security-oauth2 configured to return JWT tokens and these tokens travel in the request headers between my microservices.
Now I have a new requirement that I would like to be able to authenticate with Google using OpenID connect as well.
I have been researching how to do it but I haven't found a solution using spring-security-oauth2 because I want to keep my security core and avoid change it for this new requirement, this means I want to use my JWT certificate to validate the tokens that are flying between my microservices.
I suppose that I have to register the user with Google OpenId flow and use it to login with my current flow, but I don't know how to integrate with the web frontend, and how to register them.
I'm working with Spring Boot 1.5.4 and Spring Cloud 1.2.1
This is my current configuration:
MyAuthorizationServer.java
#Configuration
#EnableAuthorizationServer
public class MyAuthorizationServer extends AuthorizationServerConfigurerAdapter {
#Value("${keyStore.location}")
private Resource resource;
#Value("${keyStore.password}")
private String password;
#Value("${keyStore.alias}")
private String alias;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private DataSource dataSource;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyStoreKeyFactory keyStoreKeyFactory =
new KeyStoreKeyFactory(resource, password.toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair(alias));
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(
Arrays.asList(tokenEnhancer(), accessTokenConverter()));
endpoints.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain)
.authenticationManager(authenticationManager);
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
}
MyResourceServer.java
#Configuration
#EnableResourceServer
public class MyResourceServer extends ResourceServerConfigurerAdapter {
#Autowired
private DefaultTokenServices tokenServices;
#Override
public void configure(final HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests()
.antMatchers("/admin/** ").permitAll()
.anyRequest().authenticated();
}
#Override
public void configure(ResourceServerSecurityConfigurer config) {
config.tokenServices(tokenServices);
}
}
MyWebServerSecurity.java
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class MyWebServerSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/oauth/authorize").permitAll()
.anyRequest().authenticated().and().csrf().disable();
}
}
Thanks for your help.
Regards
As I see Spring Security OAuth2.x project was moved to Spring Security 5.2.x. I try to implement authorization and resource server in new way. Everythin is working correctly except one thing - #PreAuthorize annotation. When I try to use this with standard #PreAuthorize("hasRole('ROLE_USER')") I always get forbidden. What I see is that the Principal object which is type of org.springframework.security.oauth2.jwt.Jwt is not able to resolve authorities and I have no idea why.
org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken#44915f5f: Principal: org.springframework.security.oauth2.jwt.Jwt#2cfdbd3; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#ffffa64e: RemoteIpAddress: 172.19.0.1; SessionId: null; Granted Authorities: SCOPE_read, SCOPE_write
And claims after casting it to Jwt
{user_name=user, scope=["read","write"], exp=2019-12-18T13:19:29Z, iat=2019-12-18T13:19:28Z, authorities=["ROLE_USER","READ_ONLY"], client_id=sampleClientId}
Security Server Configuration
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private AuthenticationManager authenticationManager;
#Bean
public KeyPair keyPair() {
ClassPathResource ksFile = new ClassPathResource("mytest.jks");
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(ksFile, "mypass".toCharArray());
return keyStoreKeyFactory.getKeyPair("mytest");
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyPair());
return converter;
}
#Bean
public JWKSet jwkSet() {
RSAKey key = new Builder((RSAPublicKey) keyPair().getPublic()).build();
return new JWKSet(key);
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter())
.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
public SecurityConfiguration(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers("/.well-known/jwks.json")
.permitAll()
.anyRequest()
.authenticated();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}
Resource server configuration
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResuorceServerConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
}
Maybe someone had similar issue?
By default, the resource server populates the authorities based on the "scope" claim.
If the Jwt contains a claim with the name "scope" or "scp", then Spring Security will use the value in that claim to construct the authorities by prefixing each value with "SCOPE_".
In your example, one of the claims is scope=["read","write"].
This means that the authority list will consist of "SCOPE_read" and "SCOPE_write".
You can modify the default authority mapping behaviour by providing a custom authentication converter in your security configuration.
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(getJwtAuthenticationConverter());
Then in your implementation of getJwtAuthenticationConverter, you can configure how the Jwt maps to the list of authorities.
Converter<Jwt, AbstractAuthenticationToken> getJwtAuthenticationConverter() {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
// custom logic
});
return converter;
}
Add this to your SecurityConfig
.jwt()
.jwtAuthenticationConverter(jwtAuthenticationConverter());
And the converter
private JwtAuthenticationConverter jwtAuthenticationConverter() {
// create a custom JWT converter to map the "roles" from the token as granted authorities
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
jwtGrantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}
I use spring boot and spring security and I need to encode requests. So I use encoding filter in spring security and add it before others filters. And it doesn't work. I have the following result:
#Configuration
#EnableWebSecurity
public class SecurityJavaConfig extends WebSecurityConfigurerAdapter {
#Autowired
private MyUserDetailsService myUserDetailsService;
#Autowired
private UserDao userDao;
#Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Autowired
private AuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
#Bean(name = "myAuthenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder customPasswordEncoder() {
return new PasswordEncoder() {
#Override
public String encode(CharSequence rawPassword) {
return DigestUtils.md5Hex(rawPassword.toString());
}
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return DigestUtils.md5Hex(rawPassword.toString()).equals(encodedPassword);
}
};
}
#Bean
public CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter()
throws Exception {
CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter = new CustomUsernamePasswordAuthenticationFilter(userDao);
customUsernamePasswordAuthenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
customUsernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
customUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);
customUsernamePasswordAuthenticationFilter
.setAuthenticationManager(authenticationManagerBean());
return customUsernamePasswordAuthenticationFilter;
}
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(myUserDetailsService).passwordEncoder(customPasswordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
http.addFilterBefore(filter,CsrfFilter.class);
//Implementing Token based authentication in this filter
final TokenAuthenticationFilter tokenFilter = new TokenAuthenticationFilter(userDao);
http.addFilterBefore(tokenFilter, BasicAuthenticationFilter.class);
http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), CustomUsernamePasswordAuthenticationFilter.class);
http.csrf().disable();
http.cors();
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/news/create").hasAnyAuthority("ADMIN")
.antMatchers("/news/update").hasAnyAuthority("ADMIN")
.antMatchers("/news/update/*").hasAnyAuthority("ADMIN")
.antMatchers("/news/delete").hasAnyAuthority("ADMIN")
.antMatchers("/**").hasAnyAuthority("USER", "ADMIN")
.and()
.logout();
}
//cors configuration bean
...
}
I've used many different ways how to solve it. But nothing works...
I can't now post this question because there is a lot of code. So sorry, but I have to write some sentences to post it)
Thanks
try to add encoding config in application.properties
as below :
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
See doc for more info
I want to use OAuth2 for my REST spring boot project. Using some examples I have created configuration for OAuth2:
#Configuration
public class OAuth2Configuration {
private static final String RESOURCE_ID = "restservice";
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
// #formatter:off
resources
.resourceId(RESOURCE_ID);
// #formatter:on
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.anonymous().disable()
.authorizeRequests().anyRequest().authenticated();
// #formatter:on
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore = new InMemoryTokenStore();
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsServiceImpl userDetailsService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
// #formatter:off
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
// #formatter:on
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// #formatter:off
clients
.inMemory()
.withClient("clientapp")
.authorizedGrantTypes("password", "refresh_token", "trust")
.authorities("USER")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.secret("clientsecret")
.accessTokenValiditySeconds(1200)
.refreshTokenValiditySeconds(3600);
// #formatter:on
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
}
}
This is my SecurityConfiguration class:
#Configuration
#EnableWebSecurity
#Order(1)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.authorizeRequests().antMatchers("/api/register").permitAll()
.and()
.authorizeRequests().antMatchers("/api/free").permitAll()
.and()
.authorizeRequests().antMatchers("/oauth/token").permitAll()
.and()
.authorizeRequests().antMatchers("/api/secured").hasRole("USER")
.and()
.authorizeRequests().anyRequest().authenticated();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I tried to check my application with 2 simple requests:
#RequestMapping(value = "/api/secured", method = RequestMethod.GET)
public String checkSecured(){
return "Authorization is ok";
}
#RequestMapping(value = "/api/free", method = RequestMethod.GET)
public String checkFree(){
return "Free from authorization";
}
Firstly I checked two requests:
/api/free returned code 200 and the string "Free from authorization"
/api/secured returned {"timestamp":1487451065106,"status":403,"error":"Forbidden","message":"Access Denied","path":"/api/secured"}
And it seems that they work fine.
Then I got access_token (using credentials from my users database)
/oauth/token?grant_type=password&username=emaila&password=emailo
Response:
{"access_token":"3344669f-c66c-4161-9516-d7e2f31a32e8","token_type":"bearer","refresh_token":"c71c17e4-45ba-458c-9d98-574de33d1859","expires_in":1199,"scope":"read write"}
Then I tried to send a request (with the token I got) for resource which requires authentication:
/api/secured?access_token=3344669f-c66c-4161-9516-d7e2f31a32e8
Here is response:
{"timestamp":1487451630224,"status":403,"error":"Forbidden","message":"Access Denied","path":"/api/secured"}
I cannot understand why access is denied. I am not sure in configurations and it seems that they are incorrect. Also I still do not clearly understand relationships of methods configure(HttpSecurity http) in class which extends WebSecurityConfigurerAdapter and in another which extends ResourceServerConfigurerAdapter.
Thank you for any help!
If you are using spring boot 1.5.1 or recently updated to it, note that they changed the filter order for spring security oauth2 (Spring Boot 1.5 Release Notes).
According to the release notes, try to add the following property to application.properties/yml, after doing that the resource server filters will be used after your other filters as a fallback - this should cause the authorization to be accepted before falling to the resource server:
security.oauth2.resource.filter-order = 3
You can find a good answer for your other questions here: https://stackoverflow.com/questions/28537181