How to implement custom UserDetailsService or custom AuthenticationProvider in Spring authorization server 0.2.0 - spring-boot

I am trying a new Spring Authorization server 0.2.0. I have managed to successfully run a sample application located at https://github.com/spring-projects/spring-authorization-server/tree/main/samples/boot/oauth2-integration.
Now, I am trying to add custom UserDetailsService to the authorization server. I have created a custom UserDetailsService with users saved in the Mysql database.
I have replaced this
#Bean
UserDetailsService users() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user1")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
with this
#Bean
UserDetailsService users() {
return new CustomUserDetailsService();
}
Now Application throws an error "No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken" while trying to login in "Authorization Code" grant flow.
I don't know where to add my custom AuthenticationProvider. I have tried adding to DefaultSecurityConfig as below. But authorization code grant flow always returns invalid_client.
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authenticationProvider(authenticationProvider)
.authorizeRequests(authorizeRequests ->
authorizeRequests.antMatchers("/actuator/**").permitAll()
.anyRequest().authenticated())
.formLogin(withDefaults());
return http.build();
}
I think, I missed something about client authentication here as my custom authenticationProvider is having to authenticate the method only for users but not clients.
Now my question is how to add custom AuthenticationProvider or CustomUserDetailsService without adding AuthenticationProvider to the Spring authorization server.
UPDATE:
Here are my CustomUserDetailsService and CustomAuthenticationProvider
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public DcubeUserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Supplier<UsernameNotFoundException> s =
() -> new UsernameNotFoundException("Problem during authentication!");
DcubeUser u = userRepository.findUserByUsername(username).orElseThrow(s);
return new DcubeUserDetails(u);
}
}
#Service
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
CustomUserDetails user = userDetailsService.loadUserByUsername(username);
return checkPassword(user, password);
}
#Override
public boolean supports(Class<?> aClass) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
}
private Authentication checkPassword(CustomUserDetails user, String rawPassword) {
if (Objects.equals(rawPassword, user.getPassword())) {
return new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), user.getAuthorities());
} else {
throw new BadCredentialsException("Bad credentials");
}
}
}
Here is my log
2021-10-27 09:08:34.387 TRACE 10928 --- [nio-8888-exec-7] o.s.s.w.s.HttpSessionRequestCache : Did not match request /error to the saved one DefaultSavedRequest [http://localhost:8888/oauth2/authorize?response_type=code&client_id=web-client&scope=web:write]
2021-10-27 09:08:34.387 TRACE 10928 --- [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderAwareRequestFilter (10/14)
2021-10-27 09:08:34.387 TRACE 10928 --- [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking AnonymousAuthenticationFilter (11/14)
2021-10-27 09:08:34.387 TRACE 10928 --- [nio-8888-exec-7] o.s.s.w.a.AnonymousAuthenticationFilter : Did not set SecurityContextHolder since already authenticated UsernamePasswordAuthenticationToken [Principal=Ramesh, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=D4FF0763B895353AC334140528DE35CD], Granted Authorities=[ADMIN]]
2021-10-27 09:08:34.387 TRACE 10928 --- [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking SessionManagementFilter (12/14)
2021-10-27 09:08:34.387 TRACE 10928 --- [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking ExceptionTranslationFilter (13/14)
2021-10-27 09:08:34.387 TRACE 10928 --- [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking FilterSecurityInterceptor (14/14)
2021-10-27 09:08:34.387 DEBUG 10928 --- [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Secured GET /error
2021-10-27 09:08:34.464 DEBUG 10928 --- [nio-8888-exec-7] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2021-10-27 09:08:56.440 TRACE 10928 --- [nio-8888-exec-8] o.s.security.web.FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer$$Lambda$1085/0x0000000801355c90#32e7df65, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#421d7900, org.springframework.security.web.context.SecurityContextPersistenceFilter#42a7e7e1, org.springframework.security.web.header.HeaderWriterFilter#55e88bc, org.springframework.security.web.csrf.CsrfFilter#20a116a0, org.springframework.security.web.authentication.logout.LogoutFilter#67e21ea2, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter#e2ee348, org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter#5d67bf4d, org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter#1477d4e6, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter#5ec3689b, org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter#448fa659, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#7c0a6f62, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter#4946dfde, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter#45964b9e, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#554e9509, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#34ea86ff, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#166a5659, org.springframework.security.web.session.SessionManagementFilter#4c12f54a, org.springframework.security.web.access.ExceptionTranslationFilter#417b3642, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#22ed2886, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter#76219fe, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenIntrospectionEndpointFilter#4c599679, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter#1bcf2c64]] (1/2)
2021-10-27 09:08:56.440 DEBUG 10928 --- [nio-8888-exec-8] o.s.security.web.FilterChainProxy : Securing POST /oauth2/authorize
2021-10-27 09:08:56.440 TRACE 10928 --- [nio-8888-exec-8] o.s.security.web.FilterChainProxy : Invoking WebAsyncManagerIntegrationFilter (1/22)
2021-10-27 09:08:56.441 TRACE 10928 --- [nio-8888-exec-8] o.s.security.web.FilterChainProxy : Invoking SecurityContextPersistenceFilter (2/22)
2021-10-27 09:08:56.441 TRACE 10928 --- [nio-8888-exec-8] w.c.HttpSessionSecurityContextRepository : Retrieved SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=Ramesh, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=D4FF0763B895353AC334140528DE35CD], Granted Authorities=[ADMIN]]] from SPRING_SECURITY_CONTEXT
2021-10-27 09:08:56.441 DEBUG 10928 --- [nio-8888-exec-8] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=Ramesh, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=D4FF0763B895353AC334140528DE35CD], Granted Authorities=[ADMIN]]]
2021-10-27 09:08:56.441 TRACE 10928 --- [nio-8888-exec-8] o.s.security.web.FilterChainProxy : Invoking HeaderWriterFilter (3/22)
2021-10-27 09:08:56.442 TRACE 10928 --- [nio-8888-exec-8] o.s.security.web.FilterChainProxy : Invoking CsrfFilter (4/22)
2021-10-27 09:08:56.442 TRACE 10928 --- [nio-8888-exec-8] o.s.security.web.csrf.CsrfFilter : Did not protect against CSRF since request did not match And [CsrfNotRequired [TRACE, HEAD, GET, OPTIONS], Not [Or [org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer$$Lambda$1085/0x0000000801355c90#32e7df65]]]
2021-10-27 09:08:56.442 TRACE 10928 --- [nio-8888-exec-8] o.s.security.web.FilterChainProxy : Invoking LogoutFilter (5/22)
2021-10-27 09:08:56.443 TRACE 10928 --- [nio-8888-exec-8] o.s.s.w.a.logout.LogoutFilter : Did not match request to Ant [pattern='/logout', POST]
2021-10-27 09:08:56.443 TRACE 10928 --- [nio-8888-exec-8] o.s.security.web.FilterChainProxy : Invoking OAuth2AuthorizationEndpointFilter (6/22)
2021-10-27 09:08:56.444 TRACE 10928 --- [nio-8888-exec-8] o.s.s.authentication.ProviderManager : Authenticating request with OAuth2AuthorizationCodeRequestAuthenticationProvider (1/8)
2021-10-27 09:08:56.447 DEBUG 10928 --- [nio-8888-exec-8] o.s.s.web.DefaultRedirectStrategy : Redirecting to http://localhost:8080/authorized?code=iaFZSqcRLeJucw2mx_HNgji1PWN9QPHaUZt0htdH2zc3_4hEPFoBamnijwuRcK2xTzOT_W4jCTne3AmjAKB2gyoVzod5otPfgB8WSLc_8-x2B13oapwhlWX4dBUUER2e
2021-10-27 09:08:56.447 TRACE 10928 --- [nio-8888-exec-8] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match request to [Is Secure]
2021-10-27 09:08:56.447 DEBUG 10928 --- [nio-8888-exec-8] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2021-10-27 09:09:23.121 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer$$Lambda$1085/0x0000000801355c90#32e7df65, Filters=[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#421d7900, org.springframework.security.web.context.SecurityContextPersistenceFilter#42a7e7e1, org.springframework.security.web.header.HeaderWriterFilter#55e88bc, org.springframework.security.web.csrf.CsrfFilter#20a116a0, org.springframework.security.web.authentication.logout.LogoutFilter#67e21ea2, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter#e2ee348, org.springframework.security.oauth2.server.authorization.oidc.web.OidcProviderConfigurationEndpointFilter#5d67bf4d, org.springframework.security.oauth2.server.authorization.web.NimbusJwkSetEndpointFilter#1477d4e6, org.springframework.security.oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter#5ec3689b, org.springframework.security.oauth2.server.authorization.web.OAuth2ClientAuthenticationFilter#448fa659, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#7c0a6f62, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter#4946dfde, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter#45964b9e, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#554e9509, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#34ea86ff, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#166a5659, org.springframework.security.web.session.SessionManagementFilter#4c12f54a, org.springframework.security.web.access.ExceptionTranslationFilter#417b3642, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#22ed2886, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter#76219fe, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenIntrospectionEndpointFilter#4c599679, org.springframework.security.oauth2.server.authorization.web.OAuth2TokenRevocationEndpointFilter#1bcf2c64]] (1/2)
2021-10-27 09:09:23.122 DEBUG 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Securing POST /oauth2/token?grant_type=authorization_code&code=iaFZSqcRLeJucw2mx_HNgji1PWN9QPHaUZt0htdH2zc3_4hEPFoBamnijwuRcK2xTzOT_W4jCTne3AmjAKB2gyoVzod5otPfgB8WSLc_8-x2B13oapwhlWX4dBUUER2e&scope=dcube:write&redirect_uri=http://localhost:8888/authorized
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking WebAsyncManagerIntegrationFilter (1/22)
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking SecurityContextPersistenceFilter (2/22)
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] w.c.HttpSessionSecurityContextRepository : Created SecurityContextImpl [Null authentication]
2021-10-27 09:09:23.122 DEBUG 10928 --- [io-8888-exec-10] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking HeaderWriterFilter (3/22)
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking CsrfFilter (4/22)
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.csrf.CsrfFilter : Did not protect against CSRF since request did not match And [CsrfNotRequired [TRACE, HEAD, GET, OPTIONS], Not [Or [org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer$$Lambda$1085/0x0000000801355c90#32e7df65]]]
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking LogoutFilter (5/22)
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] o.s.s.w.a.logout.LogoutFilter : Did not match request to Ant [pattern='/logout', POST]
2021-10-27 09:09:23.122 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking OAuth2AuthorizationEndpointFilter (6/22)
2021-10-27 09:09:23.123 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking OidcProviderConfigurationEndpointFilter (7/22)
2021-10-27 09:09:23.123 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking NimbusJwkSetEndpointFilter (8/22)
2021-10-27 09:09:23.123 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking OAuth2AuthorizationServerMetadataEndpointFilter (9/22)
2021-10-27 09:09:23.123 TRACE 10928 --- [io-8888-exec-10] o.s.security.web.FilterChainProxy : Invoking OAuth2ClientAuthenticationFilter (10/22)
2021-10-27 09:09:23.124 TRACE 10928 --- [io-8888-exec-10] o.s.s.authentication.ProviderManager : Authenticating request with OAuth2ClientAuthenticationProvider (1/8)
2021-10-27 09:09:23.124 WARN 10928 --- [io-8888-exec-10] o.s.s.c.bcrypt.BCryptPasswordEncoder : Encoded password does not look like BCrypt
2021-10-27 09:09:23.127 TRACE 10928 --- [io-8888-exec-10] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match request to [Is Secure]
2021-10-27 09:09:23.127 DEBUG 10928 --- [io-8888-exec-10] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2021-10-27 09:09:23.127 DEBUG 10928 --- [io-8888-exec-10] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2021-10-27 09:09:23.127 DEBUG 10928 --- [io-8888-exec-10] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request

you need to delete following Bean from DefaultSecurityConfig class.
#Bean
UserDetailsService users() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user1")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
Add following method and an Autowired custom AuthenticationProvider to the same class
#Autowired
public void myCoolMethodName(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
Now everything working as I expected.
The complete DefaultSecurityConfig will be like
#EnableWebSecurity
public class DefaultSecurityConfig {
#Autowired
private CustomAuthenticationProvider authenticationProvider;
#Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests ->
authorizeRequests.anyRequest().authenticated())
.formLogin(withDefaults());
return http.build();
}
#Autowired
public void whateverMethodName(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
}

First, cross-check that you've made relatable changes in the security config file.
#Configuration
#EnableWebSecurity
#ComponentScan("com.frugalis")
public class CustAuthProviderConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider authProvider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and().httpBasic();
}
}
The above code registers a custom authentication provider and authorizes users.
To create a custom user service, you need to implement the UserDetailsService interface and override the loadUserByUsername() method.
Create UserDetailsServiceImp class under service package.
public class UserDetailsServiceImp implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/*Here we are using dummy data, you need to load user data from
database or other third party application*/
User user = findUserbyUername(username);
UserBuilder builder = null;
if (user != null) {
builder = org.springframework.security.core.userdetails.User.withUsername(username);
builder.password(new BCryptPasswordEncoder().encode(user.getPassword()));
builder.roles(user.getRoles());
} else {
throw new UsernameNotFoundException("User not found.");
}
return builder.build();
}
private User findUserbyUername(String username) {
if(username.equalsIgnoreCase("admin")) {
return new User(username, "admin123", "ADMIN");
}
return null;
}
}
Make sure to use the appropriate spring boot version and maven repositories.
For more, refer to this example:Spring Security 5 - Custom UserDetailsService example
Now define a Custom Authentication Provider.
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
boolean shouldAuthenticateAgainstThirdPartySystem = true;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
if (name.equals("admin") && password.equals("password")) {
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
final UserDetails principal = new User(name, password, grantedAuths);
final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
return auth;
} else {
return null;
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
In the above code, we have retrieved the Username and password from the Authentication object. Once We retrieve the Authentication Object and Credentials, we are validating the username and password.
You can perform database-based authentication, we have done a hard-coded validation here.
Once the user is valid we try and set GRANTED_AUTHORITY in the list of String and return an UserDetails Object to the Caller an Authentication object. Instead of spring-provided UserDetails, we can customize the User object set in principal and return.
Custom Authentication Provider Spring Security

Related

403 Forbidden when introducing authorization on spring boot rest

I am with my first spring-boot project. I did succesfully configure it to check for authentication; if the user/password was wrong the method was not invoked (status 401 unauthorized), if it was right it succeeded.
Now I have added authorization with JSR250 and I am only getting 403 Access denied.
The WS:
#RestController
#RequestMapping("/password")
public class ServicioPassword {
#GetMapping(path = "ldap")
public ResponseEntity<String> getLdap() {
var authentication = SecurityContextHolder.getContext().getAuthentication();
System.out.println("EN LDAP " + authentication.getPrincipal() + " - " + authentication.isAuthenticated());
for (var authority : authentication.getAuthorities()) {
System.out.println("Authority= " + authority);
}
return ResponseEntity.ok("DE LDAP");
}
When invoked, I get this on console:
EN LDAP LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]] - true
Authority= AGNI_OIMIVR
Yet, if I add #RolesAllowed("AGNI_OIMIVR"), when I invoke it I get a 403 Forbidden.
The MethodSecurityConfig:
#Configuration
#EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true)
public class MethodSecurityConfig
extends GlobalMethodSecurityConfiguration{
}
I have kept the WebSecurityConfig:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Autowired
private Environment environment;
#Bean
BindAuthenticator bindAuthenticator(
final BaseLdapPathContextSource contextSource) {
var bindAuthenticator = new BindAuthenticator(contextSource);
bindAuthenticator.setUserDnPatterns(new String[]{environment.getRequiredProperty("spring.ldap.userdnpattern")});
return bindAuthenticator;
}
#Bean
AuthenticationProvider ldapAuthenticationProvider(
final LdapAuthenticator ldapAuthenticator) {
var ldapAuthenticationProvider = new LdapAuthenticationProvider(ldapAuthenticator);
var ldapUserDetailsMapper = new CustomUserDetailsMapper();
var ldapMemberRoles = environment.getRequiredProperty("spring.ldap.roleattributes");
ldapUserDetailsMapper.setRoleAttributes(ldapMemberRoles.split(","));
ldapUserDetailsMapper.setRolePrefix("");
ldapAuthenticationProvider.setUserDetailsContextMapper(ldapUserDetailsMapper);
return ldapAuthenticationProvider;
}
#Bean
SecurityFilterChain filterChain(
final HttpSecurity http)
throws Exception {
http.csrf().disable()
.cors().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and()
.authorizeRequests()
.anyRequest().authenticated().and()
.httpBasic();
return http.build();
}
UPDATE: Adding log after setting logging.level.org.springframework.security=TRACE:
Note that the line: 2022-07-07 13:04:27.464 WARN 81968 --- [nio-8080-exec-2] e.s.d.o.s.ws.CustomUserDetailsMapper : createAuthority agni_oimivr comes from a log from one of my custom classes.
2022-07-07 13:04:27.441 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.www.BasicAuthenticationFilter : Found username 'ivr_apl_user' in Basic Authorization header
2022-07-07 13:04:27.442 TRACE 81968 --- [nio-8080-exec-2] o.s.s.authentication.ProviderManager : Authenticating request with LdapAuthenticationProvider (1/1)
2022-07-07 13:04:27.444 TRACE 81968 --- [nio-8080-exec-2] o.s.s.l.a.BindAuthenticator : Attempting to bind as cn=ivr_apl_user,ou=[REDACTED]
2022-07-07 13:04:27.444 TRACE 81968 --- [nio-8080-exec-2] s.s.l.DefaultSpringSecurityContextSource : Removing pooling flag for user cn=ivr_apl_user,ou=[REDACTED]
2022-07-07 13:04:27.463 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.l.a.BindAuthenticator : Bound cn=ivr_apl_user,ou=[REDACTED]
2022-07-07 13:04:27.463 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.l.u.LdapUserDetailsMapper : Mapping user details from context with DN cn=ivr_apl_user,ou=[REDACTED]
2022-07-07 13:04:27.464 WARN 81968 --- [nio-8080-exec-2] e.s.d.o.s.ws.CustomUserDetailsMapper : createAuthority agni_oimivr
2022-07-07 13:04:27.464 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.l.a.LdapAuthenticationProvider : Authenticated user
2022-07-07 13:04:27.465 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.w.a.www.BasicAuthenticationFilter : Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]]
2022-07-07 13:04:27.465 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking RequestCacheAwareFilter (7/12)
2022-07-07 13:04:27.465 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.s.HttpSessionRequestCache : No saved request
2022-07-07 13:04:27.465 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderAwareRequestFilter (8/12)
2022-07-07 13:04:27.466 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking AnonymousAuthenticationFilter (9/12)
2022-07-07 13:04:27.466 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Did not set SecurityContextHolder since already authenticated UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]]
2022-07-07 13:04:27.466 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking SessionManagementFilter (10/12)
2022-07-07 13:04:27.467 TRACE 81968 --- [nio-8080-exec-2] s.CompositeSessionAuthenticationStrategy : Preparing session with ChangeSessionIdAuthenticationStrategy (1/1)
2022-07-07 13:04:27.467 DEBUG 81968 --- [nio-8080-exec-2] w.c.HttpSessionSecurityContextRepository : The HttpSession is currently null, and the HttpSessionSecurityContextRepository is prohibited from creating an HttpSession (because the allowSessionCreation property is false) - SecurityContext thus not stored for next request
2022-07-07 13:04:27.467 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking ExceptionTranslationFilter (11/12)
2022-07-07 13:04:27.467 TRACE 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking FilterSecurityInterceptor (12/12)
2022-07-07 13:04:27.468 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Did not re-authenticate UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]] before authorizing
2022-07-07 13:04:27.468 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Authorizing filter invocation [GET /password/ldap] with attributes [authenticated]
2022-07-07 13:04:27.469 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Authorized filter invocation [GET /password/ldap] with attributes [authenticated]
2022-07-07 13:04:27.470 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Did not switch RunAs authentication since RunAsManager returned null
2022-07-07 13:04:27.470 DEBUG 81968 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Secured GET /password/ldap
2022-07-07 13:04:27.471 TRACE 81968 --- [nio-8080-exec-2] o.s.s.a.i.a.MethodSecurityInterceptor : Did not re-authenticate UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]] before authorizing
2022-07-07 13:04:27.472 TRACE 81968 --- [nio-8080-exec-2] o.s.s.a.i.a.MethodSecurityInterceptor : Authorizing ReflectiveMethodInvocation: public org.springframework.http.ResponseEntity es.ssib.dtic.oimivr.service.ws.v1.ServicioPassword.getLdap(); target is of class [es.ssib.dtic.oimivr.service.ws.v1.ServicioPassword] with attributes [ROLE_AGNI_OIMIVR]
2022-07-07 13:04:27.475 TRACE 81968 --- [nio-8080-exec-2] o.s.s.a.i.a.MethodSecurityInterceptor : Failed to authorize ReflectiveMethodInvocation: public org.springframework.http.ResponseEntity es.ssib.dtic.oimivr.service.ws.v1.ServicioPassword.getLdap(); target is of class [es.ssib.dtic.oimivr.service.ws.v1.ServicioPassword] with attributes [ROLE_AGNI_OIMIVR] using AffirmativeBased [DecisionVoters=[org.springframework.security.access.annotation.Jsr250Voter#6797e2e2, org.springframework.security.access.vote.RoleVoter#2ab76862, org.springframework.security.access.vote.AuthenticatedVoter#152f6a2e], AllowIfAllAbstainDecisions=false]
2022-07-07 13:04:27.484 TRACE 81968 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Sending UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]] to access denied handler since access is denied
org.springframework.security.access.AccessDeniedException: Acceso denegado
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73) ~[spring-security-core-5.7.1.jar:5.7.1]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:239) ~[spring-security-core-5.7.1.jar:5.7.1]
[...]
2022-07-07 13:04:27.497 DEBUG 81968 --- [nio-8080-exec-2] o.s.s.w.access.AccessDeniedHandlerImpl : Responding with 403 status code
What am I doing wrong?
The Authentication object of your authenticated user is:
UsernamePasswordAuthenticationToken [Principal=LdapUserDetailsImpl [Dn=cn=ivr_apl_user,ou=IVR,ou=Aplicaciones,dc=pre,dc=aplssib; Username=ivr_apl_user; Password=[PROTECTED]; Enabled=true; AccountNonExpired=true; CredentialsNonExpired=true; AccountNonLocked=true; Granted Authorities=[AGNI_OIMIVR]], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[AGNI_OIMIVR]]
Note that the GrantedAuthorities is Granted Authorities=[AGNI_OIMIVR], there is no ROLE_ prefix there. When you add #RolesAllowed("AGNI_OIMIVR") to the method, the ROLE_ prefix will be added automatically to the authority that you passed as an argument to the annotation, becoming ROLE_AGNI_OIMIVR.
Spring Security will try to match ROLE_AGNI_OIMIVR that is in the annotation with AGNI_OIMIVR that is in the granted authorities' property, but they do not match.
You have three options:
Change the role in LDAP to have the ROLE_ prefix
Expose a Bean of GrantedAuthorityDefaults removing the rolePrefix, like so:
#Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults("");
}
Use #PreAuthorize("hasAuthority('AGNI_OIMIVR')")
Another tip would be to use the new #EnableMethodSecurity(jsr250Enabled = true) which uses the simplified AuthorizationManager API, improve logging, amongst others.

Spring Boot Security Basic auth access denied

I'm trying to make an authenticated GET request on one of the resources:
http://user:psw#localhost:8090/devices
This works fine from the browser. But from National Instrument GWeb I keep getting Code 401 (Unauthorized).
SecurityConfiguration.java:
#Configuration
#EnableWebSecurity
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final DatabaseUserDetailsService databaseUserDetailsService;
public SecurityConfiguration(DatabaseUserDetailsService databaseUserDetailsService) {
super();
this.databaseUserDetailsService = databaseUserDetailsService;
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
#Bean
public AuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(this.databaseUserDetailsService);
return provider;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://rog-valerio", "http://localhost:8090"));
configuration.setAllowedMethods(Arrays.asList("GET","POST", "OPTIONS"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
From the configure() method:
httpSecurity.cors().and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
I'm I am not wrong this should mean that any request should be able to authenticate.
By enabling spring security debug, when I try to make the authenticated request I get the following:
2022-03-09 10:37:00.520 DEBUG 27408 --- [nio-8090-exec-5] o.s.security.web.FilterChainProxy : Securing GET /devices
2022-03-09 10:37:00.520 DEBUG 27408 --- [nio-8090-exec-5] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2022-03-09 10:37:00.521 DEBUG 27408 --- [nio-8090-exec-5] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2022-03-09 10:37:00.521 DEBUG 27408 --- [nio-8090-exec-5] o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [GET /devices] with attributes [authenticated]
2022-03-09 10:37:00.522 DEBUG 27408 --- [nio-8090-exec-5] o.s.s.w.s.HttpSessionRequestCache : Saved request http://localhost:8090/devices to session
2022-03-09 10:37:00.523 DEBUG 27408 --- [nio-8090-exec-5] s.w.a.DelegatingAuthenticationEntryPoint : Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]
2022-03-09 10:37:00.523 DEBUG 27408 --- [nio-8090-exec-5] s.w.a.DelegatingAuthenticationEntryPoint : No match found. Using default entry point org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint#30dfc62d
2022-03-09 10:37:00.523 DEBUG 27408 --- [nio-8090-exec-5] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2022-03-09 10:37:00.523 DEBUG 27408 --- [nio-8090-exec-5] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2022-03-09 10:37:00.523 DEBUG 27408 --- [nio-8090-exec-5] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2022-03-09 10:37:00.523 DEBUG 27408 --- [nio-8090-exec-5] o.s.security.web.FilterChainProxy : Securing GET /error
2022-03-09 10:37:00.524 DEBUG 27408 --- [nio-8090-exec-5] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2022-03-09 10:37:00.524 DEBUG 27408 --- [nio-8090-exec-5] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2022-03-09 10:37:00.524 DEBUG 27408 --- [nio-8090-exec-5] o.s.security.web.FilterChainProxy : Secured GET /error
2022-03-09 10:37:00.525 DEBUG 27408 --- [nio-8090-exec-5] a.DefaultWebInvocationPrivilegeEvaluator : filter invocation [/error] denied for AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=05282221D24CA222616679CE3049C092], Granted Authorities=[ROLE_ANONYMOUS]]
org.springframework.security.access.AccessDeniedException: Access is denied
And access is denied. Username and password are correct. Why am I getting the request rejected? Maybe there is some configuration that I am missing?
I found the answer, configuration was fine. But, as stated here https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization#examples , I added "Authorization" header with base64 encoded username and password. Now it works.
I'll not delete the question because maybe it'll be useful to somebody

Spring Authorization Server | /userinfo endpoint returns 401 Unauthorized Error

I'm trying to use Spring Authorization Server for authorizing users, but I have a problem with /userinfo endpoint, it's always returning 401 Unauthorized Error.
My /userinfo request looks like:
GET /userinfo HTTP/1.1
Host: localhost:8080
Authorization: Bearer eyJraWQiOiIyMTIxNjAzNC1kYTc4LTRlMTQtODI3Ni1lNzlmM2NlZDM3NzYiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImF1ZCI6ImN5cHJlc3MtY2xpZW50LWlkIiwibmJmIjoxNjQ2MzI2Mzc2LCJzY29wZSI6WyJvcGVuaWQiXSwiaXNzIjoiaHR0cDpcL1wvbG9jYWxob3N0OjgwODAiLCJleHAiOjE2NDYzMjgxNzYsImlhdCI6MTY0NjMyNjM3Nn0.aJsCVLoszgi2uCq6Jd9ov83QZFsqN1HK7-sE7Lbs11APRP1cHRYV2hlnrt7i7znMMquWsIfutiVlwOlPzX-lDJpNgthHkqVlIplrIFQdvCT6FTXO7V8dnyyHFhPbnPdYtWHnFoES3gpEazKD8IHnxuvYz75D98EcU9pOFH7zwqxh7t3uhvDXzijjdM59C_94zng2ufCCRmWf0NZd9uj1M9Y8iz1SI_fNjBbkwhe8ZecN6GGX9BPkuaWc_WB4OP8nANIkGgEpf-NlEoitrRPBDVwB-yAXKr8DV6c6Nb-AnGj-ogyjmdLBRE0tFG2mH6mHyplJYnQPzJjfOx_mqV9U0A
My Spring Authorization Server configuration:
#EnableWebSecurity
public class SpringSecurityConfiguration {
#Bean
public UserDetailsService users() {
// #formatter:off
UserDetails user = User.withUsername("admin").password("password").roles("ADMIN").build();
return new InMemoryUserDetailsManager(user);
}
#Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
// defining security for other endpoints of your application including the
// #formatter:off
http.authorizeRequests(authorizeRequest -> authorizeRequest.anyRequest().authenticated())
.formLogin(Customizer.withDefaults());
// #formatter:on
return http.build();
}
}
#Configuration
public class AuthorizationServerConfiguration {
#Bean
public OAuth2AuthorizationConsentService authorizationConsentService() {
return new InMemoryOAuth2AuthorizationConsentService();
}
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
// Defining security for the default endpoints of an Authorization Server
applyDefaultSecurity(http);
return http.cors().configurationSource(corsConfigurationSource()).and().formLogin(Customizer.withDefaults())
.build();
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:3000");
config.addAllowedHeader("*");
config.addAllowedHeader("authorization");
config.addAllowedMethod("GET");
config.addAllowedMethod("POST");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PUT");
config.addAllowedMethod("TRACE");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/.well-known/openid-configuration", config);
source.registerCorsConfiguration("/oauth2/token", config);
source.registerCorsConfiguration("/userinfo", config);
source.registerCorsConfiguration("userinfo", config);
source.registerCorsConfiguration("/oauth2/authorize", config);
source.registerCorsConfiguration("/oauth2/jwks", config);
return source;
}
#Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("cypress-client-id").clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).tokenSettings(tokenSettings())
.redirectUri("http://localhost:3000/signin/callback")
.redirectUri("http://localhost:3000/silent/callback").scope(OPENID).scope("offline_access")
.clientSettings(ClientSettings.builder().requireProofKey(true).build()).build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
#Bean
public TokenSettings tokenSettings() {
// #formatter:off
return TokenSettings.builder().accessTokenTimeToLive(Duration.ofMinutes(30L)).build();
// #formatter:on
}
}
The stake trace:
2022-03-03 18:08:48.875 TRACE 13257 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderAwareRequestFilter (17/25)
2022-03-03 18:08:48.876 TRACE 13257 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking AnonymousAuthenticationFilter (18/25)
2022-03-03 18:08:49.037 TRACE 13257 --- [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=E12CB3A032D3C0C442783899676963FC], Granted Authorities=[ROLE_ANONYMOUS]]
2022-03-03 18:08:49.037 TRACE 13257 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking SessionManagementFilter (19/25)
2022-03-03 18:08:49.204 TRACE 13257 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking ExceptionTranslationFilter (20/25)
2022-03-03 18:08:49.360 TRACE 13257 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Invoking FilterSecurityInterceptor (21/25)
2022-03-03 18:08:49.360 TRACE 13257 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Did not re-authenticate AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=E12CB3A032D3C0C442783899676963FC], Granted Authorities=[ROLE_ANONYMOUS]] before authorizing
2022-03-03 18:08:49.360 TRACE 13257 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Authorizing filter invocation [GET /userinfo] with attributes [authenticated]
2022-03-03 18:08:49.360 TRACE 13257 --- [nio-8080-exec-2] o.s.s.w.a.expression.WebExpressionVoter : Voted to deny authorization
2022-03-03 18:08:49.361 TRACE 13257 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [GET /userinfo] with attributes [authenticated] using AffirmativeBased [DecisionVoters=[org.springframework.security.web.access.expression.WebExpressionVoter#86d6bf7], AllowIfAllAbstainDecisions=false]
2022-03-03 18:08:49.512 TRACE 13257 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=E12CB3A032D3C0C442783899676963FC], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73) ~[spring-security-core-5.6.1.jar:5.6.1]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:239) ~[spring-security-core-5.6.1.jar:5.6.1]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:208) ~[spring-security-core-5.6.1.jar:5.6.1]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:113) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) ~[spring-security-web-5.6.1.jar:5.6.1]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.6.1.jar:5.6.1]
Does anyone know how to fix this problem?
Tnx in advance
Mihajlo
See OpenID Connect 1.0 UserInfo Endpoint in the reference docs, which has an example configuration demonstrating how to enable the use of the user info endpoint. Also, take a look at OidcUserInfoTests, which has a configuration that demonstrates this.
It requires the use of .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt) and a JwtDecoder #Bean to allow the JWT access token to be validated.

spring boot oauth2 - cannot obtain access token when use Basic Auth

I have problem to get access token from my spring-boot server v.2.0.3.RELEASE. I use spring-security-oauth v.2.3.3.RELEASE.
When I use postman I can get access token and in log I see that BasicAuthenticateFilter is match. But when use angularjs/react, BasicAuthenticateFilter is ommited and I got 401 without any message.
AuthenticationServer
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
static final String CLIENT_ID = "client";
static final String CLIENT_SECRET = "$2a$04$AMTwWHtjscVAHH4gPHx04.82v/W80KVJptp0l/QUWrlkiWU7g7wbe";
static final String GRANT_TYPE = "password";
static final String AUTHORIZATION_CODE = "authorization_code";
static final String REFRESH_TOKEN = "refresh_token";
static final String IMPLICIT = "implicit";
static final String SCOPE_READ = "read";
static final String SCOPE_WRITE = "write";
static final String TRUST = "trust";
static int ACCESS_TOKEN_VALIDITY_SECONDS = 2*60*60;
static final int REFRESH_TOKEN_VALIDITY_SECONDS = 6*60*60;
#Autowired
private TokenStore tokenStore;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(CLIENT_ID)
.secret(CLIENT_SECRET)
.authorizedGrantTypes(GRANT_TYPE, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT)
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
.refreshTokenValiditySeconds(REFRESH_TOKEN_VALIDITY_SECONDS);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager);
}
#Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
return propertySourcesPlaceholderConfigurer;
}
}
SecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Resource(name = "userService")
private UserDetailsService userDetailsService;
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(encoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated();
}
#Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(50);
return bean;
}
}
ResourceServer
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "resource_id";
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/user/register","/user/login").permitAll()
.antMatchers("/**").authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler())
.and().headers().frameOptions().disable();
}
}
angularjs code
angular.module('myApp.view1', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
templateUrl: 'view1/view1.html',
controller: 'View1Ctrl'
});
}])
.controller('View1Ctrl', ['$http','$httpParamSerializer', function($http, $httpParamSerializer) {
var ctrl = this;
this.data = {
grant_type:"password",
username: "",
password: "",
client_id: "client"
};
this.encoded = btoa("client:secret");
this.login = function() {
var req = {
method: 'POST',
url: "http://localhost:8080/api/oauth/token",
headers: {
"Authorization": "Basic " + ctrl.encoded,
"Content-type": "application/x-www-form-urlencoded; charset=utf-8"
},
data: $httpParamSerializer(ctrl.data)
}
$http(req).then(function(data){
console.log(data);
$http.defaults.headers.common.Authorization =
'Bearer ' + data.data.access_token;
$cookies.put("access_token", data.data.access_token);
window.location.href="index";
}, function(error) {
console.log(error);
});
}
}]);
This is my log from spring-boot
2018-06-22 19:01:45.134 INFO 23778 --- [nio-8080-exec-3] o.a.c.c.C.[Tomcat].[localhost].[/api] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-06-22 19:01:45.134 INFO 23778 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2018-06-22 19:01:45.143 INFO 23778 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 9 ms
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/oauth/token']
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/token'; against '/oauth/token'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : matched
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /oauth/token' doesn't match 'GET /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /oauth/token' doesn't match 'POST /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /oauth/token' doesn't match 'PUT /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /oauth/token' doesn't match 'DELETE /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#64454d87: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /oauth/token at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/oauth/token'; against '/oauth/token'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated]
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#64454d87: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2018-06-22 19:01:45.146 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter#62efc6af, returned: -1
2018-06-22 19:01:45.153 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
I find out solution for my problem. Main problem was with send OPTIONS request to oauth/token. I change my CorsFilter and SecurityConfig.
SecurityConfig.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
}
SimpleCorsFilter.java
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {
public SimpleCorsFilter() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
After this changes I got access token

Returning bad credential in oauth2 implemention using spring boot 1.5

As i am trying to create simple login in oauth2 implementation using spring boot. Unfortunately its not working, as i am newbie in spring
My configuration
ApplicationStarter.java
#SpringBootApplication
#EnableAutoConfiguration
public class ApplicationStarter extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(ApplicationStarter.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(ApplicationStarter.class, args);
}
}
ResourceServerConfiguration.java
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my_rest_api";
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
System.out.println("Inside ResourceServerConfiguration");
http.
anonymous().disable()
.requestMatchers().antMatchers("/user/**")
.and().authorizeRequests()
.antMatchers("/user/**").access("hasRole('ADMIN')")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
AuthorizationServerConfiguration.java
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private static String REALM="MY_OAUTH_REALM";
#Autowired
private TokenStore tokenStore;
#Autowired
private UserApprovalHandler userApprovalHandler;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
System.out.println("Inside AuthorizationServerConfiguration");
clients.inMemory()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.secret("secret")
.accessTokenValiditySeconds(120).//Access token is only valid for 2 minutes.
refreshTokenValiditySeconds(600);//Refresh token is only valid for 10 minutes.
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm(REALM+"/client");
}
}
MethodSecurityConfig.java
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
#Autowired
private OAuth2SecurityConfiguration securityConfig;
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
OAuth2SecurityConfiguration.java
#Configuration
#ComponentScan
#EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("inside OAuth2SecurityConfiguration : globalUserDetails()");
auth.inMemoryAuthentication()
.withUser("bill").password("abc123").roles("ADMIN").and()
.withUser("bob").password("abc123").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("inside OAuth2SecurityConfiguration : configure()");
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
System.out.println("inside OAuth2SecurityConfiguration : authenticationManagerBean()");
return super.authenticationManagerBean();
}
#Bean
public TokenStore tokenStore() {
System.out.println("inside OAuth2SecurityConfiguration : tokenStore()");
return new InMemoryTokenStore();
}
#Bean
#Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
System.out.println("inside OAuth2SecurityConfiguration : userApprovalHandler()");
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
#Bean
#Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
System.out.println("inside OAuth2SecurityConfiguration : approvalStore()");
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
}
Please do correct me where i am went wrong? whether any more configuration needed or not?
as i followed
http://websystique.com/spring-security/secure-spring-rest-api-using-oauth2/
as reference.
spring boot log
2017-10-26 11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.b.w.f.OrderedRequestContextFilter : Bound request context to
thread: org.apache.catalina.connector.RequestFacade#1f2fcd1 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/css/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/css/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/js/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/js/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/images/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/images/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/webjars/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/webjars/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='//favicon.ico'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '//favicon.ico'
2017-10-26 11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/error'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/error' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : No matches found 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/'] 2017-10-26 11:15:07.851 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Request
'/oauth/token' matched by universal pattern '/' 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : matched 2017-10-26
11:15:07.851 DEBUG 21456 --- [nio-8080-exec-5]
o.s.security.web.FilterChainProxy :
/oauth/token?grant_type=password&username=bill&password=abc123 at
position 1 of 11 in additional filter chain; firing Filter:
'WebAsyncManagerIntegrationFilter' 2017-10-26 11:15:07.851 DEBUG 21456
--- [nio-8080-exec-5] o.s.security.web.FilterChainProxy : /oauth/token?grant_type=password&username=bill&password=abc123 at
position 2 of 11 in additional filter chain; firing Filter:
'SecurityContextPersistenceFilter' 2017-10-26 11:15:07.852 DEBUG 21456
--- [nio-8080-exec-5] o.s.security.web.FilterChainProxy : /oauth/token?grant_type=password&username=bill&password=abc123 at
position 3 of 11 in additional filter chain; firing Filter:
'HeaderWriterFilter' 2017-10-26 11:15:07.852 DEBUG 21456 ---
[nio-8080-exec-5] o.s.security.web.FilterChainProxy :
/oauth/token?grant_type=password&username=bill&password=abc123 at
position 4 of 11 in additional filter chain; firing Filter:
'LogoutFilter' 2017-10-26 11:15:07.852 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.web.util.matcher.OrRequestMatcher : Trying to
match using Ant [pattern='/logout', GET] 2017-10-26 11:15:07.852 DEBUG
21456 --- [nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher :
Request 'POST /oauth/token' doesn't match 'GET /logout 2017-10-26
11:15:07.852 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/logout', POST] 2017-10-26 11:15:07.852 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking
match of request : '/oauth/token'; against '/logout' 2017-10-26
11:15:07.852 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/logout', PUT] 2017-10-26 11:15:07.869 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Request
'POST /oauth/token' doesn't match 'PUT /logout 2017-10-26 11:15:07.869
DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant
[pattern='/logout', DELETE] 2017-10-26 11:15:07.869 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.u.matcher.AntPathRequestMatcher : Request
'POST /oauth/token' doesn't match 'DELETE /logout 2017-10-26
11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.web.util.matcher.OrRequestMatcher : No matches found 2017-10-26
11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.security.web.FilterChainProxy :
/oauth/token?grant_type=password&username=bill&password=abc123 at
position 5 of 11 in additional filter chain; firing Filter:
'BasicAuthenticationFilter' 2017-10-26 11:15:07.869 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.a.www.BasicAuthenticationFilter : Basic
Authentication Authorization header found for user 'my-trusted-client'
2017-10-26 11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.authentication.ProviderManager : Authentication attempt
using
org.springframework.security.authentication.dao.DaoAuthenticationProvider
2017-10-26 11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.a.dao.DaoAuthenticationProvider : User 'my-trusted-client'
not found 2017-10-26 11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
o.s.s.w.a.www.BasicAuthenticationFilter : Authentication request for
failed:
org.springframework.security.authentication.BadCredentialsException:
Bad credentials 2017-10-26 11:15:07.869 DEBUG 21456 ---
[nio-8080-exec-5] o.s.s.w.header.writers.HstsHeaderWriter : Not
injecting HSTS header since it did not match the requestMatcher
org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#1ff799
2017-10-26 11:15:07.869 DEBUG 21456 --- [nio-8080-exec-5]
s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now
cleared, as request processing completed 2017-10-26 11:15:07.869 DEBUG
21456 --- [nio-8080-exec-5] o.s.b.w.f.OrderedRequestContextFilter :
Cleared thread-bound request context:
org.apache.catalina.connector.RequestFacade#1f2fcd1 2017-10-26
11:15:07.870 DEBUG 21456 --- [nio-8080-exec-5]
o.s.web.servlet.DispatcherServlet : DispatcherServlet with name
'dispatcherServlet' processing POST request for [/auth/error]
2017-10-26 11:15:07.870 DEBUG 21456 --- [nio-8080-exec-5]
s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method
for path /error 2017-10-26 11:15:07.870 DEBUG 21456 ---
[nio-8080-exec-5] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning
handler method [public
org.springframework.http.ResponseEntity>
org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)]
2017-10-26 11:15:07.870 DEBUG 21456 --- [nio-8080-exec-5]
o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance
of singleton bean 'basicErrorController' 2017-10-26 11:15:07.874 DEBUG
21456 --- [nio-8080-exec-5] o.s.w.s.m.m.a.HttpEntityMethodProcessor :
Written [{timestamp=Thu Oct 26 11:15:07 IST 2017, status=401,
error=Unauthorized, message=Bad credentials, path=/auth/oauth/token}]
as "application/json" using
[org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#32886a]
2017-10-26 11:15:07.874 DEBUG 21456 --- [nio-8080-exec-5]
o.s.web.servlet.DispatcherServlet : Null ModelAndView returned
to DispatcherServlet with name 'dispatcherServlet': assuming
HandlerAdapter completed request handling 2017-10-26 11:15:07.874
DEBUG 21456 --- [nio-8080-exec-5] o.s.web.servlet.DispatcherServlet
: Successfully completed request
gradle.build
> /* * This build file was generated by the Gradle 'init' task. * *
> This generated file contains a sample Java Library project to get you
> started. * For more details take a look at the Java Libraries chapter
> in the Gradle * user guide available at
> https://docs.gradle.org/3.5/userguide/java_library_plugin.html */
> buildscript {
> ext { springBootVersion = '1.5.7.RELEASE' }
> repositories { mavenCentral() }
> dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
> } } // Apply the java-library plugin to add support for Java Library
> apply plugin: 'java' apply plugin: 'eclipse' apply plugin:
> 'org.springframework.boot' apply plugin: 'war'
>
>
> sourceCompatibility = 1.8 // In this section you declare where to find
> the dependencies of your project repositories {
> // Use jcenter for resolving your dependencies.
> // You can declare any Maven/Ivy/file repository here. // jcenter() mavenCentral() }
>
> dependencies {
> // This dependency is exported to consumers, that is to say found on their compile classpath.
> //api 'org.apache.commons:commons-math3:3.6.1'
> //providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.5.2.RELEASE'
> // This dependency is used internally, and not exposed to consumers on their own compile classpath.
> implementation 'com.google.guava:guava:21.0'
>
> // Use JUnit test framework
> testImplementation 'junit:junit:4.12'
>
>
> // compile("org.springframework.boot:spring-boot-starter-security:1.4.1.RELEASE")
> // compile("org.springframework.security.oauth:spring-security-oauth2:2.0.2.RELEASE")
> //
> compile("org.springframework.security:spring-security-config:3.2.0.RELEASE")
> // compile("org.gitlab4j:gitlab4j-api:4.6.0")
> // compile("org.springframework.boot:spring-boot-starter-tomcat:1.5.2.RELEASE")
>
> compile('org.springframework.boot:spring-boot-starter-actuator')
> compile('org.springframework.boot:spring-boot-starter-security')
> compile('org.springframework.security.oauth:spring-security-oauth2')
> compile('org.springframework.security:spring-security-config')
> compile('org.springframework.boot:spring-boot-starter-web')
> providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
>
> testCompile('org.springframework.boot:spring-boot-starter-test') }
Change your authorization server config like that
AuthorizationServerConfiguration.java
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
System.out.println("Inside AuthorizationServerConfiguration");
clients.inMemory()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust").resourceIds("my_rest_api")
.secret("secret")
.accessTokenValiditySeconds(120).//Access token is only valid for 2 minutes.
refreshTokenValiditySeconds(600);//Refresh token is only valid for 10 minutes.
}
Here changes is I put a resourceIds after scope and that resource id will be same as Resources server's RESOURCE_ID.
You declared in ResourceServerConfiguration such like that
private static final String RESOURCE_ID = "my_rest_api";
So putting the string in authorization server can solve your problem I believe.
Thanks.

Resources