I've got a very weird problem with Spring Security and basic auth. I'd basically like to protect swagger ui with basic auth. Everything works (without auth) until I introduce the following in spring config:
<http pattern="/swagger*/**" xmlns="http://www.springframework.org/schema/security"
authentication-manager-ref="basicAuthenticationManager">
<http-basic />
<intercept-url pattern="/swagger*/**" access="isAuthenticated()" />
</http>
This results in a 404 due to a permission denied, the log shows:
DEBUG [HTTP38] [ExceptionTranslationFilter] Chain processed normally
DEBUG [HTTP22] [AntPathRequestMatcher] Checking match of request : '/swagger-ui.html'; against '/swagger*/**'
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 1 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG [HTTP22] [HttpSessionSecurityContextRepository] No HttpSession currently exists
DEBUG [HTTP22] [HttpSessionSecurityContextRepository] No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 2 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 4 of 11 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG [HTTP22] [HttpSessionRequestCache] saved request doesn't match
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG [HTTP22] [AnonymousAuthenticationFilter] Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@4f862d10: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG [HTTP22] [FilterChainProxy] /swagger-ui.html at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG [HTTP22] [AntPathRequestMatcher] Checking match of request : '/swagger-ui.html'; against '/swagger*/**'
DEBUG [HTTP22] [FilterSecurityInterceptor] Secure object: FilterInvocation: URL: /swagger-ui.html; Attributes: [isAuthenticated()]
DEBUG [HTTP22] [FilterSecurityInterceptor] Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@4f862d10: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
DEBUG [HTTP22] [AffirmativeBased] Voter: org.springframework.security.web.access.expression.WebExpressionVoter@10de9715, returned: -1
DEBUG [HTTP22] [ExceptionTranslationFilter] Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) ~[spring-security-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) [spring-security-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
So it seems the AnonymousAuthFilter sets anonymous which is not allowed due to the access="isAuthenticated()".
So if I add the following:
<http pattern="/swagger*/**" xmlns="http://www.springframework.org/schema/security"
authentication-manager-ref="basicAuthenticationManager">
<http-basic />
<intercept-url pattern="/swagger*/**" access="isAuthenticated()" />
<anonymous enabled="false" />
</http>
It will complain about missing auth object (An Authentication object was not found in the SecurityContext):
DEBUG [HTTP15] [ExceptionTranslationFilter] Chain processed normally
DEBUG [HTTP25] [AntPathRequestMatcher] Checking match of request : '/swagger-ui.html'; against '/swagger*/**'
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 1 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG [HTTP25] [HttpSessionSecurityContextRepository] No HttpSession currently exists
DEBUG [HTTP25] [HttpSessionSecurityContextRepository] No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 2 of 10 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 3 of 10 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 4 of 10 in additional filter chain; firing Filter: 'CsrfFilter'
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 5 of 10 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 6 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG [HTTP25] [HttpSessionRequestCache] saved request doesn't match
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 7 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 8 of 10 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 9 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG [HTTP25] [FilterChainProxy] /swagger-ui.html at position 10 of 10 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG [HTTP25] [AntPathRequestMatcher] Checking match of request : '/swagger-ui.html'; against '/swagger*/**'
DEBUG [HTTP25] [FilterSecurityInterceptor] Secure object: FilterInvocation: URL: /swagger-ui.html; Attributes: [isAuthenticated()]
DEBUG [HTTP25] [ExceptionTranslationFilter] Authentication exception occurred; redirecting to authentication entry point
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:379) ~[spring-security-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:223) ~[spring-security-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]
....
I'd like to point out:
- This is a big enterprise application and there is stuff around it. Web contexts, however, are pretty narrowed down and I really removed almost everything else.
- This used to work. What I changed was the mapping in web.xml. Before it was /v2/* that was mapped to springmvc-servlet, now it is /*.
Any ideas? To me it seems correct and it all looks good in log too - it just never asks for basic auth.
Any input welcome.
Thank you and BR
Dario