Last active
January 3, 2016 21:09
-
-
Save sethrylan/8519413 to your computer and use it in GitHub Desktop.
Audit Logging
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.lang.annotation.ElementType; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
import java.lang.annotation.Target; | |
@Target(ElementType.METHOD) | |
@Retention(RetentionPolicy.RUNTIME) | |
public @interface Audited { | |
boolean requireRemoteIp() default true; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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<String> 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<String, List<String>> 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<String, List<String>> entry : request.getQueryParameters(true).entrySet()) { | |
final String name = entry.getKey(); | |
final List<String> value = entry.getValue(); | |
builder.append(" Param : " + name + " = " + value + " \n"); | |
} | |
logger.info(builder.toString()); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
environment.jersey().register(new AuditedResourceMethodDispatchAdapter()); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Returns a list of site codes for available VistA sites. | |
* @return JSON list of site codes strings | |
*/ | |
@GET | |
@Audited | |
@Path("sites") | |
@Produces(MediaType.APPLICATION_JSON) | |
public String getSites() { | |
return (new Gson()).toJson(this.rpcService.getSiteCodeList()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment