package com.bazaarvoice.auth.hmac.server;
import static com.bazaarvoice.auth.hmac.common.Credentials.builder;
import static javax.ws.rs.core.Response.status;
import static javax.ws.rs.core.Response.Status.UNAUTHORIZED;
import static org.apache.commons.lang.Validate.notNull;
import java.net.URI;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import org.glassfish.hk2.api.Factory;
import org.glassfish.jersey.server.ContainerRequest;
import com.bazaarvoice.auth.hmac.common.Credentials.CredentialsBuilder;
import com.bazaarvoice.auth.hmac.common.Version;
/**
* {@link Factory} for creating a principal wherever it is required for a request.
*
* @param <P> The type of principal
* @see Authenticator
*/
public class PrincipalFactory<P> implements Factory<P> {
private final Authenticator<? extends P> authenticator;
private final Provider<? extends ContainerRequest> requestProvider;
/**
* @param authenticator the application's credential authenticator (required)
* @param requestProvider object that provides access to the active request (required)
*/
@Inject
public PrincipalFactory(final Authenticator<P> authenticator,
final Provider<ContainerRequest> requestProvider) {
// we could technically declare the dependency as Authenticator<? extends P>, but that complicates HK2
// dependency-injection
notNull(authenticator, "authenticator cannot be null");
this.authenticator = authenticator;
this.requestProvider = requestProvider;
}
public P provide() {
final ContainerRequest request = getRequestProvider().get();
final UriInfo uriInfo = request.getUriInfo();
final URI requestUri = uriInfo.getRequestUri();
final MultivaluedMap<? super String, ? extends String> queryParameters = uriInfo
.getQueryParameters();
final List<? extends String> apiKeys = queryParameters.get("apiKey");
if (apiKeys == null || apiKeys.isEmpty()) {
throw new BadRequestException("apiKey is required");
}
final CredentialsBuilder builder = builder();
builder.withApiKey(!apiKeys.isEmpty() ? apiKeys.get(0) : null);
builder.withSignature(request.getHeaderString("X-Auth-Signature"));
builder.withTimestamp(request.getHeaderString("X-Auth-Timestamp"));
builder.withVersion(
Version.fromValue(request.getHeaderString("X-Auth-Version")));
builder.withMethod(request.getMethod());
builder.withPath(requestUri.getPath() + "?" + requestUri.getQuery());
final P retval = getAuthenticator().authenticate(builder.build());
if (retval == null) {
throw new NotAuthorizedException(status(UNAUTHORIZED).build());
}
return retval;
}
public void dispose(final P instance) {
}
protected Authenticator<? extends P> getAuthenticator() {
return authenticator;
}
protected Provider<? extends ContainerRequest> getRequestProvider() {
return requestProvider;
}
}