title: Spring Security custom authentication filter using Java Config
body: <p>I'm trying to configure Spring Security using Java config in a basic web application to authenticate against an external web service using an encrypted token provided in a URL request parameter.</p>
  
  <p>I would like (I think) to have a security filter that intercepts requests from the Login Portal (they all go to /authenticate), the filter will use an AuthenticationProvider to process the bussiness logic of the authentication process.</p>
  
  <p>Login Portal --> Redirect '\authenticate' (+ Token) --> Authenticate Token back to Login Portal (WS) --> If success get roles and setup user.</p>
  
  <p>I have created a filter..</p>
  
  <pre><code>@Component
  public final class OEWebTokenFilter extends GenericFilterBean {
      @Override
      public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
          if (request instanceof HttpServletRequest) {
               OEToken token = extractToken(request);
               // dump token into security context (for authentication-provider to pick up)
               SecurityContextHolder.getContext().setAuthentication(token);
          }
      }   
      chain.doFilter(request, response);
  }
  </code></pre>
  
  <p>An AuthenticationProvider...</p>
  
  <pre><code>@Component
  public final class OEWebTokenAuthenticationProvider implements AuthenticationProvider {
      @Autowired
      private WebTokenService webTokenService;
  
      @Override
      public boolean supports(final Class&lt;?&gt; authentication) {
          return OEWebToken.class.isAssignableFrom(authentication);
      }
  
      @Override
      public Authentication authenticate(final Authentication authentication) {
           if (!(authentication instanceof OEWebToken)) {
               throw new AuthenticationServiceException("expecting a OEWebToken, got " + authentication);
          }
  
          try {
              // validate token locally
              OEWebToken token = (OEWebToken) authentication;
              checkAccessToken(token);
  
              // validate token remotely
              webTokenService.validateToken(token);
  
              // obtain user info from the token
              User userFromToken = webTokenService.obtainUserInfo(token);
  
              // obtain the user from the db
              User userFromDB = userDao.findByUserName(userFromToken.getUsername());
  
              // validate the user status
              checkUserStatus(userFromDB);
  
              // update ncss db with values from OE
              updateUserInDb(userFromToken, userFromDB);
  
              // determine access rights
              List&lt;GrantedAuthority&gt; roles = determineRoles(userFromDB);
  
              // put account into security context (for controllers to use)
              return new AuthenticatedAccount(userFromDB, roles);
          } catch (AuthenticationException e) {
              throw e;
          } catch (Exception e) {
               // stop non-AuthenticationExceptions. otherwise full stacktraces returned to the requester
               throw new AuthenticationServiceException("Internal error occurred");
          }
      }
  </code></pre>
  
  <p>And my Spring Security Config</p>
  
  <pre><code>@Configuration
  @EnableWebSecurity
  @EnableGlobalMethodSecurity(prePostEnabled = true)
  public class SecurityConfig extends WebSecurityConfigurerAdapter {
  
      @Autowired
      OESettings oeSettings;
  
      @Bean(name="oeAuthenticationService")
      public AuthenticationService oeAuthenticationService() throws AuthenticationServiceException {
          return new AuthenticationServiceImpl(new OEAuthenticationServiceImpl(), oeSettings.getAuthenticateUrl(), oeSettings.getApplicationKey());
      }
  
      @Autowired
      private OEWebTokenFilter tokenFilter;
  
      @Autowired
      private OEWebTokenAuthenticationProvider tokenAuthenticationProvider;
  
      @Autowired
      private OEWebTokenEntryPoint tokenEntryPoint;
  
      @Bean(name="authenticationManager")
      @Override
      public AuthenticationManager authenticationManagerBean() throws Exception {
          return super.authenticationManagerBean();
      }
  
      @Override
      public void configure(AuthenticationManagerBuilder auth)  throws Exception {
          auth.authenticationProvider(tokenAuthenticationProvider);
      }
  
      @Bean
      public FilterRegistrationBean filterRegistrationBean () {  
          FilterRegistrationBean registrationBean = new FilterRegistrationBean();     
          registrationBean.setFilter(tokenFilter);    
          registrationBean.setEnabled(false);
          return registrationBean;
      }
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.csrf().disable()
              .authorizeRequests()
              .antMatchers("/authenticate**").permitAll()
              .antMatchers("/resources/**").hasAuthority("ROLE_USER")
              .antMatchers("/home**").hasAuthority("ROLE_USER")
              .antMatchers("/personSearch**").hasAuthority("ROLE_ADMIN")
              // Spring Boot actuator endpoints
              .antMatchers("/autoconfig**").hasAuthority("ROLE_ADMIN")
              .antMatchers("/beans**").hasAuthority("ROLE_ADMIN")
              .antMatchers("/configprops**").hasAuthority("ROLE_ADMIN")
              .antMatchers("/dump**").hasAuthority("ROLE_ADMIN")
              .antMatchers("/env**").hasAuthority("ROLE_ADMIN")
              .antMatchers("/health**").hasAuthority("ROLE_ADMIN")
              .antMatchers("/info**").hasAuthority("ROLE_ADMIN")
              .antMatchers("/mappings**").hasAuthority("ROLE_ADMIN")
              .antMatchers("/metrics**").hasAuthority("ROLE_ADMIN")
              .antMatchers("/trace**").hasAuthority("ROLE_ADMIN")
              .and()
                  .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)
                  .authenticationProvider(tokenAuthenticationProvider)
                  .antMatcher("/authenticate/**")
                  .exceptionHandling().authenticationEntryPoint(tokenEntryPoint)
              .and()
                  .logout().logoutSuccessUrl(oeSettings.getUrl());
      }
  }
  </code></pre>
  
  <p>My problem is the configuration of the filter in my SpringConfig class. I want the filter to only come into effect when the request is for the /authenticate URL, I've added .antMatcher("/authenticate/**") to the filter configuration. </p>
  
  <pre><code>.and()
                  .addFilterBefore(tokenFilter, UsernamePasswordAuthenticationFilter.class)
                  .authenticationProvider(tokenAuthenticationProvider)
                  .antMatcher("/authenticate/**")
                  .exceptionHandling().authenticationEntryPoint(tokenEntryPoint)
  </code></pre>
  
  <p>When I have this line in all other URLs are no longer secured, I can manually navigate to /home without authenticating, remove the line and /home is authenticated.</p>
  
  <p>Should I be declaring a filter that is only applicable to a specific URL?</p>
  
  <p>How can I implement this whilst maintaining the security of other URLs?</p>