@Override
  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) resp;

    String appId = accessKeyUtil.extractAppIdFromRequest(request);
    if (StringUtils.isBlank(appId)) {
      response.sendError(HttpServletResponse.SC_BAD_REQUEST, "InvalidAppId");
      return;
    }

    List<String> availableSecrets = accessKeyUtil.findAvailableSecret(appId);
    if (!CollectionUtils.isEmpty(availableSecrets)) {
      String timestamp = request.getHeader(Signature.HTTP_HEADER_TIMESTAMP);
      String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);

      // check timestamp, valid within 1 minute
      if (!checkTimestamp(timestamp)) {
        logger.warn("Invalid timestamp. appId={},timestamp={}", appId, timestamp);
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "RequestTimeTooSkewed");
        return;
      }

      // check signature
      String uri = request.getRequestURI();
      String query = request.getQueryString();
      if (!checkAuthorization(authorization, availableSecrets, timestamp, uri, query)) {
        logger.warn("Invalid authorization. appId={},authorization={}", appId, authorization);
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
        return;
      }
    }

    chain.doFilter(request, response);
  }
@Test
  public void testRequestTimeOneMinFasterThenCurrentTime() throws Exception {
    String appId = "someAppId";
    List<String> secrets = Lists.newArrayList("someSecret");
    String oneMinAfterTimestamp = Long.toString(System.currentTimeMillis() + 61 * 1000);

    when(accessKeyUtil.extractAppIdFromRequest(any())).thenReturn(appId);
    when(accessKeyUtil.findAvailableSecret(appId)).thenReturn(secrets);
    when(request.getHeader(Signature.HTTP_HEADER_TIMESTAMP)).thenReturn(oneMinAfterTimestamp);

    clientAuthenticationFilter.doFilter(request, response, filterChain);

    verify(response).sendError(HttpServletResponse.SC_UNAUTHORIZED, "RequestTimeTooSkewed");
    verify(filterChain, never()).doFilter(request, response);
  }