import com.google.common.collect.ImmutableSet; import com.google.common.net.HttpHeaders; import com.sun.jersey.api.core.HttpContext; import com.sun.jersey.api.core.HttpRequestContext; import com.sun.jersey.api.model.AbstractResourceMethod; import com.sun.jersey.spi.container.ResourceMethodDispatchAdapter; import com.sun.jersey.spi.container.ResourceMethodDispatchProvider; import com.sun.jersey.spi.dispatch.RequestDispatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.ext.Provider; import java.util.List; import java.util.Map; import java.util.Set; @Provider public class AuditedResourceMethodDispatchAdapter implements ResourceMethodDispatchAdapter { private final static Set REDACTED_HEADERS = ImmutableSet.of(HttpHeaders.AUTHORIZATION); private static class AuditResourceMethodDispatchProvider implements ResourceMethodDispatchProvider { private final ResourceMethodDispatchProvider provider; private AuditResourceMethodDispatchProvider(ResourceMethodDispatchProvider provider) { this.provider = provider; } @Override public RequestDispatcher create(AbstractResourceMethod abstractResourceMethod) { final RequestDispatcher dispatcher = provider.create(abstractResourceMethod); final Audited audited = abstractResourceMethod.getAnnotation(Audited.class); if (audited != null) { return new AuditedRequestDispatcher(dispatcher, audited.requireRemoteIp()); } return dispatcher; } } @Override public ResourceMethodDispatchProvider adapt(ResourceMethodDispatchProvider provider) { return new AuditResourceMethodDispatchProvider(provider); } private static class AuditedRequestDispatcher implements RequestDispatcher { private static Logger logger = LoggerFactory.getLogger(AuditedResourceMethodDispatchAdapter.class); private final RequestDispatcher dispatcher; private final boolean requireRemoteIPAddressInformation; private AuditedRequestDispatcher(RequestDispatcher dispatcher, boolean requireRemoteIPAddressInformation) { this.dispatcher = dispatcher; this.requireRemoteIPAddressInformation = requireRemoteIPAddressInformation; } @Override public void dispatch(Object resource, HttpContext context) { dispatcher.dispatch(resource, context); final HttpRequestContext request = context.getRequest(); final StringBuilder builder = new StringBuilder(); builder.append("\nPROTECTED RESOURCE ACCESS\n"); builder.append(" Resource : " + resource.getClass() + "\n"); if (requireRemoteIPAddressInformation && !request.getRequestHeaders().keySet().contains(HttpHeaders.X_FORWARDED_FOR)) { throw new RuntimeException("Header " + HttpHeaders.X_FORWARDED_FOR + " is required but was not found in the request"); } for (Map.Entry> entry : request.getRequestHeaders().entrySet()) { if (!REDACTED_HEADERS.contains(entry.getKey())) { builder.append(" Header : " + entry.getKey() + " = " + entry.getValue() + "\n"); } } builder.append(" Method : " + request.getMethod() + "\n"); builder.append(" URI : " + request.getRequestUri() + "\n"); for (Map.Entry> entry : request.getQueryParameters(true).entrySet()) { final String name = entry.getKey(); final List value = entry.getValue(); builder.append(" Param : " + name + " = " + value + " \n"); } logger.info(builder.toString()); } } }