Search in sources :

Example 1 with UserAuthentication

use of org.pmiops.workbench.auth.UserAuthentication in project workbench by all-of-us.

the class AuthInterceptor method preHandle.

/**
 * Returns true iff the request is auth'd and should proceed. Publishes authenticated user info
 * using Spring's SecurityContext.
 * @param handler The Swagger-generated ApiController. It contains our handler as a private
 *     delegate.
 */
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // OPTIONS methods requests don't need authorization.
    if (request.getMethod().equals(HttpMethods.OPTIONS)) {
        return true;
    }
    HandlerMethod method = (HandlerMethod) handler;
    boolean isAuthRequired = false;
    ApiOperation apiOp = AnnotationUtils.findAnnotation(method.getMethod(), ApiOperation.class);
    if (apiOp != null) {
        for (Authorization auth : apiOp.authorizations()) {
            if (auth.value().equals(authName)) {
                isAuthRequired = true;
                break;
            }
        }
    }
    if (!isAuthRequired) {
        return true;
    }
    String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
    if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
        log.warning("No bearer token found in request");
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        return false;
    }
    String token = authorizationHeader.substring("Bearer".length()).trim();
    Userinfoplus userInfo;
    try {
        userInfo = userInfoService.getUserInfo(token);
    } catch (HttpResponseException e) {
        log.log(Level.WARNING, "{0} response getting user info for bearer token {1}: {2}", new Object[] { e.getStatusCode(), token, e.getStatusMessage() });
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        return false;
    }
    // TODO: check Google group membership to ensure user is in registered user group
    String userEmail = userInfo.getEmail();
    WorkbenchConfig workbenchConfig = workbenchConfigProvider.get();
    if (workbenchConfig.auth.serviceAccountApiUsers.contains(userEmail)) {
        // Whitelisted service accounts are able to make API calls, too.
        // TODO: stop treating service accounts as normal users, have a separate table for them,
        // administrators.
        User user = userDao.findUserByEmail(userEmail);
        if (user == null) {
            user = userService.createServiceAccountUser(userEmail);
        }
        SecurityContextHolder.getContext().setAuthentication(new UserAuthentication(user, userInfo, token, UserType.SERVICE_ACCOUNT));
        log.log(Level.INFO, "{0} service account in use", userInfo.getEmail());
        return true;
    }
    String gsuiteDomainSuffix = "@" + workbenchConfig.googleDirectoryService.gSuiteDomain;
    if (!userEmail.endsWith(gsuiteDomainSuffix)) {
        try {
            // If the email isn't in our GSuite domain, try FireCloud; we could be dealing with a
            // pet service account. In both AofU and FireCloud, the pet SA is treated as if it were
            // the user it was created for.
            userEmail = fireCloudService.getMe().getUserInfo().getUserEmail();
        } catch (ApiException e) {
            log.log(Level.INFO, "FireCloud lookup for {0} failed, can't access the workbench: {1}", new Object[] { userInfo.getEmail(), e.getMessage() });
            response.sendError(e.getCode());
            return false;
        }
        if (!userEmail.endsWith(gsuiteDomainSuffix)) {
            log.log(Level.INFO, "User {0} isn't in domain {1}, can't access the workbench", new Object[] { userEmail, gsuiteDomainSuffix });
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return false;
        }
    }
    User user = userDao.findUserByEmail(userEmail);
    if (user == null) {
        // TODO(danrodney): start populating contact email in Google account, use it here.
        user = userService.createUser(userInfo.getGivenName(), userInfo.getFamilyName(), userInfo.getEmail(), null);
    } else {
        if (user.getDisabled()) {
            throw new ForbiddenException(ExceptionUtils.errorResponse(ErrorCode.USER_DISABLED, "This user account has been disabled."));
        }
    }
    SecurityContextHolder.getContext().setAuthentication(new UserAuthentication(user, userInfo, token, UserType.RESEARCHER));
    // TODO: setup this in the context, get rid of log statement
    log.log(Level.INFO, "{0} logged in", userInfo.getEmail());
    if (!hasRequiredAuthority(method, user)) {
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
        return false;
    }
    return true;
}
Also used : Userinfoplus(com.google.api.services.oauth2.model.Userinfoplus) WorkbenchConfig(org.pmiops.workbench.config.WorkbenchConfig) ForbiddenException(org.pmiops.workbench.exceptions.ForbiddenException) User(org.pmiops.workbench.db.model.User) HttpResponseException(com.google.api.client.http.HttpResponseException) UserAuthentication(org.pmiops.workbench.auth.UserAuthentication) HandlerMethod(org.springframework.web.method.HandlerMethod) Authorization(io.swagger.annotations.Authorization) ApiOperation(io.swagger.annotations.ApiOperation) ApiException(org.pmiops.workbench.firecloud.ApiException)

Example 2 with UserAuthentication

use of org.pmiops.workbench.auth.UserAuthentication in project workbench by all-of-us.

the class ProfileControllerTest method createUser.

private Profile createUser() throws Exception {
    when(cloudStorageService.readInvitationKey()).thenReturn(INVITATION_KEY);
    when(directoryService.createUser(GIVEN_NAME, FAMILY_NAME, USERNAME, PASSWORD)).thenReturn(googleUser);
    when(fireCloudService.isRequesterEnabledInFirecloud()).thenReturn(false);
    Profile result = profileController.createAccount(createAccountRequest).getBody();
    user = userDao.findUserByEmail(PRIMARY_EMAIL);
    user.setEmailVerificationStatus(EmailVerificationStatus.SUBSCRIBED);
    userDao.save(user);
    when(userProvider.get()).thenReturn(user);
    when(userAuthenticationProvider.get()).thenReturn(new UserAuthentication(user, null, null, UserType.RESEARCHER));
    return result;
}
Also used : UserAuthentication(org.pmiops.workbench.auth.UserAuthentication) Profile(org.pmiops.workbench.model.Profile)

Example 3 with UserAuthentication

use of org.pmiops.workbench.auth.UserAuthentication in project workbench by all-of-us.

the class ProfileController method initializeUserIfNeeded.

private User initializeUserIfNeeded() {
    UserAuthentication userAuthentication = userAuthenticationProvider.get();
    User user = userAuthentication.getUser();
    if (userAuthentication.getUserType() == UserType.SERVICE_ACCOUNT) {
        // Service accounts don't need further initialization.
        return user;
    }
    // On first sign-in, create a FC user, billing project, and set the first sign in time.
    if (user.getFirstSignInTime() == null) {
        // instead use the freeTierBillingProjectStatus.
        if (user.getFreeTierBillingProjectName() == null) {
            String billingProjectName = createFirecloudUserAndBillingProject(user);
            user.setFreeTierBillingProjectName(billingProjectName);
            user.setFreeTierBillingProjectStatus(BillingProjectStatus.PENDING);
        }
        user.setFirstSignInTime(new Timestamp(clock.instant().toEpochMilli()));
        try {
            return userDao.save(user);
        } catch (ObjectOptimisticLockingFailureException e) {
            log.log(Level.WARNING, "version conflict for user update", e);
            throw new ConflictException("Failed due to concurrent modification");
        }
    }
    // Free tier billing project setup is complete; nothing to do.
    if (BillingProjectStatus.READY.equals(user.getFreeTierBillingProjectStatus())) {
        return user;
    }
    // On subsequent sign-ins to the first, attempt to complete the setup of the FC billing project
    // and mark the Workbench's project setup as completed. FC project creation is asynchronous, so
    // first confirm whether Firecloud claims the project setup is complete.
    BillingProjectStatus status = null;
    try {
        status = fireCloudService.getBillingProjectMemberships().stream().filter(m -> user.getFreeTierBillingProjectName().equals(m.getProjectName())).map(m -> fcToWorkbenchBillingMap.get(m.getCreationStatus())).findFirst().orElse(BillingProjectStatus.NONE);
    } catch (ApiException e) {
        log.log(Level.WARNING, "failed to retrieve billing projects, continuing", e);
        return user;
    }
    switch(status) {
        case NONE:
        case PENDING:
            log.log(Level.INFO, "free tier project is still initializing, continuing");
            return user;
        case ERROR:
            log.log(Level.SEVERE, String.format("free tier project %s failed to be created", user.getFreeTierBillingProjectName()));
            user.setFreeTierBillingProjectStatus(status);
            return userDao.save(user);
        case READY:
            break;
        default:
            log.log(Level.SEVERE, String.format("unrecognized status '%s'", status));
            return user;
    }
    // notebooks.
    try {
        fireCloudService.grantGoogleRoleToUser(user.getFreeTierBillingProjectName(), FireCloudService.BIGQUERY_JOB_USER_GOOGLE_ROLE, user.getEmail());
    } catch (ApiException e) {
        log.log(Level.WARNING, "granting BigQuery role on created free tier billing project failed", e);
        // Allow the user to continue, as most workbench functionality will still be usable.
        return user;
    }
    log.log(Level.INFO, "free tier project initialized and BigQuery role granted");
    user.setFreeTierBillingProjectStatus(BillingProjectStatus.READY);
    return userDao.save(user);
}
Also used : Message(javax.mail.Message) ObjectOptimisticLockingFailureException(org.springframework.orm.ObjectOptimisticLockingFailureException) IdVerificationListResponse(org.pmiops.workbench.model.IdVerificationListResponse) Provider(javax.inject.Provider) MailChimpService(org.pmiops.workbench.mailchimp.MailChimpService) FireCloudService(org.pmiops.workbench.firecloud.FireCloudService) MessagingException(javax.mail.MessagingException) Autowired(org.springframework.beans.factory.annotation.Autowired) EmailException(org.pmiops.workbench.exceptions.EmailException) DirectoryService(org.pmiops.workbench.google.DirectoryService) Authority(org.pmiops.workbench.model.Authority) CreateAccountRequest(org.pmiops.workbench.model.CreateAccountRequest) Map(java.util.Map) CloudStorageService(org.pmiops.workbench.google.CloudStorageService) User(org.pmiops.workbench.db.model.User) Profile(org.pmiops.workbench.model.Profile) UserService(org.pmiops.workbench.db.dao.UserService) UserDao(org.pmiops.workbench.db.dao.UserDao) Transport(javax.mail.Transport) ImmutableMap(com.google.common.collect.ImmutableMap) Timestamp(java.sql.Timestamp) AuthorityRequired(org.pmiops.workbench.annotations.AuthorityRequired) InvitationVerificationRequest(org.pmiops.workbench.model.InvitationVerificationRequest) ConflictException(org.pmiops.workbench.exceptions.ConflictException) Logger(java.util.logging.Logger) Collectors(java.util.stream.Collectors) RestController(org.springframework.web.bind.annotation.RestController) List(java.util.List) Address(com.blockscore.models.Address) BillingProjectStatus(org.pmiops.workbench.model.BillingProjectStatus) WorkbenchEnvironment(org.pmiops.workbench.config.WorkbenchEnvironment) UnsupportedEncodingException(java.io.UnsupportedEncodingException) UserType(org.pmiops.workbench.auth.UserAuthentication.UserType) BillingProjectMembership(org.pmiops.workbench.model.BillingProjectMembership) UsernameTakenResponse(org.pmiops.workbench.model.UsernameTakenResponse) ApiException(org.pmiops.workbench.firecloud.ApiException) Function(java.util.function.Function) ArrayList(java.util.ArrayList) Level(java.util.logging.Level) InternetAddress(javax.mail.internet.InternetAddress) ProfileService(org.pmiops.workbench.auth.ProfileService) BadRequestException(org.pmiops.workbench.exceptions.BadRequestException) ExceptionUtils(org.pmiops.workbench.exceptions.ExceptionUtils) Properties(java.util.Properties) IdVerificationRequest(org.pmiops.workbench.model.IdVerificationRequest) IdVerificationReviewRequest(org.pmiops.workbench.model.IdVerificationReviewRequest) BlockscoreIdVerificationStatus(org.pmiops.workbench.model.BlockscoreIdVerificationStatus) IOException(java.io.IOException) MimeMessage(javax.mail.internet.MimeMessage) BlockscoreService(org.pmiops.workbench.blockscore.BlockscoreService) UserAuthentication(org.pmiops.workbench.auth.UserAuthentication) HttpStatus(org.springframework.http.HttpStatus) ServerErrorException(org.pmiops.workbench.exceptions.ServerErrorException) WorkbenchConfig(org.pmiops.workbench.config.WorkbenchConfig) Clock(java.time.Clock) Session(javax.mail.Session) EmailVerificationStatus(org.pmiops.workbench.model.EmailVerificationStatus) Person(com.blockscore.models.Person) ResponseEntity(org.springframework.http.ResponseEntity) CreationStatusEnum(org.pmiops.workbench.firecloud.model.BillingProjectMembership.CreationStatusEnum) BillingProjectStatus(org.pmiops.workbench.model.BillingProjectStatus) User(org.pmiops.workbench.db.model.User) ConflictException(org.pmiops.workbench.exceptions.ConflictException) UserAuthentication(org.pmiops.workbench.auth.UserAuthentication) Timestamp(java.sql.Timestamp) ObjectOptimisticLockingFailureException(org.springframework.orm.ObjectOptimisticLockingFailureException) ApiException(org.pmiops.workbench.firecloud.ApiException)

Aggregations

UserAuthentication (org.pmiops.workbench.auth.UserAuthentication)3 WorkbenchConfig (org.pmiops.workbench.config.WorkbenchConfig)2 User (org.pmiops.workbench.db.model.User)2 ApiException (org.pmiops.workbench.firecloud.ApiException)2 Profile (org.pmiops.workbench.model.Profile)2 Address (com.blockscore.models.Address)1 Person (com.blockscore.models.Person)1 HttpResponseException (com.google.api.client.http.HttpResponseException)1 Userinfoplus (com.google.api.services.oauth2.model.Userinfoplus)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 ApiOperation (io.swagger.annotations.ApiOperation)1 Authorization (io.swagger.annotations.Authorization)1 IOException (java.io.IOException)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 Timestamp (java.sql.Timestamp)1 Clock (java.time.Clock)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 Map (java.util.Map)1 Properties (java.util.Properties)1