Skip to content

Instantly share code, notes, and snippets.

@ryankennedy
Created September 24, 2013 17:48
Show Gist options
  • Save ryankennedy/6688601 to your computer and use it in GitHub Desktop.
Save ryankennedy/6688601 to your computer and use it in GitHub Desktop.
Example of adding audited REST endpoints to a Dropwizard service.
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 {
}
import com.google.common.base.Preconditions;
import com.sun.jersey.api.model.AbstractResourceMethod;
import com.sun.jersey.spi.container.ResourceMethodDispatchProvider;
import com.sun.jersey.spi.dispatch.RequestDispatcher;
import org.slf4j.Logger;
public class AuditedMethodDispatchProvider implements ResourceMethodDispatchProvider {
private final ResourceMethodDispatchProvider provider;
private final Logger logger;
private final boolean requireRemoteIPAddressInformation;
public AuditedMethodDispatchProvider(ResourceMethodDispatchProvider provider, Logger logger, boolean requireRemoteIPAddressInformation) {
this.requireRemoteIPAddressInformation = requireRemoteIPAddressInformation;
this.logger = Preconditions.checkNotNull(logger);
this.provider = Preconditions.checkNotNull(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 AuditedMethodRequestDispatcher(dispatcher, logger, requireRemoteIPAddressInformation);
}
return dispatcher;
}
}
import com.google.common.base.Preconditions;
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.spi.dispatch.RequestDispatcher;
import org.slf4j.Logger;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class AuditedMethodRequestDispatcher implements RequestDispatcher {
private final static Set<String> REDACTED_HEADERS = ImmutableSet.of(HttpHeaders.AUTHORIZATION);
private final RequestDispatcher dispatcher;
private final Logger logger;
private final boolean requireRemoteIPAddressInformation;
public AuditedMethodRequestDispatcher(RequestDispatcher dispatcher, Logger logger, boolean requireRemoteIPAddressInformation) {
this.requireRemoteIPAddressInformation = requireRemoteIPAddressInformation;
this.dispatcher = Preconditions.checkNotNull(dispatcher);
this.logger = Preconditions.checkNotNull(logger);
}
@Override
public void dispatch(Object resource, HttpContext context) {
logRequest(resource, context);
dispatcher.dispatch(resource, context);
}
private void logRequest(Object resource, HttpContext 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());
}
}
Copy link

ghost commented May 2, 2014

How does the DispatchProvider get the boolean value 'requireRemoteIPAddressInformation'?
Does this require a code snippet in the application startup?
Is there a configuration file entry?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment