From 30afb243df2f8f9e647ed5b27da7b8a11cc549d0 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Tue, 22 Nov 2016 11:16:34 -0500 Subject: [PATCH] centralize canLogInAsBuiltinUser method #3338 --- .../java/edu/harvard/iq/dataverse/Shib.java | 2 +- .../edu/harvard/iq/dataverse/api/Admin.java | 4 +- .../AuthenticationServiceBean.java | 98 +++++++++++++++++-- .../providers/shib/ShibServiceBean.java | 82 ---------------- 4 files changed, 94 insertions(+), 92 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/Shib.java b/src/main/java/edu/harvard/iq/dataverse/Shib.java index 0fbf2929dfa..9945d10c916 100644 --- a/src/main/java/edu/harvard/iq/dataverse/Shib.java +++ b/src/main/java/edu/harvard/iq/dataverse/Shib.java @@ -315,7 +315,7 @@ public String confirmAndConvertAccount() { String lookupStringPerAuthProvider = userPersistentId; UserIdentifier userIdentifier = new UserIdentifier(lookupStringPerAuthProvider, internalUserIdentifer); logger.fine("builtin username: " + builtinUsername); - AuthenticatedUser builtInUserToConvert = shibService.canLogInAsBuiltinUser(builtinUsername, builtinPassword); + AuthenticatedUser builtInUserToConvert = authSvc.canLogInAsBuiltinUser(builtinUsername, builtinPassword); if (builtInUserToConvert != null) { AuthenticatedUser au = authSvc.convertBuiltInToShib(builtInUserToConvert, shibAuthProvider.getId(), userIdentifier); if (au != null) { diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index ed952471f5c..dbc231f03c8 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -451,7 +451,7 @@ public Response builtin2shib(String content) { if (oldBuiltInUser != null) { String usernameOfBuiltinAccountToConvert = oldBuiltInUser.getUserName(); response.add("old username", usernameOfBuiltinAccountToConvert); - AuthenticatedUser authenticatedUser = shibService.canLogInAsBuiltinUser(usernameOfBuiltinAccountToConvert, password); + AuthenticatedUser authenticatedUser = authSvc.canLogInAsBuiltinUser(usernameOfBuiltinAccountToConvert, password); if (authenticatedUser != null) { knowsExistingPassword = true; AuthenticatedUser convertedUser = authSvc.convertBuiltInToShib(builtInUserToConvert, shibProviderId, newUserIdentifierInLookupTable); @@ -597,7 +597,7 @@ public Response builtin2oauth(String content) { if (oldBuiltInUser != null) { String usernameOfBuiltinAccountToConvert = oldBuiltInUser.getUserName(); response.add("old username", usernameOfBuiltinAccountToConvert); - AuthenticatedUser authenticatedUser = shibService.canLogInAsBuiltinUser(usernameOfBuiltinAccountToConvert, password); + AuthenticatedUser authenticatedUser = authSvc.canLogInAsBuiltinUser(usernameOfBuiltinAccountToConvert, password); if (authenticatedUser != null) { knowsExistingPassword = true; AuthenticatedUser convertedUser = authSvc.convertBuiltInUserToRemoteUser(builtInUserToConvert, newProviderId, newUserIdentifierInLookupTable); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java index 9319966a8fc..74506f93c38 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java @@ -13,6 +13,7 @@ import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProviderFactory; import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUser; import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUserServiceBean; +import edu.harvard.iq.dataverse.authorization.providers.builtin.PasswordEncryption; import edu.harvard.iq.dataverse.authorization.providers.echo.EchoAuthenticationProviderFactory; import edu.harvard.iq.dataverse.authorization.providers.oauth2.AbstractOAuth2AuthenticationProvider; import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2AuthenticationProviderFactory; @@ -23,6 +24,7 @@ import edu.harvard.iq.dataverse.confirmemail.ConfirmEmailServiceBean; import edu.harvard.iq.dataverse.passwordreset.PasswordResetData; import edu.harvard.iq.dataverse.passwordreset.PasswordResetServiceBean; +import edu.harvard.iq.dataverse.util.BundleUtil; import java.sql.Timestamp; import java.util.Calendar; import java.util.Collection; @@ -624,7 +626,7 @@ public AuthenticatedUser convertBuiltInToShib(AuthenticatedUser builtInUserToCon String builtinUsername = builtInUserIdentifier.replaceFirst(AuthenticatedUser.IDENTIFIER_PREFIX, ""); BuiltinUser builtin = builtinUserServiceBean.findByUserName(builtinUsername); if (builtin != null) { - // These were created by AuthenticationResponse.Status.BREAKOUT in ShibServiceBean.canLogInAsBuiltinUser + // These were created by AuthenticationResponse.Status.BREAKOUT in canLogInAsBuiltinUser List oldTokens = passwordResetServiceBean.findPasswordResetDataByDataverseUser(builtin); for (PasswordResetData oldToken : oldTokens) { em.remove(oldToken); @@ -662,8 +664,8 @@ public AuthenticatedUser convertBuiltInUserToRemoteUser(AuthenticatedUser builtI authuserLookup.setAuthenticationProviderId(newProviderId); String oldUserLookupIdentifier = authuserLookup.getPersistentUserId(); logger.info("this should be 'pete' or whatever the old builtin username was: " + oldUserLookupIdentifier); - String perUserShibIdentifier = newUserIdentifierInLookupTable.getLookupStringPerAuthProvider(); - authuserLookup.setPersistentUserId(perUserShibIdentifier); + String perUserIdentifier = newUserIdentifierInLookupTable.getLookupStringPerAuthProvider(); + authuserLookup.setPersistentUserId(perUserIdentifier); /** * @todo this should be a transaction of some kind. We want to update * the authenticateduserlookup and also delete the row from the @@ -673,7 +675,7 @@ public AuthenticatedUser convertBuiltInUserToRemoteUser(AuthenticatedUser builtI String builtinUsername = builtInUserIdentifier.replaceFirst(AuthenticatedUser.IDENTIFIER_PREFIX, ""); BuiltinUser builtin = builtinUserServiceBean.findByUserName(builtinUsername); if (builtin != null) { - // These were created by AuthenticationResponse.Status.BREAKOUT in ShibServiceBean.canLogInAsBuiltinUser + // These were created by AuthenticationResponse.Status.BREAKOUT in canLogInAsBuiltinUser List oldTokens = passwordResetServiceBean.findPasswordResetDataByDataverseUser(builtin); for (PasswordResetData oldToken : oldTokens) { em.remove(oldToken); @@ -682,7 +684,7 @@ public AuthenticatedUser convertBuiltInUserToRemoteUser(AuthenticatedUser builtI } else { logger.info("Couldn't delete builtin user because could find it based on username " + builtinUsername); } - AuthenticatedUser nonBuiltinUser = lookupUser(newProviderId, perUserShibIdentifier); + AuthenticatedUser nonBuiltinUser = lookupUser(newProviderId, perUserIdentifier); if (nonBuiltinUser != null) { return nonBuiltinUser; } @@ -690,8 +692,8 @@ public AuthenticatedUser convertBuiltInUserToRemoteUser(AuthenticatedUser builtI } /** - * @param idOfAuthUserToConvert The id of the AuthenticatedUser (Shibboleth - * user) to convert to a BuiltinUser. + * @param idOfAuthUserToConvert The id of the remote AuthenticatedUser + * (Shibboleth user or OAuth user) to convert to a BuiltinUser. * @param newEmailAddress The new email address that will be used instead of * the user's old email address from the institution that they have left. * @return BuiltinUser @@ -750,4 +752,86 @@ public BuiltinUser convertRemoteToBuiltIn(Long idOfAuthUserToConvert, String new return builtinUser; } + public AuthenticatedUser canLogInAsBuiltinUser(String username, String password) { + logger.fine("checking to see if " + username + " knows the password..."); + if (password == null) { + logger.info("password was null"); + return null; + } + + AuthenticationRequest authReq = new AuthenticationRequest(); + /** + * @todo Should this really be coming from a bundle like this? Added + * because that's what BuiltinAuthenticationProvider does. + */ + authReq.putCredential(BundleUtil.getStringFromBundle("login.builtin.credential.usernameOrEmail"), username); + authReq.putCredential(BundleUtil.getStringFromBundle("login.builtin.credential.password"), password); + /** + * @todo Should probably set IP address here. + */ +// authReq.setIpAddress(session.getUser().getRequestMetadata().getIpAddress()); + + String credentialsAuthProviderId = BuiltinAuthenticationProvider.PROVIDER_ID; + try { + AuthenticatedUser au = authenticate(credentialsAuthProviderId, authReq); + logger.fine("User authenticated:" + au.getEmail()); + return au; + } catch (AuthenticationFailedException ex) { + logger.info("The username and/or password entered is invalid: " + ex.getResponse().getMessage()); + if (AuthenticationResponse.Status.BREAKOUT.equals(ex.getResponse().getStatus())) { + /** + * Note that this "BREAKOUT" status creates PasswordResetData! + * We'll delete it just before blowing away the BuiltinUser in + * AuthenticationServiceBean.convertBuiltInToShib + */ + logger.info("AuthenticationFailedException caught in canLogInAsBuiltinUser: The username and/or password entered is invalid: " + ex.getResponse().getMessage() + " - Maybe the user (" + username + ") hasn't upgraded their password? Checking the old password..."); + BuiltinUser builtinUser = builtinUserServiceBean.findByUsernameOrEmail(username); + if (builtinUser != null) { + boolean userAuthenticated = PasswordEncryption.getVersion(builtinUser.getPasswordEncryptionVersion()).check(password, builtinUser.getEncryptedPassword()); + if (userAuthenticated == true) { + AuthenticatedUser authUser = lookupUser(BuiltinAuthenticationProvider.PROVIDER_ID, builtinUser.getUserName()); + if (authUser != null) { + return authUser; + } else { + logger.info("canLogInAsBuiltinUser: Couldn't find AuthenticatedUser based on BuiltinUser username " + builtinUser.getUserName()); + } + } else { + logger.info("canLogInAsBuiltinUser: User doesn't know old pre-bcrypt password either."); + } + } else { + logger.info("canLogInAsBuiltinUser: Couldn't run `check` because no BuiltinUser found with username " + username); + } + } + return null; + } catch (EJBException ex) { + Throwable cause = ex; + StringBuilder sb = new StringBuilder(); + sb.append(ex + " "); + while (cause.getCause() != null) { + cause = cause.getCause(); + sb.append(cause.getClass().getCanonicalName() + " "); + sb.append(cause.getMessage()).append(" "); + /** + * @todo Investigate why authSvc.authenticate is throwing + * NullPointerException. If you convert a Shib user or an OAuth + * user to a Builtin user, the password will be null. + */ + if (cause instanceof NullPointerException) { + for (int i = 0; i < 2; i++) { + StackTraceElement stacktrace = cause.getStackTrace()[i]; + if (stacktrace != null) { + String classCanonicalName = stacktrace.getClass().getCanonicalName(); + String methodName = stacktrace.getMethodName(); + int lineNumber = stacktrace.getLineNumber(); + String error = "at " + stacktrace.getClassName() + "." + stacktrace.getMethodName() + "(" + stacktrace.getFileName() + ":" + lineNumber + ") "; + sb.append(error); + } + } + } + } + logger.info("When trying to validate password, exception calling authSvc.authenticate: " + sb.toString()); + return null; + } + } + } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibServiceBean.java index 82a6f775ad5..ca247d0c9c2 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/shib/ShibServiceBean.java @@ -160,88 +160,6 @@ public BuiltinUser findBuiltInUserByAuthUserIdentifier(String authUserIdentifier return builtinUserService.findByUserName(authUserIdentifier); } - public AuthenticatedUser canLogInAsBuiltinUser(String username, String password) { - logger.fine("checking to see if " + username + " knows the password..."); - if (password == null) { - logger.info("password was null"); - return null; - } - - AuthenticationRequest authReq = new AuthenticationRequest(); - /** - * @todo Should this really be coming from a bundle like this? Added - * because that's what BuiltinAuthenticationProvider does. - */ - authReq.putCredential(BundleUtil.getStringFromBundle("login.builtin.credential.usernameOrEmail"), username); - authReq.putCredential(BundleUtil.getStringFromBundle("login.builtin.credential.password"), password); - /** - * @todo Should probably set IP address here. - */ -// authReq.setIpAddress(session.getUser().getRequestMetadata().getIpAddress()); - - String credentialsAuthProviderId = BuiltinAuthenticationProvider.PROVIDER_ID; - try { - AuthenticatedUser au = authSvc.authenticate(credentialsAuthProviderId, authReq); - logger.fine("User authenticated:" + au.getEmail()); - return au; - } catch (AuthenticationFailedException ex) { - logger.info("The username and/or password entered is invalid: " + ex.getResponse().getMessage()); - if (AuthenticationResponse.Status.BREAKOUT.equals(ex.getResponse().getStatus())) { - /** - * Note that this "BREAKOUT" status creates PasswordResetData! - * We'll delete it just before blowing away the BuiltinUser in - * AuthenticationServiceBean.convertBuiltInToShib - */ - logger.info("AuthenticationFailedException caught in canLogInAsBuiltinUser: The username and/or password entered is invalid: " + ex.getResponse().getMessage() + " - Maybe the user (" + username + ") hasn't upgraded their password? Checking the old password..."); - BuiltinUser builtinUser = builtinUserService.findByUsernameOrEmail(username); - if (builtinUser != null) { - boolean userAuthenticated = PasswordEncryption.getVersion(builtinUser.getPasswordEncryptionVersion()).check(password, builtinUser.getEncryptedPassword()); - if (userAuthenticated == true) { - AuthenticatedUser authUser = authSvc.lookupUser(BuiltinAuthenticationProvider.PROVIDER_ID, builtinUser.getUserName()); - if (authUser != null) { - return authUser; - } else { - logger.info("canLogInAsBuiltinUser: Couldn't find AuthenticatedUser based on BuiltinUser username " + builtinUser.getUserName()); - } - } else { - logger.info("canLogInAsBuiltinUser: User doesn't know old pre-bcrypt password either."); - } - } else { - logger.info("canLogInAsBuiltinUser: Couldn't run `check` because no BuiltinUser found with username " + username); - } - } - return null; - } catch (EJBException ex) { - Throwable cause = ex; - StringBuilder sb = new StringBuilder(); - sb.append(ex + " "); - while (cause.getCause() != null) { - cause = cause.getCause(); - sb.append(cause.getClass().getCanonicalName() + " "); - sb.append(cause.getMessage()).append(" "); - /** - * @todo Investigate why authSvc.authenticate is throwing - * NullPointerException. If you convert a Shib user to a Builtin - * user, the password may be null. - */ - if (cause instanceof NullPointerException) { - for (int i = 0; i < 2; i++) { - StackTraceElement stacktrace = cause.getStackTrace()[i]; - if (stacktrace != null) { - String classCanonicalName = stacktrace.getClass().getCanonicalName(); - String methodName = stacktrace.getMethodName(); - int lineNumber = stacktrace.getLineNumber(); - String error = "at " + stacktrace.getClassName() + "." + stacktrace.getMethodName() + "(" + stacktrace.getFileName() + ":" + lineNumber + ") "; - sb.append(error); - } - } - } - } - logger.info("When trying to validate password, exception calling authSvc.authenticate: " + sb.toString()); - return null; - } - } - public String getAffiliation(String shibIdp, DevShibAccountType devShibAccountType) { JsonArray emptyJsonArray = new JsonArray(); String discoFeedJson = emptyJsonArray.toString();