Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import javax.inject.Provider;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.ForbiddenException;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
Expand Down Expand Up @@ -57,9 +58,46 @@ public class CheckLoginFilter implements ContainerRequestFilter, ContainerRespon
@Inject
protected Provider<Request> _grizzlyRequest;

/*************** The following three methods control the default behavior for WDK endpoints ************/

/**
* @param path request URL path
* @return true if no authorization is required and no guest
* user should be created for this request, else false
*/
protected boolean isPathToSkip(String path) {
// skip user check for prometheus metrics requests
return SystemService.PROMETHEUS_ENDPOINT_PATH.equals(path);
}

/**
* A return value of true indicates a valid bearer token is required; the token
* may be a guest depending on the value of isGuestUserAllowed(). If false is
* returned, no token is present, and isGuestUserAllowed() returns true, then a
* new guest token will be generated for this request and returned to the user.
*
* @param path request URL path
* @return true if a valid bearer token is required on the request, else false
*/
protected boolean isValidTokenRequired(String path) {
return false;
}

/**
* A return value of true indicates a guest user is allowed to access this
* endpoint. If a sent token is absent and isValidTokenRequired() returns false,
* a new guest token will be generated for use on this request.
*
* @param path request URL path
* @return true if guests are allowed to access this endpoint, else false
*/
protected boolean isGuestUserAllowed(String path) {
return true;
}

@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// skip endpoints which do not require a user; prevents guests from being unnecessarily created
// skip endpoints which do not require auth nor a guest user; prevents guests from being unnecessarily created
String requestPath = requestContext.getUriInfo().getPath();
if (isPathToSkip(requestPath)) return;

Expand All @@ -72,20 +110,45 @@ public void filter(ContainerRequestContext requestContext) throws IOException {

try {
if (rawToken == null) {
// no credentials submitted; automatically create a guest to use on this request
useNewGuest(factory, request, requestContext, requestPath);
// no credentials submitted; check requirements of this path
if (isValidTokenRequired(requestPath)) {
LOG.warn("Did not received bearer token as required for path:" + requestPath);
throw new NotAuthorizedException(Response.status(Status.UNAUTHORIZED).build());
}
// if allowed, automatically create a guest to use on this request
if (isGuestUserAllowed(requestPath)) {
useNewGuest(factory, request, requestContext, requestPath);
}
else {
// no authentication provided, and guests are disallowed
throw new NotAuthorizedException(Response.status(Status.UNAUTHORIZED).build());
}
}
else {
try {
// validate submitted token
ValidatedToken token = factory.validateBearerToken(rawToken);
User user = factory.convertToUser(token);
setRequestAttributes(request, token, user);
LOG.info("Validated successfully. Request will be processed for user " + user.getUserId());
if (!user.isGuest() || isGuestUserAllowed(requestPath)) {
setRequestAttributes(request, token, user);
LOG.info("Validated successfully. Request will be processed for " +
(user.isGuest() ? "guest" : "registered") + " user " + user.getUserId());
}
else {
// valid guest token submitted, but guests disallowed for this path
throw new ForbiddenException();
}
}
catch (ExpiredTokenException e) {
// token is expired; use guest token for now which should inspire them to log back in
useNewGuest(factory, request, requestContext, requestPath);
if (isGuestUserAllowed(requestPath)) {
// token is expired, but a new guest token is allowed to be generated,
// which will hopefully inspire them to log back in
useNewGuest(factory, request, requestContext, requestPath);
}
else {
throw new NotAuthorizedException(Response.status(Status.UNAUTHORIZED)
.entity("Authorization token has expired.").build());
}
}
catch (InvalidTokenException e) {
// passed token is invalid; throw 401
Expand All @@ -94,10 +157,10 @@ public void filter(ContainerRequestContext requestContext) throws IOException {
}
}
}
catch (Exception e) {
catch (WdkModelException | RuntimeException e) {
// any other exception is fatal, but log first
LOG.error("Unable to authenticate with Authorization header " + rawToken, e);
throw e instanceof RuntimeException ? (RuntimeException)e : new WdkRuntimeException(e);
throw e instanceof WdkModelException ? new WdkRuntimeException(e) : (RuntimeException)e;
}
}

Expand Down Expand Up @@ -131,11 +194,6 @@ private String findRawBearerToken(RequestData request, ContainerRequestContext r
return cookie == null ? null : cookie.getValue();
}

protected boolean isPathToSkip(String path) {
// skip user check for prometheus metrics requests
return SystemService.PROMETHEUS_ENDPOINT_PATH.equals(path);
}

@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
Expand Down