package com.github.kpavlov.restws.server.hmac; import com.github.kpavlov.restws.commons.HmacSignatureBuilder; import org.springframework.beans.factory.annotation.Required; import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class HmacAuthenticationFilter extends OncePerRequestFilter { private UserDetailsService userDetailsService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { final AuthHeader authHeader = HmacUtil.getAuthHeader(request); if (authHeader == null) { // invalid authorization token logger.warn("Authorization header is missing"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return; } final String username = authHeader.getApiKey(); UserDetails userDetails = userDetailsService.loadUserByUsername(username); assert (userDetails != null); CachingRequestWrapper requestWrapper = new CachingRequestWrapper(request); final byte[] contentAsByteArray = requestWrapper.getContentAsByteArray(); final HmacSignatureBuilder signatureBuilder = new HmacSignatureBuilder() .algorithm(authHeader.getAlgorithm()) .scheme(request.getScheme()) .host(request.getServerName() + ":" + request.getServerPort()) .method(request.getMethod()) .resource(request.getRequestURI()) .contentType(request.getContentType()) .date(request.getHeader(HttpHeaders.DATE)) .nonce(authHeader.getNonce()) .apiKey(username) .apiSecret(userDetails.getPassword()) .payload(contentAsByteArray); if (!signatureBuilder.isHashEquals(authHeader.getDigest())) { throw new BadCredentialsException("HmacAccessFilter.badSignature"); } final PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken( userDetails.getUsername(), null, userDetails.getAuthorities()); authentication.setDetails(userDetails); SecurityContextHolder.getContext().setAuthentication(authentication); try { filterChain.doFilter(requestWrapper, response); } finally { SecurityContextHolder.clearContext(); } } @Required public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } }