Search in sources :

Example 1 with UserFromAuthProvider

use of uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider in project isaac-api by isaacphysics.

the class UserAccountManager method authenticateCallback.

/**
 * Authenticate Callback will receive the authentication information from the different provider types. (e.g. OAuth
 * 2.0 (IOAuth2Authenticator) or bespoke)
 *
 * This method will either register a new user and attach the linkedAccount or locate the existing account of the
 * user and create a session for that.
 *
 * @param request
 *            - http request from the user - should contain url encoded token details.
 * @param response
 *            to store the session in our own segue cookie.
 * @param provider
 *            - the provider who has just authenticated the user.
 * @param rememberMe
 *            - Boolean to indicate whether or not this cookie expiry duration should be long or short
 * @return Response containing the user object. Alternatively a SegueErrorResponse could be returned.
 * @throws AuthenticationProviderMappingException
 *             - if we cannot locate an appropriate authenticator.
 * @throws SegueDatabaseException
 *             - if there is a local database error.
 * @throws IOException
 *             - Problem reading something
 * @throws NoUserException
 *             - If the user doesn't exist with the provider.
 * @throws AuthenticatorSecurityException
 *             - If there is a security probably with the authenticator.
 * @throws CrossSiteRequestForgeryException
 *             - as per exception description.
 * @throws CodeExchangeException
 *             - as per exception description.
 * @throws AuthenticationCodeException
 *             - as per exception description.
 */
public RegisteredUserDTO authenticateCallback(final HttpServletRequest request, final HttpServletResponse response, final String provider, final boolean rememberMe) throws AuthenticationProviderMappingException, AuthenticatorSecurityException, NoUserException, IOException, SegueDatabaseException, AuthenticationCodeException, CodeExchangeException, CrossSiteRequestForgeryException {
    IAuthenticator authenticator = this.userAuthenticationManager.mapToProvider(provider);
    // get the auth provider user data.
    UserFromAuthProvider providerUserDO = this.userAuthenticationManager.getThirdPartyUserInformation(request, provider);
    // if the UserFromAuthProvider exists then this is a login request so process it.
    RegisteredUser userFromLinkedAccount = this.userAuthenticationManager.getSegueUserFromLinkedAccount(authenticator.getAuthenticationProvider(), providerUserDO.getProviderUserId());
    if (userFromLinkedAccount != null) {
        return this.logUserIn(request, response, userFromLinkedAccount, rememberMe);
    }
    RegisteredUser currentUser = getCurrentRegisteredUserDO(request);
    // if the user is currently logged in and this is a request for a linked account, then create the new link.
    if (null != currentUser) {
        Boolean intentionToLinkRegistered = (Boolean) request.getSession().getAttribute(LINK_ACCOUNT_PARAM_NAME);
        if (intentionToLinkRegistered == null || !intentionToLinkRegistered) {
            throw new SegueDatabaseException("User is already authenticated - " + "expected request to link accounts but none was found.");
        }
        List<AuthenticationProvider> usersProviders = this.database.getAuthenticationProvidersByUser(currentUser);
        if (!usersProviders.contains(authenticator.getAuthenticationProvider())) {
            // create linked account
            this.userAuthenticationManager.linkProviderToExistingAccount(currentUser, authenticator.getAuthenticationProvider(), providerUserDO);
            // clear link accounts intention until next time
            request.removeAttribute(LINK_ACCOUNT_PARAM_NAME);
        }
        return this.convertUserDOToUserDTO(getCurrentRegisteredUserDO(request));
    } else {
        if (providerUserDO.getEmail() != null && !providerUserDO.getEmail().isEmpty() && this.findUserByEmail(providerUserDO.getEmail()) != null) {
            log.warn("A user tried to use unknown provider '" + capitalizeFully(provider) + "' to log in to an account with matching email (" + providerUserDO.getEmail() + ").");
            throw new DuplicateAccountException("You do not use " + capitalizeFully(provider) + " to log on to Isaac." + " You may have registered using a different provider, or a username and password.");
        }
        // this must be a registration request
        RegisteredUser segueUserDO = this.registerUserWithFederatedProvider(authenticator.getAuthenticationProvider(), providerUserDO);
        RegisteredUserDTO segueUserDTO = this.logUserIn(request, response, segueUserDO, rememberMe);
        segueUserDTO.setFirstLogin(true);
        try {
            ImmutableMap<String, Object> emailTokens = ImmutableMap.of("provider", capitalizeFully(provider));
            emailManager.sendTemplatedEmailToUser(segueUserDTO, emailManager.getEmailTemplateDTO("email-template-registration-confirmation-federated"), emailTokens, EmailType.SYSTEM);
        } catch (ContentManagerException e) {
            log.error("Registration email could not be sent due to content issue: " + e.getMessage());
        }
        return segueUserDTO;
    }
}
Also used : IAuthenticator(uk.ac.cam.cl.dtg.segue.auth.IAuthenticator) SegueDatabaseException(uk.ac.cam.cl.dtg.segue.dao.SegueDatabaseException) AuthenticationProvider(uk.ac.cam.cl.dtg.segue.auth.AuthenticationProvider) RegisteredUser(uk.ac.cam.cl.dtg.isaac.dos.users.RegisteredUser) RegisteredUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO) UserFromAuthProvider(uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider) ContentManagerException(uk.ac.cam.cl.dtg.segue.dao.content.ContentManagerException)

Example 2 with UserFromAuthProvider

use of uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider in project isaac-api by isaacphysics.

the class UserAuthenticationManager method getThirdPartyUserInformation.

/**
 * Get the 3rd party authentication providers user object.
 * This can be used to look up existing segue users or create a new one.
 *
 * @param request
 *            - to retrieve session params
 * @param provider
 *            - the provider we are interested in.
 * @return a user object with 3rd party data inside.
 * @throws AuthenticationProviderMappingException
 *             - if we cannot locate an appropriate authenticator.
 * @throws IOException
 *             - Problem reading something
 * @throws NoUserException
 *             - If the user doesn't exist with the provider.
 * @throws AuthenticatorSecurityException
 *             - If there is a security probably with the authenticator.
 * @throws CrossSiteRequestForgeryException
 *             - as per exception description.
 * @throws CodeExchangeException
 *             - as per exception description.
 * @throws AuthenticationCodeException
 *             - as per exception description.
 */
public UserFromAuthProvider getThirdPartyUserInformation(final HttpServletRequest request, final String provider) throws AuthenticationProviderMappingException, AuthenticatorSecurityException, NoUserException, IOException, AuthenticationCodeException, CodeExchangeException, CrossSiteRequestForgeryException {
    IAuthenticator authenticator = mapToProvider(provider);
    IOAuthAuthenticator oauthProvider;
    // this is a reference that the provider can use to look up user details.
    String providerSpecificUserLookupReference;
    // if we are an OAuth2Provider complete next steps of oauth
    if (authenticator instanceof IOAuthAuthenticator) {
        oauthProvider = (IOAuthAuthenticator) authenticator;
        providerSpecificUserLookupReference = this.getOauthInternalRefCode(oauthProvider, request);
    } else {
        throw new AuthenticationProviderMappingException("Unable to map to a known authenticator. The provider: " + provider + " is unknown");
    }
    UserFromAuthProvider userFromProvider = oauthProvider.getUserInfo(providerSpecificUserLookupReference);
    return userFromProvider;
}
Also used : IAuthenticator(uk.ac.cam.cl.dtg.segue.auth.IAuthenticator) UserFromAuthProvider(uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider) AuthenticationProviderMappingException(uk.ac.cam.cl.dtg.segue.auth.exceptions.AuthenticationProviderMappingException) IOAuthAuthenticator(uk.ac.cam.cl.dtg.segue.auth.IOAuthAuthenticator)

Example 3 with UserFromAuthProvider

use of uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider in project isaac-api by isaacphysics.

the class FacebookAuthenticator method getUserInfo.

@Override
public synchronized UserFromAuthProvider getUserInfo(final String internalProviderReference) throws NoUserException, AuthenticatorSecurityException {
    Credential credentials = credentialStore.get(internalProviderReference);
    if (verifyAccessTokenIsValid(credentials)) {
        log.debug("Successful Verification of access token with provider.");
    } else {
        log.error("Unable to verify access token - it could be an indication of fraud.");
        throw new AuthenticatorSecurityException("Access token is invalid - the client id returned by the identity provider does not match ours.");
    }
    FacebookUser userInfo = null;
    try {
        GenericUrl url = new GenericUrl(USER_INFO_URL + "?fields=" + requestedFields);
        url.set("access_token", credentials.getAccessToken());
        userInfo = JsonLoader.load(inputStreamToString(url.toURL().openStream()), FacebookUser.class, true);
        log.debug("Retrieved User info from Facebook");
    } catch (IOException e) {
        log.error("An IO error occurred while trying to retrieve user information: " + e);
    }
    if (userInfo != null && userInfo.getId() != null) {
        EmailVerificationStatus emailStatus = userInfo.isVerified() ? EmailVerificationStatus.VERIFIED : EmailVerificationStatus.NOT_VERIFIED;
        String email = userInfo.getEmail();
        if (null == email) {
            email = userInfo.getId() + "-facebook";
            emailStatus = EmailVerificationStatus.DELIVERY_FAILED;
            log.warn("No email address provided by Facebook! Using (" + email + ") instead");
        }
        return new UserFromAuthProvider(userInfo.getId(), userInfo.getFirstName(), userInfo.getLastName(), email, emailStatus, null, null, null);
    } else {
        throw new NoUserException("No user could be created from provider details!");
    }
}
Also used : Credential(com.google.api.client.auth.oauth2.Credential) AuthenticatorSecurityException(uk.ac.cam.cl.dtg.segue.auth.exceptions.AuthenticatorSecurityException) UserFromAuthProvider(uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider) NoUserException(uk.ac.cam.cl.dtg.segue.auth.exceptions.NoUserException) GenericUrl(com.google.api.client.http.GenericUrl) IOException(java.io.IOException) EmailVerificationStatus(uk.ac.cam.cl.dtg.isaac.dos.users.EmailVerificationStatus) FacebookUser(uk.ac.cam.cl.dtg.isaac.dos.users.FacebookUser)

Example 4 with UserFromAuthProvider

use of uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider in project isaac-api by isaacphysics.

the class UserManagerTest method authenticateCallback_checkNewUserIsAuthenticated_createInternalUserAccount.

/**
 * Check that a new (unseen) user is registered when seen with 3rd party authenticator.
 *
 * @throws Exception
 *             -
 */
@Test
public final void authenticateCallback_checkNewUserIsAuthenticated_createInternalUserAccount() throws Exception {
    IOAuth2Authenticator dummyAuth = createMock(FacebookAuthenticator.class);
    UserAccountManager userManager = buildTestUserManager(AuthenticationProvider.TEST, dummyAuth);
    UserAuthenticationManager authManager = buildTestAuthenticationManager(AuthenticationProvider.TEST, dummyAuth);
    // method param setup for method under test
    HttpSession dummySession = createMock(HttpSession.class);
    HttpServletRequest request = createMock(HttpServletRequest.class);
    HttpServletResponse response = createMock(HttpServletResponse.class);
    String someDomain = "http://www.somedomain.com/";
    String someClientId = "someClientId";
    String someAuthCode = "someAuthCode";
    String someState = "someState";
    StringBuffer sb = new StringBuffer(someDomain + "?state=" + someState + "&code=" + someAuthCode);
    String validQueryStringFromProvider = "client_id=" + someClientId + "&redirect_uri=" + someDomain;
    String fullResponseUrlFromProvider = someDomain + "?state=" + someState + "&code=" + someAuthCode + "?client_id=" + someClientId + "&redirect_uri=" + someDomain;
    String someProviderGeneratedLookupValue = "MYPROVIDERREF";
    String someProviderUniqueUserId = "USER-1";
    Long someSegueUserId = 533L;
    String someSegueAnonymousUserId = "9284723987anonymous83924923";
    AnonymousUser au = new AnonymousUser();
    au.setSessionId(someSegueAnonymousUserId);
    expect(this.dummyUserCache.storeAnonymousUser(au)).andReturn(au).atLeastOnce();
    expect(this.dummyUserCache.getById(au.getSessionId())).andReturn(au).atLeastOnce();
    AnonymousUserDTO someAnonymousUserDTO = new AnonymousUserDTO();
    someAnonymousUserDTO.setSessionId(someSegueAnonymousUserId);
    String validOAuthProvider = "test";
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.SECOND, 500);
    String validDateString = sdf.format(calendar.getTime());
    expect(request.getSession()).andReturn(dummySession).atLeastOnce();
    // empty as not logged in.
    Cookie[] cookieWithoutSessionInfo = {};
    expect(request.getCookies()).andReturn(cookieWithoutSessionInfo).times(2);
    // session
    expect(dummySession.getAttribute(Constants.ANONYMOUS_USER)).andReturn(someSegueAnonymousUserId).atLeastOnce();
    // id
    // Mock CSRF checks
    expect(dummySession.getAttribute(Constants.STATE_PARAM_NAME)).andReturn(CSRF_TEST_VALUE).atLeastOnce();
    expect(request.getParameter(Constants.STATE_PARAM_NAME)).andReturn(CSRF_TEST_VALUE).atLeastOnce();
    // Mock URL params extract stuff
    expect(request.getQueryString()).andReturn(validQueryStringFromProvider).atLeastOnce();
    expect(request.getRequestURL()).andReturn(sb);
    // Mock extract auth code call
    expect(dummyAuth.extractAuthCode(fullResponseUrlFromProvider)).andReturn(someAuthCode);
    // Mock exchange code for token call
    expect(dummyAuth.exchangeCode(someAuthCode)).andReturn(someProviderGeneratedLookupValue).atLeastOnce();
    expect(((IFederatedAuthenticator) dummyAuth).getAuthenticationProvider()).andReturn(AuthenticationProvider.TEST).atLeastOnce();
    // User object back from provider
    UserFromAuthProvider providerUser = new UserFromAuthProvider(someProviderUniqueUserId, "TestFirstName", "TestLastName", "test@test.com", EmailVerificationStatus.VERIFIED, Role.STUDENT, new Date(), Gender.MALE);
    // Mock get User Information from provider call
    expect(((IFederatedAuthenticator) dummyAuth).getUserInfo(someProviderGeneratedLookupValue)).andReturn(providerUser).atLeastOnce();
    // Expect this to be a new user and to register them (i.e. return null
    // from database)
    expect(dummyDatabase.getByLinkedAccount(AuthenticationProvider.TEST, someProviderUniqueUserId)).andReturn(null).atLeastOnce();
    RegisteredUser mappedUser = new RegisteredUser(null, "TestFirstName", "testLastName", "test@test.com", Role.STUDENT, new Date(), Gender.MALE, new Date(), null, null, null, null);
    mappedUser.setSessionToken(0);
    expect(dummyDatabase.getAuthenticationProvidersByUsers(Collections.singletonList(mappedUser))).andReturn(new HashMap<RegisteredUser, List<AuthenticationProvider>>() {

        {
            put(mappedUser, Lists.newArrayList(AuthenticationProvider.GOOGLE));
        }
    }).atLeastOnce();
    expect(dummyDatabase.getSegueAccountExistenceByUsers(Collections.singletonList(mappedUser))).andReturn(ImmutableMap.of(mappedUser, false)).atLeastOnce();
    RegisteredUserDTO mappedUserDTO = new RegisteredUserDTO();
    expect(dummyMapper.map(providerUser, RegisteredUser.class)).andReturn(mappedUser).atLeastOnce();
    expect(dummyMapper.map(mappedUser, RegisteredUserDTO.class)).andReturn(mappedUserDTO).atLeastOnce();
    expect(dummyMapper.map(au, AnonymousUserDTO.class)).andReturn(someAnonymousUserDTO).anyTimes();
    // handle duplicate account check.
    expect(dummyDatabase.getByEmail(providerUser.getEmail())).andReturn(null).once();
    // A main part of the test is to check the below call happens
    expect(dummyDatabase.registerNewUserWithProvider(mappedUser, AuthenticationProvider.TEST, someProviderUniqueUserId)).andReturn(mappedUser).atLeastOnce();
    mappedUser.setId(someSegueUserId);
    expect(dummyDatabase.getById(someSegueUserId)).andReturn(mappedUser);
    Map<String, String> sessionInformation = getSessionInformationAsAMap(authManager, someSegueUserId.toString(), validDateString, mappedUser.getSessionToken());
    Cookie[] cookieWithSessionInfo = getCookieArray(sessionInformation);
    // Expect a session to be created
    response.addCookie(cookieWithSessionInfo[0]);
    expectLastCall().once();
    expect(request.getCookies()).andReturn(cookieWithSessionInfo).anyTimes();
    dummyQuestionDatabase.mergeAnonymousQuestionAttemptsIntoRegisteredUser(someAnonymousUserDTO, mappedUserDTO);
    expectLastCall().once();
    expect(dummyQueue.getEmailTemplateDTO("email-template-registration-confirmation-federated")).andReturn(new EmailTemplateDTO()).once();
    dummyQueue.sendTemplatedEmailToUser(anyObject(), anyObject(), anyObject(), anyObject());
    expectLastCall().once();
    replay(dummySession, request, dummyAuth, dummyQuestionDatabase, dummyMapper, dummyDatabase, dummyLocalAuth, dummyQueue, dummyUserCache);
    // Act
    RegisteredUserDTO u = userManager.authenticateCallback(request, response, validOAuthProvider, false);
    // Assert
    verify(dummySession, request, dummyAuth, dummyQuestionDatabase);
    assertTrue(u instanceof RegisteredUserDTO);
}
Also used : Cookie(javax.servlet.http.Cookie) HashMap(java.util.HashMap) HttpSession(javax.servlet.http.HttpSession) Calendar(java.util.Calendar) AuthenticationProvider(uk.ac.cam.cl.dtg.segue.auth.AuthenticationProvider) HttpServletResponse(javax.servlet.http.HttpServletResponse) IOAuth2Authenticator(uk.ac.cam.cl.dtg.segue.auth.IOAuth2Authenticator) Date(java.util.Date) RegisteredUser(uk.ac.cam.cl.dtg.isaac.dos.users.RegisteredUser) HttpServletRequest(javax.servlet.http.HttpServletRequest) EmailTemplateDTO(uk.ac.cam.cl.dtg.isaac.dto.content.EmailTemplateDTO) RegisteredUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO) UserFromAuthProvider(uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider) AnonymousUser(uk.ac.cam.cl.dtg.isaac.dos.users.AnonymousUser) AnonymousUserDTO(uk.ac.cam.cl.dtg.isaac.dto.users.AnonymousUserDTO) Test(org.junit.Test)

Example 5 with UserFromAuthProvider

use of uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider in project isaac-api by isaacphysics.

the class GoogleAuthenticator method getUserInfo.

@Override
public synchronized UserFromAuthProvider getUserInfo(final String internalProviderReference) throws NoUserException, AuthenticatorSecurityException {
    Credential credentials = credentialStore.getIfPresent(internalProviderReference);
    if (verifyAccessTokenIsValid(credentials)) {
        log.debug("Successful Verification of access token with provider.");
    } else {
        log.error("Unable to verify access token - it could be an indication of fraud.");
        throw new AuthenticatorSecurityException("Access token is invalid - the client id returned by the identity provider does not match ours.");
    }
    Oauth2 userInfoService = new Oauth2.Builder(new NetHttpTransport(), new JacksonFactory(), credentials).setApplicationName(Constants.APPLICATION_NAME).build();
    Userinfo userInfo = null;
    try {
        userInfo = userInfoService.userinfo().get().execute();
        log.debug("Retrieved User info from google: " + userInfo.toPrettyString());
    } catch (IOException e) {
        log.error("An IO error occurred while trying to retrieve user information: " + e);
    }
    if (userInfo != null && userInfo.getId() != null) {
        EmailVerificationStatus emailStatus = userInfo.isVerifiedEmail() ? EmailVerificationStatus.VERIFIED : EmailVerificationStatus.NOT_VERIFIED;
        String email = userInfo.getEmail();
        if (null == email) {
            email = userInfo.getId() + "-google";
            emailStatus = EmailVerificationStatus.DELIVERY_FAILED;
            log.warn("No email address provided by Google! Using (" + email + ") instead");
        }
        return new UserFromAuthProvider(userInfo.getId(), userInfo.getGivenName(), userInfo.getFamilyName(), email, emailStatus, null, null, null);
    } else {
        throw new NoUserException("No user could be created from provider details!");
    }
}
Also used : Credential(com.google.api.client.auth.oauth2.Credential) AuthenticatorSecurityException(uk.ac.cam.cl.dtg.segue.auth.exceptions.AuthenticatorSecurityException) NetHttpTransport(com.google.api.client.http.javanet.NetHttpTransport) UserFromAuthProvider(uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider) Oauth2(com.google.api.services.oauth2.Oauth2) CacheBuilder(com.google.common.cache.CacheBuilder) NoUserException(uk.ac.cam.cl.dtg.segue.auth.exceptions.NoUserException) Userinfo(com.google.api.services.oauth2.model.Userinfo) IOException(java.io.IOException) EmailVerificationStatus(uk.ac.cam.cl.dtg.isaac.dos.users.EmailVerificationStatus) JacksonFactory(com.google.api.client.json.jackson2.JacksonFactory)

Aggregations

UserFromAuthProvider (uk.ac.cam.cl.dtg.isaac.dos.users.UserFromAuthProvider)6 Credential (com.google.api.client.auth.oauth2.Credential)3 IOException (java.io.IOException)3 EmailVerificationStatus (uk.ac.cam.cl.dtg.isaac.dos.users.EmailVerificationStatus)3 NoUserException (uk.ac.cam.cl.dtg.segue.auth.exceptions.NoUserException)3 RegisteredUser (uk.ac.cam.cl.dtg.isaac.dos.users.RegisteredUser)2 RegisteredUserDTO (uk.ac.cam.cl.dtg.isaac.dto.users.RegisteredUserDTO)2 AuthenticationProvider (uk.ac.cam.cl.dtg.segue.auth.AuthenticationProvider)2 IAuthenticator (uk.ac.cam.cl.dtg.segue.auth.IAuthenticator)2 AuthenticatorSecurityException (uk.ac.cam.cl.dtg.segue.auth.exceptions.AuthenticatorSecurityException)2 GenericUrl (com.google.api.client.http.GenericUrl)1 NetHttpTransport (com.google.api.client.http.javanet.NetHttpTransport)1 JacksonFactory (com.google.api.client.json.jackson2.JacksonFactory)1 Oauth2 (com.google.api.services.oauth2.Oauth2)1 Userinfo (com.google.api.services.oauth2.model.Userinfo)1 CacheBuilder (com.google.common.cache.CacheBuilder)1 Calendar (java.util.Calendar)1 Date (java.util.Date)1 HashMap (java.util.HashMap)1 Cookie (javax.servlet.http.Cookie)1