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;
}
}
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;
}
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!");
}
}
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);
}
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!");
}
}
Aggregations