Logout doesn't work after updating Spring Boot from 2.7 to 3.0.1 - spring-boot

I have a Spring Boot application and the web security config looks like as follows:
#Configuration
#EnableWebSecurity(debug = false)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ClientRegistrationRepository clientRegistrationRepository;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// enables oauth2 login for any request
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
// configures logout adding an oidc logout success handler and invalidating the session on logout
.and()
.logout()
.logoutSuccessHandler(oidcLogoutSuccessHandler())
.invalidateHttpSession(true)
// adds security headers
.and()
.headers()
.addHeaderWriter(new StaticHeadersWriter("Referrer-Policy", "same-origin"))
.addHeaderWriter(new StaticHeadersWriter("Strict-Transport-Security", "max-age=31536000; includeSubDomains"))
// configures csrf
.and()
.csrf()
.csrfTokenRepository(getCookieCsrfTokenRepository());
}
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
// disables security for swagger ui and open api docs
return web -> web.ignoring().antMatchers("/**/health", "/swagger-ui/**", "/v3/**");
}
private CookieCsrfTokenRepository getCookieCsrfTokenRepository() {
CookieCsrfTokenRepository cookieCsrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
cookieCsrfTokenRepository.setCookiePath("/");
return cookieCsrfTokenRepository;
}
private OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler() {
// configures the oidc logout success handler to redirect to the idp login page
OidcClientInitiatedLogoutSuccessHandler successHandler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository);
successHandler.setPostLogoutRedirectUri("{baseUrl}" + RouteConstants.IDP_LOGIN);
return successHandler;
}
}
After updating the Spring Boot version from 2.7 to 3.0.1 and doing according changes, the applications runs normally I can login successfully, but the logout doesn't work. The WebSecurityConfig class now looks like as follows:
#Configuration
#EnableWebSecurity(debug = false)
public class WebSecurityConfig {
#Autowired
private ClientRegistrationRepository clientRegistrationRepository;
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// enables oauth2 login for any request
.authorizeHttpRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
// configures logout adding an oidc logout success handler and invalidating the session on logout
.and()
.logout()
.logoutSuccessHandler(oidcLogoutSuccessHandler())
.invalidateHttpSession(true)
// adds security headers
.and()
.headers()
.addHeaderWriter(new StaticHeadersWriter("Referrer-Policy", "same-origin"))
.addHeaderWriter(new StaticHeadersWriter("Strict-Transport-Security", "max-age=31536000; includeSubDomains"))
// configures csrf
.and()
.csrf()
.csrfTokenRepository(getCookieCsrfTokenRepository());
return http.build();
}
//The rest of the methods are the same
}
I added this property to make paths starting with /** work in a method webSecurityCustomizer()
spring.mvc.pathmatch.matching-strategy=ant-path-matcher
I noticed that the response cookie of http://localhost/api/v1/authentication/idp_login request doesn't contain XSRF-TOKEN, but before the update it was. Looking at the logs I am getting this error
org.springframework.security.web.FilterChainProxy - Securing POST /logout
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking DisableEncodeUrlFilter (1/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking WebAsyncManagerIntegrationFilter (2/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking SecurityContextHolderFilter (3/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking HeaderWriterFilter (4/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking CsrfFilter (5/15)
2023-01-21 DEBUG org.springframework.security.web.csrf.CsrfFilter - Invalid CSRF token found for http://localhost/api/v1/authentication/logout
2023-01-21 DEBUG org.springframework.security.web.access.AccessDeniedHandlerImpl - Responding with 403 status code
2023-01-21 TRACE org.springframework.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match request to [Is Secure]
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/**/health'], Filters=[]] (1/4)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/swagger-ui/**'], Filters=[]] (2/4)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/v3/**'], Filters=[]] (3/4)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter#527fc8e, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#61bfc9bf, org.springframework.security.web.context.SecurityContextHolderFilter#3722c145, org.springframework.security.web.header.HeaderWriterFilter#7601bc96, org.springframework.security.web.csrf.CsrfFilter#33063f5b, org.springframework.security.web.authentication.logout.LogoutFilter#3291b443, org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter#707b1a44, org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter#7132a9dc, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter#424de326, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter#2c7106d9, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#2975a9e, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#765ffb14, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#329bad59, org.springframework.security.web.access.ExceptionTranslationFilter#33634f04, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#53abfc07]] (4/4)
2023-01-21 DEBUG org.springframework.security.web.FilterChainProxy - Securing POST /error
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking DisableEncodeUrlFilter (1/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking WebAsyncManagerIntegrationFilter (2/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking SecurityContextHolderFilter (3/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking HeaderWriterFilter (4/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking CsrfFilter (5/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking LogoutFilter (6/15)
2023-01-21 TRACE org.springframework.security.web.authentication.logout.LogoutFilter - Did not match request to Ant [pattern='/logout', POST]
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking OAuth2AuthorizationRequestRedirectFilter (7/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking OAuth2LoginAuthenticationFilter (8/15)
2023-01-21 TRACE org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter - Did not match request to Ant [pattern='/login/oauth2/code/*']
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking DefaultLoginPageGeneratingFilter (9/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking DefaultLogoutPageGeneratingFilter (10/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking RequestCacheAwareFilter (11/15)
2023-01-21 TRACE org.springframework.security.web.savedrequest.HttpSessionRequestCache - matchingRequestParameterName is required for getMatchingRequest to lookup a value, but not provided
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking SecurityContextHolderAwareRequestFilter (12/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking AnonymousAuthenticationFilter (13/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking ExceptionTranslationFilter (14/15)
2023-01-21 TRACE org.springframework.security.web.FilterChainProxy - Invoking FilterSecurityInterceptor (15/15)
2023-01-21 TRACE org.springframework.security.web.context.HttpSessionSecurityContextRepository - Retrieved SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=Name: [f:5f27139d-e373-4f94-885e-2771b67c493e:admin], Granted Authorities: [[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]], User Attributes: [{at_hash=IezFNMq7qXBpS499wXpjZg, sub=f:5f27139d-e373-4f94-885e-2771b67c493e:admin, email_verified=false, iss=http://localhost:80/idp/realms/products, typ=ID, preferred_username=admin, nonce=RpXazbXIYWDYNmAYJeX088axKakz0J-XpIq7KoYzHGs, platform={userId=db1ca9cc-da2e-4e6a-bd96-111111111111, username=admin, email=admin#fortra.tmp.com, tenantId=bf045e23-d197-4ba2-ba5b-1f1f275ac2cd, cpUserId=cp_user_id2}, sid=9a579605-b6aa-4267-91e9-d6cfde2bbc4d, aud=[cp], acr=1, azp=cp, auth_time=2023-01-21T19:54:16Z, exp=2023-01-21T19:59:17Z, session_state=9a579605-b6aa-4267-91e9-d6cfde2bbc4d, iat=2023-01-21T19:54:26Z, jti=7278704f-2b56-471a-9b11-ef017268de23}], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=172.27.0.11, SessionId=9fa00c79-63cf-4528-bf1f-c0d358d9b655], Granted Authorities=[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]]] from SPRING_SECURITY_CONTEXT
2023-01-21 TRACE org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Did not set SecurityContextHolder since already authenticated OAuth2AuthenticationToken [Principal=Name: [f:5f27139d-e373-4f94-885e-2771b67c493e:admin], Granted Authorities: [[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]], User Attributes: [{at_hash=IezFNMq7qXBpS499wXpjZg, sub=f:5f27139d-e373-4f94-885e-2771b67c493e:admin, email_verified=false, iss=http://localhost:80/idp/realms/products, typ=ID, preferred_username=admin, nonce=RpXazbXIYWDYNmAYJeX088axKakz0J-XpIq7KoYzHGs, platform={userId=db1ca9cc-da2e-4e6a-bd96-111111111111, username=admin, email=admin#fortra.tmp.com, tenantId=bf045e23-d197-4ba2-ba5b-1f1f275ac2cd, cpUserId=cp_user_id2}, sid=9a579605-b6aa-4267-91e9-d6cfde2bbc4d, aud=[cp], acr=1, azp=cp, auth_time=2023-01-21T19:54:16Z, exp=2023-01-21T19:59:17Z, session_state=9a579605-b6aa-4267-91e9-d6cfde2bbc4d, iat=2023-01-21T19:54:26Z, jti=7278704f-2b56-471a-9b11-ef017268de23}], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=172.27.0.11, SessionId=9fa00c79-63cf-4528-bf1f-c0d358d9b655], Granted Authorities=[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]]
2023-01-21 TRACE org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Did not re-authenticate OAuth2AuthenticationToken [Principal=Name: [f:5f27139d-e373-4f94-885e-2771b67c493e:admin], Granted Authorities: [[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]], User Attributes: [{at_hash=IezFNMq7qXBpS499wXpjZg, sub=f:5f27139d-e373-4f94-885e-2771b67c493e:admin, email_verified=false, iss=http://localhost:80/idp/realms/products, typ=ID, preferred_username=admin, nonce=RpXazbXIYWDYNmAYJeX088axKakz0J-XpIq7KoYzHGs, platform={userId=db1ca9cc-da2e-4e6a-bd96-111111111111, username=admin, email=admin#fortra.tmp.com, tenantId=bf045e23-d197-4ba2-ba5b-1f1f275ac2cd, cpUserId=cp_user_id2}, sid=9a579605-b6aa-4267-91e9-d6cfde2bbc4d, aud=[cp], acr=1, azp=cp, auth_time=2023-01-21T19:54:16Z, exp=2023-01-21T19:59:17Z, session_state=9a579605-b6aa-4267-91e9-d6cfde2bbc4d, iat=2023-01-21T19:54:26Z, jti=7278704f-2b56-471a-9b11-ef017268de23}], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=172.27.0.11, SessionId=9fa00c79-63cf-4528-bf1f-c0d358d9b655], Granted Authorities=[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]] before authorizing
2023-01-21 TRACE org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorizing filter invocation [POST /error] with attributes [authenticated]
2023-01-21 DEBUG org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorized filter invocation [POST /error] with attributes [authenticated]
2023-01-21 TRACE org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Did not switch RunAs authentication since RunAsManager returned null
2023-01-21 DEBUG org.springframework.security.web.FilterChainProxy - Secured POST /error
Do the other changes need to make it work?

I resolved the problem by adding csrfTokenRequestHandler like this
http.csrf().csrfTokenRequestHandler(getCsrfTokenRequestHandler())
private CsrfTokenRequestAttributeHandler getCsrfTokenRequestHandler() {
CsrfTokenRequestAttributeHandler requestHandler = new CsrfTokenRequestAttributeHandler();
// set the name of the attribute the CsrfToken will be populated on
requestHandler.setCsrfRequestAttributeName(null);
return request handler;
}
Still had another issue that x-xss-protection is 0 but should be "1; mode=block"

Related

Spring Security basic auth exception lead to unwanted /error page call

I have simple spring-boot rest api service with following security config:
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().disable();
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/Events/**").permitAll()
.antMatchers(String.format("%s/**", restApiDocPath)).permitAll()
.antMatchers(String.format("%s/**", swaggerPath)).permitAll()
.antMatchers("/api/users/**").hasAuthority(SmUserRole.ROLE_ADMIN_STR)
.anyRequest().authenticated()
.and()
.httpBasic();
return http.build();
}
Unauthorized access to /api/users/ return 401 as expected but in logs I have request to /error url and AccessDeniedException in result:
o.s.security.web.FilterChainProxy : Securing GET /api/users/?page=0&size=20
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [GET /api/users/?page=0&size=20] with attributes [hasAuthority('ROLE_ADMIN')]
s.w.a.DelegatingAuthenticationEntryPoint : Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]
s.w.a.DelegatingAuthenticationEntryPoint : No match found. Using default entry point org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint#394122fd
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
o.s.security.web.FilterChainProxy : Securing GET /error?page=0&size=20
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
o.s.security.web.FilterChainProxy : Secured GET /error?page=0&size=20
a.DefaultWebInvocationPrivilegeEvaluator : filter invocation [/error] denied for AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
org.springframework.security.access.AccessDeniedException: Access is denied
I dont have /error endpoint in this service. What's the cause of this behavior?
BasicAuthenticationEntryPoint adds "WWW-Authenticate" header and sends UNAUTHORIZED error response, there is nothing about /error.

Upgrading to Spring-Security 5.7.0 SecurityContextPersistenceFilter not called

With WebSecurityConfigurerAdapter being deprecated in Spring-security 5.7.0 we are trying to migrate to the newer way to configuring securityFilterChain but in doing so i noticed in spring debug log that the SecurityContextPersistenceFilter isnt invoked. As a result when testing controllers with a requestPostProcessor the authentication set within the requestPostProcessor doesnt get applied to the HttpSession when the request is being authenticated.
Logs post the version upgrade
[main] DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - Created HttpSession as SecurityContext is non-default
[main] DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - Stored SecurityContextImpl [Authentication=TestAuthenticationToken [Principal=ApiUser [Username=USER, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[placeholder]], Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[]]] to HttpSession [org.springframework.mock.web.MockHttpSession#153d14e3]
[main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - POST "/v1/api_path”, parameters={}
[main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.xyz.Controller#controllerMethod(String, List)
Logs before the version upgrade
HttpSession as SecurityContext is non-default
[main] DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - Stored SecurityContextImpl [Authentication=TestAuthenticationToken [Principal=ApiUser [Username=USERNAME, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[placeholder]], Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[]]] to HttpSession [org.springframework.mock.web.MockHttpSession#d641499]
[main] DEBUG org.springframework.security.web.FilterChainProxy - Securing POST /v1/api_path
[main] DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - Retrieved SecurityContextImpl [Authentication=TestAuthenticationToken [Principal=ApiUser [Username=USERNAME, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[placeholder]], Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[]]]
[main] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - Set SecurityContextHolder to SecurityContextImpl [Authentication=TestAuthenticationToken [Principal=ApiUser [Username=USERNAME, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[placeholder]], Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[]]]
[main] DEBUG org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorized filter invocation [POST /v1/api_path] with attributes [authenticated]
[main] DEBUG org.springframework.security.web.FilterChainProxy - Secured POST /v1/api_path
[main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - POST "/v1/api”_path, parameters={}
[main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.Controller#ControllerMethod(String, List)
Here's the code changes made to the SecurityConfig
NEW CODE
/**
* Configure in memory authentication with the default username/password.
* #return InMemoryUserDetailsManager {#link InMemoryUserDetailsManager}
*/
#Bean
public InMemoryUserDetailsManager configureAuthentication() {
final UserDetails userDetails = new User(DEFAULT_USERNAME, DEFAULT_PASSWORD, authorities(DEFAULT_ROLES));
return new InMemoryUserDetailsManager(userDetails);
}
/**
* Security Filter chain for Http requests.
* #param http HttpSecurity
* #return SecurityFilterChain for Http requests
*/
#Bean
public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception {
http.authorizeRequests(auth ->
auth.anyRequest().authenticated())
.httpBasic()
.and()
.csrf().disable();
return http.build();
}
/**
* Set the default ignore everything on the security context.
* #return WebSecurityCustomizer - used to customize WebSecurity
*/
#Bean
public WebSecurityCustomizer ignoringCustomizer() {
return web -> web.ignoring().antMatchers("/**");
}
OLD CODE
#Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(DEFAULT_USERNAME)
.password(DEFAULT_PASSWORD)
.roles(DEFAULT_ROLES.toArray(new String[0]));
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
/**
* Set the default ignore everything on the security context.
*
* #param web {#link WebSecurity}.
*/
protected static void setIgnoreEverything(final WebSecurity web) {
web.ignoring().antMatchers("/**");
}
Realized in debugging that in the legacy code there were duplicate security filter chains but the order of their execution had been flipped and so the securityfilterchain with antpatter /** was being executed first and hence bypassing the securityContextpersistencefilter.
Solution was to remove the /** antpattern since it wasnt serving any purpose.

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

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

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

CustomAuthenticationProvider doesn't get called spring-security 5.2

I have converted an app to use spring and spring security I am using version 5.2. When I try and login my CustomAuthProvider doesn't get called. It does hit the security endpoint 'login' in the jsp and has an anonymous role. Below are the relevant configs.
#ComponentScan(basePackages = {"com.example"})
#Import({com.example.Configuration.class, WebSecurityConfig.class})
public class AppConfig {
servletContext.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/mvc/*");
Register the DelegatingFilterProxy
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
The WebSecurity class
#Configuration
#EnableWebSecurity(debug = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider)
.userDetailsService(new UserDetails());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().
authorizeRequests(a ->
a.antMatchers(
"/resources/js/**",
"/resources/scripts/**",
"/login",
"/resources/styles/**",
"/resources/images/**",
"/resources/loginPage.jsp",
"/resources/forgotUserName.jsp",
"/resources/forgotPassword.jsp",
"/mvc/jsonInitialResponse/**")
.permitAll()
.antMatchers(
"/resources/resetPassword.jsp",
"/mvc/jsonResponse/**",
"/mvc/download/**",
"/resources/**"
).authenticated())
.formLogin()
.loginPage("/resources/loginPage.jsp")
.successHandler(new CustomeAuthenticationSuccessHandler())
.failureUrl("/resources/loginPage.jsp?error=true")
.and().anonymous()
.and()
.logout()
.logoutSuccessUrl("/resources/loginPage.jsp")
.permitAll()
.and()
.csrf().disable().cors().disable();
}
}
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(final Authentication authentication) {......}
#Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
Any thoughts on what I may be missing? The CustomAuthenticationProvider isn't being called and either is the supports() method.
2020-10-06 12:26:29 DEBUG DefaultSavedRequest:359 - pathInfo: both null (property equals)
2020-10-06 12:26:29 DEBUG DefaultSavedRequest:359 - queryString: both null (property equals)
2020-10-06 12:26:29 DEBUG DefaultSavedRequest:383 - requestURI: arg1=/reinsurance-service-ui-war/resources/login; arg2=/reinsurance-service-ui-war/resources/images/icn-lock.png (property not equals)
2020-10-06 12:26:29 DEBUG HttpSessionRequestCache:95 - saved request doesn't match
2020-10-06 12:26:29 DEBUG FilterChainProxy:328 - /resources/images/icn-lock.png at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-10-06 12:26:29 DEBUG FilterChainProxy:328 - /resources/images/icn-lock.png at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2020-10-06 12:26:29 DEBUG AnonymousAuthenticationFilter:100 - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#418e8a7d: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#fffbcba8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 4503EBEA550D56CD4AF5506BC88E7576; Granted Authorities: ROLE_ANONYMOUS'
2020-10-06 12:26:29 DEBUG FilterChainProxy:328 - /resources/images/icn-lock.png at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-10-06 12:26:29 DEBUG FilterChainProxy:328 - /resources/images/icn-lock.png at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-10-06 12:26:29 DEBUG FilterChainProxy:328 - /resources/images/icn-lock.png at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-10-06 12:26:29 DEBUG AntPathRequestMatcher:177 - Checking match of request : '/resources/images/icn-lock.png'; against '/resources/js/**'
2020-10-06 12:26:29 DEBUG AntPathRequestMatcher:177 - Checking match of request : '/resources/images/icn-lock.png'; against '/resources/scripts/**'
2020-10-06 12:26:29 DEBUG AntPathRequestMatcher:177 - Checking match of request : '/resources/images/icn-lock.png'; against '/resources/styles/**'
2020-10-06 12:26:29 DEBUG AntPathRequestMatcher:177 - Checking match of request : '/resources/images/icn-lock.png'; against '/resources/images/**'
2020-10-06 12:26:29 DEBUG FilterSecurityInterceptor:219 - Secure object: FilterInvocation: URL: /resources/images/icn-lock.png; Attributes: [anonymous]
2020-10-06 12:26:29 DEBUG FilterChainProxy:313 - /resources/images/icn-pencil.png reached end of additional filter chain; proceeding with original chain
2020-10-06 12:26:29 DEBUG FilterSecurityInterceptor:348 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#418e8a7d: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#fffbcba8: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 4503EBEA550D56CD4AF5506BC88E7576; Granted Authorities: ROLE_ANONYMOUS
2020-10-06 12:26:29 DEBUG HstsHeaderWriter:169 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#51ca55f0
2020-10-06 12:26:29 DEBUG HttpSessionSecurityContextRepository:351 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-10-06 12:26:29 DEBUG ExceptionTranslationFilter:120 - Chain processed normally
2020-10-06 12:26:29 DEBUG SecurityContextPersistenceFilter:119 - SecurityContextHolder now cleared, as request processing completed
2020-10-06 12:26:29 DEBUG AffirmativeBased:66 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#3fe8aa9d, returned: 1
2020-10-06 12:26:29 DEBUG FilterSecurityInterceptor:243 - Authorization successful
2020-10-06 12:26:29 DEBUG FilterSecurityInterceptor:256 - RunAsManager did not change Authentication object
2020-10-06 12:26:29 DEBUG FilterChainProxy:313 - /resources/images/icn-lock.png reached end of additional filter chain; proceeding with original chain
2020-10-06 12:26:29 DEBUG HstsHeaderWriter:169 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#51ca55f0
2020-10-06 12:26:29 DEBUG HttpSessionSecurityContextRepository:351 - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-10-06 12:26:29 DEBUG ExceptionTranslationFilter:120 - Chain processed normally
2020-10-06 12:26:29 DEBUG SecurityContextPersistenceFilter:119 - SecurityContextHolder now cleared, as request processing completed```

Resources