@Override
 public void aroundWriteTo(WriterInterceptorContext responseCtx)
     throws IOException, WebApplicationException {
   RequestDetails requestDetails = (RequestDetails) responseCtx.getProperty(TMP_REQDETAILS);
   if (requestDetails.principal != null) {
     ByteArrayOutputStream content = new ByteArrayOutputStream();
     OutputStream oldStream = responseCtx.getOutputStream();
     responseCtx.setOutputStream(content);
     responseCtx.proceed();
     byte[] contentData = content.toByteArray();
     RESTResponseSigner responseSigner =
         new RESTResponseSigner(
             requestDetails.nonce,
             requestDetails.signature,
             requestDetails.statusCode,
             contentData);
     try {
       responseCtx
           .getHeaders()
           .add(
               RESTRequestSigner.HEADER_SIGNATURE,
               signResponse(requestDetails.principal, responseSigner.getDataToSign()));
     } catch (InvalidKeyException e) {
       logServerError(
           "Invalid key for identity " + requestDetails.identity + " : " + e.getMessage(),
           e,
           null);
       throw new WebApplicationException(INTERNAL_SERVER_ERROR);
     } catch (BackendAccessException e) {
       logServerError("Unexpected BackendAccessException" + e.getMessage(), e, null);
       throw new WebApplicationException(INTERNAL_SERVER_ERROR);
     }
     oldStream.write(contentData);
   }
 }
 @Override
 public void filter(ContainerRequestContext requestContext) throws IOException {
   String nonce = requestContext.getHeaderString(HEADER_NONCE);
   String identity = requestContext.getHeaderString(HEADER_IDENTITY);
   try {
     if (StringUtils.isNotEmpty(identity)) {
       MDC.put(MDC_IDENTITY, identity);
     }
     String timestampStr = requestContext.getHeaderString(HEADER_TIMESTAMP);
     String signature = requestContext.getHeaderString(HEADER_SIGNATURE);
     if (!ValidationUtils.notEmpty(nonce, identity, timestampStr, signature)) {
       logUnauthorizedAccess(
           "Unauthorized request (missing any of nonce, identify, timestamp, signature)",
           requestContext);
       throw new AccessUnauthorizedException();
     }
     URI requestUri = requestContext.getUriInfo().getRequestUri();
     StringBuilder path = new StringBuilder(requestUri.getPath());
     if (requestUri.getRawQuery() != null) {
       path.append('?').append(requestUri.getRawQuery());
     }
     RESTRequestSigner restRequestSigner =
         new RESTRequestSigner(
             requestContext.getMethod(), path.toString(), nonce, timestampStr, identity);
     ByteArrayOutputStream content = new ByteArrayOutputStream();
     InputStream is = requestContext.getEntityStream();
     IOUtils.copy(
         is,
         contentMaxSize != null
             ? new BoundedOutputStream(content, contentMaxSize, true)
             : content);
     byte[] contentData = content.toByteArray();
     restRequestSigner.setContent(contentData);
     try {
       Date timestamp = TimeUtils.parseISOUTCDateTime(timestampStr);
       if (timestamp.after(new Date(System.currentTimeMillis() + expiry))) {
         String message = "Unauthorized request (expired timestamp): " + timestampStr;
         logUnauthorizedAccess(message, requestContext);
         throw new AccessUnauthorizedException(message);
       }
       if (replayAttackValidator.checkNonceReplay(nonce)) {
         String message = "Unauthorized request (duplicated nonce): " + nonce;
         logUnauthorizedAccess(message, requestContext);
         throw new AccessUnauthorizedException();
       }
       requestContext.setEntityStream(new ByteArrayInputStream(contentData));
       Principal principal = findUserPrincipal(identity);
       if (principal == null) {
         logUnauthorizedAccess(
             "Unauthorized request (principal not found): " + identity, requestContext);
         throw new AccessUnauthorizedException();
       }
       if (!verifySignature(
           principal, restRequestSigner.getDataToSign(), signature, requestContext)) {
         logUnauthorizedAccess(
             "Unauthorized request (invalid signature): " + restRequestSigner.toString(),
             requestContext);
         throw new AccessUnauthorizedException();
       }
       updateAuthenticatedContext(requestContext, principal);
     } catch (ParseException e) {
       logBadRequest("Invalid timestamp: " + timestampStr, e, requestContext);
       throw new WebApplicationException(BAD_REQUEST);
     }
   } finally {
     try {
       MDC.remove(MDC_IDENTITY);
     } catch (IllegalArgumentException e) {
       //
     }
   }
 }