Search code examples
springspring-securityhawtiojolokia

Spring Security 4.x JavaConfig for Basic authentication with Hawtio


I'm trying to connect Hawtio (1.4.64) to a Jolokia agent (1.3.3) running in a Spring app in Tomcat 7.

Following a recent upgrade to Spring Security (4.0.3) hawtio stopped authenticating properly (using basic auth) and we get kicked back to the login page, similar to issue #1975 . Unlike in that issue, we are only using the Jolokia agent rather than including hawtio in our application (and we're not using Spring Boot).

After examining the Spring debug logs, it looks as though the AnonymousAuthenticationFilter is setting the user to be "anonymous" before the BasicAuthenticationFilter is applied. So I adjusted the Security configuration and disabled all the defaults, leaving the following:

@Configuration
@Order(2)
public static class JolokiaSecurityConfig extends WebSecurityConfigurerAdapter {

    public JolokiaSecurityConfig() {
        super(true); // disable defaults
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .requestMatchers().antMatchers("/jolokia/**")
            .and().authorizeRequests().antMatchers("/jolokia/**").hasAuthority(BaseRoles.DEVELOPER).and().httpBasic();
    }
}

Now when I log in to Hawtio I get an error in the Hawtio console which includes some output from my Tomcat7 server: HTTP Status 500 - An Authentication object was not found in the SecurityContext

Stacktrace:

Jul 06, 2016 12:43:14 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [jolokia-agent] in context with path [/foobar] threw exception
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:378)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:222)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:123)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)

...

Any ideas why basic authentication is no longer working? Thanks for any help!


Solution

  • We got around the problem by overriding the exception handling to call the BasicAuthenticationEntryPoint again:

    @Configuration
    @Order(2)
    public static class JolokiaSecurityConfig extends WebSecurityConfigurerAdapter {
    
        private static final String REALM = "our admin services";
        private static final String JOLOKIA_URL_PATTERN = "/jolokia/**";
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            BasicAuthenticationEntryPoint authenticationEntryPoint = new BasicAuthenticationEntryPoint();
            authenticationEntryPoint.setRealmName(REALM);
            http
                .csrf().disable()
                .requestMatchers().antMatchers(JOLOKIA_URL_PATTERN)
                .and().authorizeRequests().antMatchers(JOLOKIA_URL_PATTERN).hasAuthority(BaseRoles.DEVELOPER)
                .and().httpBasic().realmName(REALM)
                .and().exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
        }
    }