Created
September 24, 2013 17:48
-
-
Save ryankennedy/6688601 to your computer and use it in GitHub Desktop.
Example of adding audited REST endpoints to a Dropwizard service.
This file contains 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 { | |
} |
This file contains 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.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; | |
} | |
} |
This file contains 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.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()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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?