Skip to content

Commit

Permalink
Handle expired tokens better + some cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanrdoherty committed Mar 1, 2024
1 parent facb734 commit 0baf925
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 61 deletions.
23 changes: 0 additions & 23 deletions Model/src/main/java/org/gusdb/wdk/events/NewUserEvent.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class UserReferenceFactory {

private static final Integer[] SELECT_USER_REF_BY_ID_PARAM_TYPES = { Types.BIGINT };

private static class UserReference extends ThreeTuple<Long, Boolean, Date> {
// TODO: decide if this is actually needed/desired anywhere. UserRef lookups are not currently used.
public static class UserReference extends ThreeTuple<Long, Boolean, Date> {
public UserReference(Long userId, Boolean isGuest, Date firstAccess) {
super(userId, isGuest, firstAccess);
}
Expand Down Expand Up @@ -91,7 +92,7 @@ public int addUserReference(User user) throws WdkModelException {
}

// FIXME: see if this is actually needed anywhere? E.g. do we ever need to look up user refs by user ID to find last login?
private Optional<UserReference> getUserReference(long userId) throws WdkModelException {
public Optional<UserReference> getUserReference(long userId) throws WdkModelException {
try {
String sql = SELECT_USER_REF_BY_ID_SQL.replace(USER_SCHEMA_MACRO, _userSchema);
return new SQLRunner(_userDb.getDataSource(), sql, "get-user-ref").executeQuery(
Expand Down
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.NotAuthorizedException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
Expand All @@ -16,6 +17,7 @@
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;

import org.apache.log4j.Logger;
import org.glassfish.grizzly.http.server.Request;
Expand All @@ -25,9 +27,11 @@
import org.gusdb.fgputil.web.RequestData;
import org.gusdb.oauth2.client.OAuthClient;
import org.gusdb.oauth2.client.ValidatedToken;
import org.gusdb.oauth2.exception.ExpiredTokenException;
import org.gusdb.oauth2.exception.InvalidTokenException;
import org.gusdb.wdk.controller.ContextLookup;
import org.gusdb.wdk.model.Utilities;
import org.gusdb.wdk.model.WdkModel;
import org.gusdb.wdk.model.WdkModelException;
import org.gusdb.wdk.model.WdkRuntimeException;
import org.gusdb.wdk.model.user.User;
import org.gusdb.wdk.model.user.UserFactory;
Expand Down Expand Up @@ -60,45 +64,60 @@ public void filter(ContainerRequestContext requestContext) throws IOException {

ApplicationContext context = ContextLookup.getApplicationContext(_servletContext);
RequestData request = ContextLookup.getRequest(_servletRequest.get(), _grizzlyRequest.get());
WdkModel wdkModel = ContextLookup.getWdkModel(context);
UserFactory factory = ContextLookup.getWdkModel(context).getUserFactory();

// try to find submitted bearer token
String rawToken = findRawBearerToken(request, requestContext);

try {
UserFactory factory = wdkModel.getUserFactory();
ValidatedToken token;
User user;
if (rawToken != null) {
// validate submitted token
token = factory.validateBearerToken(rawToken);
user = factory.convertToUser(token);

LOG.info("Validated successfully. Request will be processed for user " + user.getUserId() + " / " + user.getEmail());
if (rawToken == null) {
// no credentials submitted; automatically create a guest to use on this request
useNewGuest(factory, request, requestContext, requestPath);
}
else {
// no credentials submitted; automatically create a guest to use on this request
TwoTuple<ValidatedToken,User> guestPair = factory.createUnregisteredUser();
token = guestPair.getFirst();
user = guestPair.getSecond();

LOG.info("Created new guest user [" + user.getUserId() + "] for request to path: /" + requestPath);

// set flag indicating that cookies should be added to response containing the new token
requestContext.setProperty(TOKEN_COOKIE_VALUE_TO_SET, token.getTokenValue());
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() + " / " + user.getEmail());
}
catch (ExpiredTokenException e) {
// token is expired; use guest token for now which should inspire them to log back in
useNewGuest(factory, request, requestContext, requestPath);
}
catch (InvalidTokenException e) {
// passed token is invalid; throw 401
LOG.warn("Received invalid bearer token for auth: " + rawToken);
throw new NotAuthorizedException(Response.noContent().build());
}
}

// set creds and user on the request object for use by this request's processing
request.setAttribute(Utilities.BEARER_TOKEN_KEY, token);
request.setAttribute(Utilities.WDK_USER_KEY, user);
}
catch (Exception e) {
// for now, log and let this go, deferring to legacy authentication
// 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);
}
}

private void useNewGuest(UserFactory factory, RequestData request, ContainerRequestContext requestContext, String requestPath) throws WdkModelException {
TwoTuple<ValidatedToken,User> guestPair = factory.createUnregisteredUser();
ValidatedToken token = guestPair.getFirst();
User user = guestPair.getSecond();
setRequestAttributes(request, token, user);

LOG.info("Created new guest user [" + user.getUserId() + "] for request to path: /" + requestPath);

// set flag indicating that cookies should be added to response containing the new token
requestContext.setProperty(TOKEN_COOKIE_VALUE_TO_SET, token.getTokenValue());
}

private void setRequestAttributes(RequestData request, ValidatedToken token, User user) {
// set creds and user on the request object for use by this request's processing
request.setAttribute(Utilities.BEARER_TOKEN_KEY, token);
request.setAttribute(Utilities.WDK_USER_KEY, user);
}

private String findRawBearerToken(RequestData request, ContainerRequestContext requestContext) {
String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (authHeader != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,14 @@
import org.gusdb.fgputil.EncryptionUtil;
import org.gusdb.fgputil.FormatUtil;
import org.gusdb.fgputil.Tuples.TwoTuple;
import org.gusdb.fgputil.events.Events;
import org.gusdb.fgputil.web.CookieBuilder;
import org.gusdb.fgputil.web.LoginCookieFactory;
import org.gusdb.oauth2.client.ValidatedToken;
import org.gusdb.oauth2.exception.InvalidPropertiesException;
import org.gusdb.wdk.cache.TemporaryUserDataStore.TemporaryUserData;
import org.gusdb.wdk.core.api.JsonKeys;
import org.gusdb.wdk.events.NewUserEvent;
import org.gusdb.wdk.model.WdkModel;
import org.gusdb.wdk.model.WdkModelException;
import org.gusdb.wdk.model.WdkRuntimeException;
import org.gusdb.wdk.model.config.ModelConfig;
import org.gusdb.wdk.model.config.ModelConfig.AuthenticationMethod;
import org.gusdb.wdk.model.user.User;
Expand Down Expand Up @@ -247,9 +244,6 @@ private Response getSuccessResponse(ValidatedToken bearerToken, User newUser, Us

synchronized(tmpData) {

Events.triggerAndWait(new NewUserEvent(newUser, oldUser),
new WdkRuntimeException("Unable to complete WDK user assignement."));

// 3-year expiration (should change secret key before then)
CookieBuilder bearerTokenCookie = new CookieBuilder(
HttpHeaders.AUTHORIZATION,
Expand Down Expand Up @@ -285,15 +279,15 @@ public Response processLogout() throws WdkModelException {

// get the current session's user, then invalidate the session
User oldUser = getRequestingUser();
getTemporaryUserData().invalidate(); // legacy
getTemporaryUserData().invalidate();

// if user is already a guest, no need to log out
if (oldUser.isGuest())
return createRedirectResponse(getContextUri()).build();

// get a new session and add new guest user to it
TwoTuple<ValidatedToken, User> newUser = getWdkModel().getUserFactory().createUnregisteredUser();

// throw new user event
Events.triggerAndWait(new NewUserEvent(newUser.getSecond(), oldUser),
new WdkRuntimeException("Unable to complete WDK user assignement."));

// create and append logout cookies to response
Set<CookieBuilder> logoutCookies = new HashSet<>();
logoutCookies.add(LoginCookieFactory.createLogoutCookie());
Expand Down

0 comments on commit 0baf925

Please sign in to comment.