Spring Download. HMAC authentication. How to add my own authentication and authentication filter?

To implement HMAC authentication, I made my own filter, provider and token. RestSecurityFilter:

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); } } } 

Authentication Provider:

 @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 < 0) && (interval > 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(() -> 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<?> authentication) { return RestToken.class.equals(authentication); } } 

I do not know how to configure WebSecurityConfig to authenticate each request with my filter and authentication provider. I assume that I need to create @ Bean to initialize RestSecurityFilter . Also the JavaDoc for AbstractAuthenticationProcessingFilter says that I need the authenticationManager property. I would appreciate working with a custom filter, provider, and token.

+4
java authentication spring-boot spring-security hmac
May 28 '15 at 9:31
source share
1 answer

I am not familiar with Spring Boot, but I saw your comment on my question How to insert AuthenticationManager using Java configuration in user filter

In Springโ€™s traditional XML security configuration, you must specify your custom RestSecurityFilter this way

 <http use-expressions="true" create-session="stateless" authentication-manager-ref="authenticationManager" entry-point-ref="restAuthenticationEntryPoint"> <custom-filter ref="restSecurityFilter" position="FORM_LOGIN_FILTER" /> </http> 

Additional information http://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/#ns-custom-filters

+3
May 29 '15 at 15:06
source share



All Articles