Skip to content

Instantly share code, notes, and snippets.

@sethrylan
Last active January 3, 2016 21:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sethrylan/8519413 to your computer and use it in GitHub Desktop.
Save sethrylan/8519413 to your computer and use it in GitHub Desktop.
Audit Logging
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;
}
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());
}
}
}
environment.jersey().register(new AuditedResourceMethodDispatchAdapter());
/**
* 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