Overriding default entry point in ServerHttpSecurity - spring

I use the following ServerHttpSecurity chain:
#Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
http
// ..filters
.authorizeExchange().anyExchange()
.access(CustomHaveAnyAuthority())
// authentication
.and()
.httpBasic()
.and()
.oauth2ResourceServer().jwt()
.authenticationManager(CustomAuthenticationService())
return http.build()
}
However in newer Spring Security 5.5.0 (upgrade from 5.3.3.RELEASE) there is a fallback upon requesting endpoints without auth to BearerTokenServerAuthenticationEntryPoint instead of HttpBasicServerAuthenticationEntryPoint.
How can I override this behaviour? I tried to resort methods above, but didn't work.
Logs from application:
2021-06-02 11:50:43,206 [boundedElastic-1] DEBUG o.s.s.w.s.a.DelegatingReactiveAuthorizationManager - Checking authorization on '/endpoint' using org.springframework.security.authorization.AuthorityReactiveAuthorizationManager#73302f30
2021-06-02 11:50:43,216 [boundedElastic-1] DEBUG o.s.s.w.s.authorization.AuthorizationWebFilter - Authorization failed: Access Denied
2021-06-02 11:50:43,220 [boundedElastic-1] DEBUG o.s.s.w.s.c.WebSessionServerSecurityContextRepository - No SecurityContext found in WebSession: 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession#921515f'
2021-06-02 11:50:43,221 [boundedElastic-1] DEBUG o.s.s.w.s.DelegatingServerAuthenticationEntryPoint - Trying to match using OrServerWebExchangeMatcher{matchers=[org.springframework.security.config.web.server.ServerHttpSecurity$HttpBasicSpec$$Lambda$1073/0x0000000100b00040#73874030, AndServerWebExchangeMatcher{matchers=[NegatedServerWebExchangeMatcher{matcher=MediaTypeRequestMatcher [matchingMediaTypes=[text/html], useEquals=false, ignoredMediaTypes=[]]}, MediaTypeRequestMatcher [matchingMediaTypes=[application/atom+xml, application/x-www-form-urlencoded, application/json, application/octet-stream, application/xml, multipart/form-data, text/xml], useEquals=false, ignoredMediaTypes=[*/*]]]}]}
2021-06-02 11:50:43,221 [boundedElastic-1] DEBUG o.s.s.w.s.util.matcher.OrServerWebExchangeMatcher - Trying to match using org.springframework.security.config.web.server.ServerHttpSecurity$HttpBasicSpec$$Lambda$1073/0x0000000100b00040#73874030
2021-06-02 11:50:43,222 [boundedElastic-1] DEBUG o.s.s.w.s.util.matcher.OrServerWebExchangeMatcher - Trying to match using AndServerWebExchangeMatcher{matchers=[NegatedServerWebExchangeMatcher{matcher=MediaTypeRequestMatcher [matchingMediaTypes=[text/html], useEquals=false, ignoredMediaTypes=[]]}, MediaTypeRequestMatcher [matchingMediaTypes=[application/atom+xml, application/x-www-form-urlencoded, application/json, application/octet-stream, application/xml, multipart/form-data, text/xml], useEquals=false, ignoredMediaTypes=[*/*]]]}
2021-06-02 11:50:43,227 [boundedElastic-1] DEBUG o.s.s.w.s.util.matcher.AndServerWebExchangeMatcher - Trying to match using NegatedServerWebExchangeMatcher{matcher=MediaTypeRequestMatcher [matchingMediaTypes=[text/html], useEquals=false, ignoredMediaTypes=[]]}
2021-06-02 11:50:43,227 [boundedElastic-1] DEBUG o.s.s.w.s.u.m.MediaTypeServerWebExchangeMatcher - httpRequestMediaTypes=[text/html, application/xhtml+xml, image/avif, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8]
2021-06-02 11:50:43,227 [boundedElastic-1] DEBUG o.s.s.w.s.u.m.MediaTypeServerWebExchangeMatcher - Processing text/html
2021-06-02 11:50:43,227 [boundedElastic-1] DEBUG o.s.s.w.s.u.m.MediaTypeServerWebExchangeMatcher - text/html .isCompatibleWith text/html = true
2021-06-02 11:50:43,228 [boundedElastic-1] DEBUG o.s.s.w.s.u.m.NegatedServerWebExchangeMatcher - matches = false
2021-06-02 11:50:43,228 [boundedElastic-1] DEBUG o.s.s.w.s.util.matcher.AndServerWebExchangeMatcher - Did not match
2021-06-02 11:50:43,228 [boundedElastic-1] DEBUG o.s.s.w.s.util.matcher.OrServerWebExchangeMatcher - No matches found
2021-06-02 11:50:43,229 [boundedElastic-1] DEBUG o.s.s.w.s.DelegatingServerAuthenticationEntryPoint - Trying to match using org.springframework.security.web.server.authentication.AuthenticationConverterServerWebExchangeMatcher#21307a04
2021-06-02 11:50:43,229 [boundedElastic-1] DEBUG o.s.s.w.s.DelegatingServerAuthenticationEntryPoint - No match found. Using default entry point org.springframework.security.oauth2.server.resource.web.server.BearerTokenServerAuthenticationEntryPoint#24d2ea8a
Thanks

You can define your own way to handle the exceptions, like this:
#Bean
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
http
.authorizeExchange().anyExchange()
.access(CustomHaveAnyAuthority())
.and()
.httpBasic()
.and()
.oauth2ResourceServer().jwt()
.authenticationManager(CustomAuthenticationService())
.exceptionHandling()
.authenticationEntryPoint(HttpBasicServerAuthenticationEntryPoint())
return http.build()
}

Related

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

Why does Spring Security reject my Keycloak auth token with "No AuthenticationProvider found"?

I'm trying to figure out why my Spring Boot application is rejecting my Keycloak JWT bearer token with a "No AuthenticationProvider found" error message.
I have a few services running in a docker compose environment:
ui (angular) -> proxy (nginx) -> rest api (spring boot) -> auth service (keycloak)
The angular ui pulls the correct keycloak client from the rest service, and then authenticates without issue. I get back a JWT token, and then turn around and hand that to follow on requests to the rest api in a header Authorization: bearer [token].
In the rest API, I can see the correct bearer token come in as a header:
2022-02-11 01:01:31.411 DEBUG 13 --- [nio-8080-exec-4] o.a.coyote.http11.Http11InputBuffer : Received [GET /api/v3/accounts HTTP/1.0
X-Real-IP: 192.168.80.1
X-Forwarded-For: 192.168.80.1
Host: rest-api.mylocal.com
Connection: close
Accept: application/json, text/plain, */*
Authorization: Bearer eyJhbGciO...
...
2022-02-11 01:01:31.421 DEBUG 13 --- [nio-8080-exec-4] o.k.adapters.PreAuthActionsHandler : adminRequest http://rest-api.mylocal.com/api/v3/accounts
...
So the bearer token is there, and with https://jwt.io/ I can verify it's what I would expect:
{
"exp": 1644515847,
...
"iss": "http://auth-service.mylocal.com/auth/realms/LocalTestRealm",
...
"typ": "Bearer",
"azp": "LocalTestClient",
...
"allowed-origins": [
"http://web-ui.mylocal.com"
],
"realm_access": {
"roles": [
"offline_access",
"default-roles-localtestrealm",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid email profile",
...
}
Processing continues by the rest api - it contacts the keycloak service and pulls the well known config:
...
2022-02-11 01:01:33.321 INFO 13 --- [nio-8080-exec-4] o.keycloak.adapters.KeycloakDeployment : Loaded URLs from http://auth-service.mylocal.com/auth/realms/LocalTestRealm/.well-known/openid-configuration
...
Finally it looks like it successfully parses the bearer token apart, grabs the user and authenticates them:
2022-02-11 01:01:33.521 DEBUG 13 --- [nio-8080-exec-4] o.a.h.impl.conn.tsccm.ConnPoolByRoute : Releasing connection [{}->http://auth-service.mylocal.com:80][null]
2022-02-11 01:01:33.521 DEBUG 13 --- [nio-8080-exec-4] o.a.h.impl.conn.tsccm.ConnPoolByRoute : Pooling connection [{}->http://auth-service.mylocal.com:80][null]; keep alive indefinitely
2022-02-11 01:01:33.521 DEBUG 13 --- [nio-8080-exec-4] o.a.h.impl.conn.tsccm.ConnPoolByRoute : Notifying no-one, there are no waiting threads
2022-02-11 01:01:33.530 DEBUG 13 --- [nio-8080-exec-4] o.k.a.rotation.JWKPublicKeyLocator : Realm public keys successfully retrieved for client LocalTestClient. New kids: [8a7dIQFASdC8BHa0mUWwZX7RBBJSeJItdmzah0Ybpcw]
2022-02-11 01:01:33.546 DEBUG 13 --- [nio-8080-exec-4] o.k.a.BearerTokenRequestAuthenticator : successful authorized
2022-02-11 01:01:33.550 TRACE 13 --- [nio-8080-exec-4] o.k.a.RefreshableKeycloakSecurityContext : checking whether to refresh.
2022-02-11 01:01:33.550 TRACE 13 --- [nio-8080-exec-4] org.keycloak.adapters.AdapterUtils : useResourceRoleMappings
2022-02-11 01:01:33.550 TRACE 13 --- [nio-8080-exec-4] org.keycloak.adapters.AdapterUtils : Setting roles:
2022-02-11 01:01:33.555 DEBUG 13 --- [nio-8080-exec-4] a.s.a.SpringSecurityRequestAuthenticator : Completing bearer authentication. Bearer roles: []
2022-02-11 01:01:33.556 DEBUG 13 --- [nio-8080-exec-4] o.k.adapters.RequestAuthenticator : User 'bf7307ca-9352-4a02-b288-0565e2b57292' invoking 'http://rest-api.mylocal.com/api/v3/accounts' on client 'LocalTestClient'
2022-02-11 01:01:33.556 DEBUG 13 --- [nio-8080-exec-4] o.k.adapters.RequestAuthenticator : Bearer AUTHENTICATED
2022-02-11 01:01:33.556 DEBUG 13 --- [nio-8080-exec-4] f.KeycloakAuthenticationProcessingFilter : Auth outcome: AUTHENTICATED
and then immediately after that fails with the No AuthenticationProvider found error:
2022-02-11 01:01:33.559 TRACE 13 --- [nio-8080-exec-4] f.KeycloakAuthenticationProcessingFilter : Failed to process authentication request
org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:234) ~[spring-security-core-5.5.1.jar!/:5.5.1]
I'm at a loss how it can say Bearer AUTHENTICATED followed by Auth outcome: AUTHENTICATED followed by No AuthenticationProvider found... I'm assuming it somehow can't convert this bearer token into a Keycloak token, even though it definitely came from my Keycloak server.
My app config:
#ComponentScan({"com.mycompany"})
#Configuration
#EnableJpaRepositories(basePackages = "com.mycompany")
#EntityScan("com.mycompany")
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class ApplicationConfiguration
extends KeycloakWebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
// These paths (comma separated) are allowed to all
.antMatchers("/api/v3/auth/config").permitAll()
.and()
.authorizeRequests()
// Everything else should be authenticated
.anyRequest().authenticated()
.and()
.csrf().disable();
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
#Bean
public KeycloakConfigResolver keycloakConfigResolver() {
// This just pulls the Keycloak config from a DB instead of the config file
return new CustomKeycloakConfigResolver();
// return new KeycloakSpringBootConfigResolver();
}
}
Missing the global config to autowire in a Keycloak auth provider:
#Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth)
throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider =
keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
new SimpleAuthorityMapper()
);
auth.authenticationProvider(keycloakAuthenticationProvider);
}

How to resolve 403 on spring security JWT authentication for public resources

I'm trying to implement a JWT based authentication using spring security in a spring boot API, but I don't know what I'm doing wrong. On my implementation of WebSecurityConfigurerAdapter I permit access to auth/** resource, but when I make a request to, for example, /auth/login, I get a 403. It seems that it is ignoring the "public" resources.
The csrf() is disabled.
This is the repository: https://github.com/wallysoncarvalho/jwt-auth-spring-security
I enabled DEBUG mode and that's what I get:
Request received for POST '/auth/login?username=wally&password=wally':
org.apache.catalina.connector.RequestFacade#585d8cc6
servletPath:/auth/login
pathInfo:null
headers:
user-agent: PostmanRuntime/7.26.8
accept: */*
postman-token: 91c2a071-a353-4d77-9c7c-b04a43b94081
host: localhost:8091
accept-encoding: gzip, deflate, br
connection: keep-alive
content-length: 0
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
JwtFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2020-12-22 20:21:15.919 DEBUG 6288 --- [nio-8091-exec-2] o.s.security.web.FilterChainProxy : Securing POST /auth/login?username=wally&password=wally
2020-12-22 20:21:15.937 DEBUG 6288 --- [nio-8091-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2020-12-22 20:21:15.948 DEBUG 6288 --- [nio-8091-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2020-12-22 20:21:15.960 INFO 6288 --- [nio-8091-exec-2] Spring Security Debugger :
************************************************************
Request received for POST '/error?username=wally&password=wally':
org.apache.catalina.core.ApplicationHttpRequest#6d88bc8c
servletPath:/error
pathInfo:null
headers:
user-agent: PostmanRuntime/7.26.8
accept: */*
postman-token: 91c2a071-a353-4d77-9c7c-b04a43b94081
host: localhost:8091
accept-encoding: gzip, deflate, br
connection: keep-alive
content-length: 0
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
JwtFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2020-12-22 20:21:15.961 DEBUG 6288 --- [nio-8091-exec-2] o.s.security.web.FilterChainProxy : Securing POST /error?username=wally&password=wally
2020-12-22 20:21:15.961 DEBUG 6288 --- [nio-8091-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2020-12-22 20:21:15.967 DEBUG 6288 --- [nio-8091-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2020-12-22 20:21:15.998 DEBUG 6288 --- [nio-8091-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [POST /error?username=wally&password=wally] with attributes [authenticated]
2020-12-22 20:21:16.022 DEBUG 6288 --- [nio-8091-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2020-12-22 20:21:16.025 DEBUG 6288 --- [nio-8091-exec-2] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/assets/**",);
}
And your #Configuration class must implements WebMvcConfigurer
Edit
Also enable WebSecurity in your config class by annotating it with #EnableWebSecurity

spring boot redirects to local url

I'm using spring-boot with spring-security.
override fun configure(http: HttpSecurity) {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
}
The problem I have is that when I use:
https://my-domain.com/testPath
instead of redirecting me to https://my-domain.com/login it redirects to
http://10.100.15.40:8541/ (this is its internal IP and port)
here some logs:
2019-06-27 08:20:31.031 DEBUG 7 --- [nio-8541-exec-1] o.s.s.w.s.HttpSessionRequestCache : DefaultSavedRequest added to Session: DefaultSavedRequest[http://10.100.15.40:8541/testPath]
2019-06-27 08:20:31.040 DEBUG 7 --- [nio-8541-exec-1] o.s.s.web.DefaultRedirectStrategy : Redirecting to 'http://10.100.15.40:8541/login'
2019-06-27 08:23:50.634 DEBUG 7 --- [nio-8541-exec-2] o.s.s.w.s.DefaultSavedRequest : requestURL: arg1=http://10.100.15.40:8541/testPath; arg2=http://10.100.15.40:8541/testPath (property equals)
2019-06-27 08:23:50.634 DEBUG 7 --- [nio-8541-exec-2] o.s.s.w.s.DefaultSavedRequest : serverName: arg1=10.100.15.40; arg2=10.100.15.40 (property equals)
Any one has an idea where can I configure it not to use the internal ip?
I found what the problem is. The problem is that the spring application is behind a proxy. And the proxy server did not sent the header X-Forwarded-For.
To solve it, I needed to configure the proxy server properly.

Spring security login error page, access denied

When I login into my oauth2 protected form with invalid credentials, the redirect to the default login error page 'login?error' does not work. In my logs I can see:
2018-02-01 10:58:35.935 DEBUG 17600 --- [http-nio-8899-exec-8] w.a.UsernamePasswordAuthenticationFilter : Updated SecurityContextHolder to contain null Authentication
2018-02-01 10:58:35.935 DEBUG 17600 --- [http-nio-8899-exec-8] w.a.UsernamePasswordAuthenticationFilter : Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler#49d1bcfd
2018-02-01 10:58:35.935 DEBUG 17600 --- [http-nio-8899-exec-8] .a.SimpleUrlAuthenticationFailureHandler : Redirecting to /login?error
2018-02-01 10:58:35.935 DEBUG 17600 --- [http-nio-8899-exec-8] o.s.s.web.DefaultRedirectStrategy : Redirecting to '/uaa/login?error'
But after the redirect there is an 'Access denied' exception:
2018-02-01 10:58:35.943 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /login?error=; Attributes: [authenticated]
2018-02-01 10:58:35.943 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#6fa90ed4: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#fffc7f0c: RemoteIpAddress: 127.0.0.1; SessionId: 03550F34462ABD6D42B5E224A4C478F9; Granted Authorities: ROLE_ANONYMOUS
2018-02-01 10:58:35.943 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter#337e3785, returned: -1
2018-02-01 10:58:35.943 DEBUG 17600 --- [http-nio-8899-exec-10] 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
Followed by a redirect to the login page again '/login'
2018-02-01 10:58:35.943 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.util.matcher.AndRequestMatcher : Trying to match using Ant [pattern='/**', GET]
2018-02-01 10:58:35.943 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Request '/login' matched by universal pattern '/**'
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.util.matcher.AndRequestMatcher : Trying to match using NegatedRequestMatcher [requestMatcher=Ant [pattern='/**/favicon.ico']]
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/login'; against '/**/favicon.ico'
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.matcher.NegatedRequestMatcher : matches = true
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.util.matcher.AndRequestMatcher : Trying to match using NegatedRequestMatcher [requestMatcher=MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager#27122376, matchingMediaTypes=[application/json], useEquals=false, ignoredMediaTypes=[*/*]]]
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : httpRequestMediaTypes=[text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, */*;q=0.8]
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : Processing text/html
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : application/json .isCompatibleWith text/html = false
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : Processing application/xhtml+xml
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : application/json .isCompatibleWith application/xhtml+xml = false
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : Processing image/webp
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : application/json .isCompatibleWith image/webp = false
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : Processing image/apng
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : application/json .isCompatibleWith image/apng = false
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : Processing application/xml;q=0.9
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : application/json .isCompatibleWith application/xml;q=0.9 = false
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : Processing */*;q=0.8
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : Ignoring
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.m.MediaTypeRequestMatcher : Did not match any media types
2018-02-01 10:58:35.944 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.matcher.NegatedRequestMatcher : matches = true
2018-02-01 10:58:35.948 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.util.matcher.AndRequestMatcher : Trying to match using NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]]
2018-02-01 10:58:35.948 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.u.matcher.NegatedRequestMatcher : matches = true
2018-02-01 10:58:35.948 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.util.matcher.AndRequestMatcher : All requestMatchers returned true
2018-02-01 10:58:35.948 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.s.HttpSessionRequestCache : DefaultSavedRequest added to Session: DefaultSavedRequest[http://localhost:8765/uaa/login?error=]
2018-02-01 10:58:35.948 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.w.a.ExceptionTranslationFilter : Calling Authentication entry point.
2018-02-01 10:58:35.948 DEBUG 17600 --- [http-nio-8899-exec-10] o.s.s.web.DefaultRedirectStrategy : Redirecting to 'http://localhost:8765/uaa/login'
Does someone have an idea whats going wrong?
Edit: Add security configuration
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#Order(-20)
protected static class LoginConfig extends WebSecurityConfigurerAdapter {
...
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**", "/images/**", "/fonts/**", "/health", "/info");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/console/**", "/reset").permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.requestMatchers()
.antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access", "/reset")
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
// #formatter:on
}
}
Another edit: When I access the oauth2 server directly without going trough Zuul, the redirect to the login error page 'login?error' page works.
Zuul's security configuration is
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.logout()
.permitAll()
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))
.and()
.authorizeRequests()
.antMatchers("/uaa/**", "/login", "/xxx/view3/**", "/*/view404", "/*/view403").permitAll()
.and()
.authorizeRequests()
.antMatchers("/xxx/**/*").hasAnyRole("USER", "ADMIN")
.antMatchers("/yyy/**/*").hasRole("ADMIN")
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.csrf().requireCsrfProtectionMatcher(csrfRequestMatcher()).csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler());
// #formatter:on
}
Edit: Added trace of requests
HAR-Export from Chrome DEV-Tools: Just share it
Just paste it in here to visualize: HAR viewer
The solution is to add
.antMatchers("/console/**", "/reset", "/login").permitAll()
to the WebSecurityConfigurerAdapter of the uaa-service. Final working configuration
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/console/**", "/reset", "/login").permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.requestMatchers()
.antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access", "/reset")
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
// #formatter:on
}
If someone could explain why this is necessary, this would be nice.

Resources