title: Spring Boot. HMAC authentication. How to add custom AuthenticationProvider and Authentication filter?
body: <p>To implement HMAC authentication I made my own filter, provider and token.
  RestSecurityFilter:</p>
  
  <pre><code>public class RestSecurityFilter extends AbstractAuthenticationProcessingFilter {
  private final Logger LOG = LoggerFactory.getLogger(RestSecurityFilter.class);
  
  private AuthenticationManager authenticationManager;
  
  public RestSecurityFilter(String defaultFilterProcessesUrl) {
      super(defaultFilterProcessesUrl);
  }
  
  public RestSecurityFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
      super(requiresAuthenticationRequestMatcher);
  }
  
  @Override
  public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
      AuthenticationRequestWrapper request = new AuthenticationRequestWrapper(req);
  
      // Get authorization headers
      String signature = request.getHeader("Signature");
      String principal = request.getHeader("API-Key");
      String timestamp = request.getHeader("timestamp");
      if ((signature == null) || (principal == null) || (timestamp == null))
      unsuccessfulAuthentication(request, response, new BadHMACAuthRequestException("Authentication attempt failed! Request missing mandatory headers."));
  
  
      // a rest credential is composed by request data to sign and the signature
      RestCredentials credentials = new RestCredentials(HMACUtils.calculateContentToSign(request), signature);
  
      // Create an authentication token
      return new RestToken(principal, credentials, Long.parseLong(timestamp));
  }
  
  @Override
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
      LOG.debug("Filter request: " + req.toString());
      HttpServletRequest request = (HttpServletRequest) req;
      HttpServletResponse response = (HttpServletResponse) res;
  
      chain.doFilter(request, response);
  
      Authentication authResult;
  
      try {
          authResult = attemptAuthentication(request, response);
          if (authResult == null)
              unsuccessfulAuthentication(request, response, new BadHMACAuthRequestException("Authentication attempt failed !"));
  
      } catch (InternalAuthenticationServiceException failed) {
          LOG.error("An internal error occurred while trying to authenticate the user.", failed);
          unsuccessfulAuthentication(request, response, failed);
      } catch (AuthenticationException failed) {
          // Authentication failed
          unsuccessfulAuthentication(request, response, failed);
      }
  }
  }
  </code></pre>
  
  <p>Authentication provider:</p>
  
  <pre><code>@Component
  public class RestAuthenticationProvider implements AuthenticationProvider {
  private final Logger LOG = LoggerFactory.getLogger(RestAuthenticationProvider.class);
  
  private ApiKeysService apiKeysService;
  
  @Autowired
  public void setApiKeysService(ApiKeysService apiKeysService) {
      this.apiKeysService = apiKeysService;
  }
  
  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
      RestToken restToken = (RestToken) authentication;
  
      // api key (aka username)
      String principal = restToken.getPrincipal();
  
      LOG.info("Authenticating api key: '" + principal + "'");
  
      // check request time, 60000 is one minute
      long interval = Clock.systemUTC().millis() - restToken.getTimestamp();
      if ((interval &lt; 0) &amp;&amp; (interval &gt; 60000))
          throw new BadHMACAuthRequestException("Auth Failed: old request.");
  
      // hashed blob
      RestCredentials credentials = restToken.getCredentials();
  
      // get secret access key from api key
      ApiKey apiKey = apiKeysService.getKeyByName(principal).orElseThrow(() -&gt; new NotFoundException("Key not found for: '" + principal + "'"));
      String secret = apiKey.getApiKey();
  
      // calculate the hmac of content with secret key
      String hmac = HMACUtils.calculateHMAC(secret, credentials.getRequestData());
      LOG.debug("Api Key '{}', calculated hmac '{}'");
  
      // check if signatures match
      if (!credentials.getSignature().equals(hmac)) {
          throw new BadHMACAuthRequestException("Auth Failed: invalid HMAC signature.");
      }
  
      return new RestToken(principal, credentials, restToken.getTimestamp(), apiKeysService.getPermissions(apiKey));
  }
  
  @Override
  public boolean supports(Class&lt;?&gt; authentication) {
      return RestToken.class.equals(authentication);
  
  }
  }
  </code></pre>
  
  <p>I don't know how to configure WebSecurityConfig to authenticate every request with my filter and Authentication Provider. I assume I need to create @Bean to initialize <code>RestSecurityFilter</code>. Also JavaDoc for <code>AbstractAuthenticationProcessingFilter</code> says I need to the <code>authenticationManager</code> property. I would appreciate working solution with custom filter, provider and token. </p>