From c64fd62250ab52a5b385632bb8930ce45625ec14 Mon Sep 17 00:00:00 2001 From: Michael Bar-Sinai Date: Sat, 22 Oct 2016 00:41:52 +0300 Subject: [PATCH] Rewrite of AuthenticatedUser and its provider hierarchy to query providr capability capability rather than look at classes. Refactoring of the DataverseUserPage to adjust itself to the capabilities of the current user's provider. --- .../update-user-account-info.puml | 28 ++ src/main/java/Bundle.properties | 2 + .../GuestbookResponseServiceBean.java | 35 -- .../iq/dataverse/ManageGuestbooksPage.java | 5 - .../AuthenticatedUserDisplayInfo.java | 8 + .../authorization/AuthenticationProvider.java | 59 ++- .../AuthenticationServiceBean.java | 35 +- .../RoleAssigneeDisplayInfo.java | 9 +- .../dataverse/authorization/UserLister.java | 10 - .../BuiltinAuthenticationProvider.java | 100 ++-- .../providers/builtin/BuiltinUser.java | 15 + .../builtin/BuiltinUserServiceBean.java | 19 +- ...inUserPage.java => DataverseUserPage.java} | 475 ++++++++---------- .../providers/builtin/PasswordEncryption.java | 10 +- .../AbstractOAuth2AuthenticationProvider.java | 14 +- .../oauth2/OAuth2FirstLoginPage.java | 2 +- .../oauth2/OAuth2LoginBackingBean.java | 5 - .../users/AuthenticatedUser.java | 14 +- .../authorization/users/GuestUser.java | 5 - .../authorization/users/PrivateUrlUser.java | 9 +- .../dataverse/authorization/users/User.java | 5 - .../confirmemail/ConfirmEmailServiceBean.java | 8 +- .../confirmemail/ConfirmEmailUtil.java | 21 +- src/main/webapp/dataverseuser.xhtml | 56 ++- .../BuiltinAuthenticationProviderTest.java | 115 +++++ .../confirmemail/ConfirmEmailUtilTest.java | 32 +- .../impl/CreatePrivateUrlCommandTest.java | 1 - .../mocks/MockBuiltinUserServiceBean.java | 37 ++ .../iq/dataverse/mocks/MocksFactory.java | 8 +- 29 files changed, 649 insertions(+), 493 deletions(-) create mode 100644 doc/Architecture/update-user-account-info.puml delete mode 100644 src/main/java/edu/harvard/iq/dataverse/authorization/UserLister.java rename src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/{BuiltinUserPage.java => DataverseUserPage.java} (69%) create mode 100644 src/test/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinAuthenticationProviderTest.java create mode 100644 src/test/java/edu/harvard/iq/dataverse/mocks/MockBuiltinUserServiceBean.java diff --git a/doc/Architecture/update-user-account-info.puml b/doc/Architecture/update-user-account-info.puml new file mode 100644 index 00000000000..30da04c6e9f --- /dev/null +++ b/doc/Architecture/update-user-account-info.puml @@ -0,0 +1,28 @@ +@startuml +actor user +participant DataverseUserPage as page +participant "provider: AuthenticationProvider" as prv +participant AuthenticationServiceBean as authSvc +user --> page: HTTP GET +== page init == +... +page -> authSvc : lookupProvider(session.user) +activate authSvc +page <-- authSvc: provider +deactivate authSvc +... + +== Can Update User? == +page -> prv: isUserInfoUpdateAllowed() +activate prv +page <-- prv: true/false +deactivate prv +... + +== Save User == +user --> page: save() +page -> page: udi = createUserDisplayInfo() +page -> prv: updateUserInfo( udi ) +page -> authSvc: updateAuthentictedUser( session.user, udi ) + +@enduml diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 85f00219fe4..ea1764dcbc1 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -206,6 +206,8 @@ login.builtin.credential.password=Password login.builtin.invalidUsernameEmailOrPassword=The username, email address, or password you entered is invalid. Need assistance accessing your account? # how do we exercise login.error? Via a password upgrade failure? See https://github.com/IQSS/dataverse/pull/2922 login.error=Error validating the username, email address, or password. Please try again. If the problem persists, contact an administrator. +user.error.cannotChangePassword=Sorry, your password cannot be changed. Please contact your system administrator. +user.error.wrongPassword=Sorry, wrong password. #confirmemail.xhtml confirmEmail.pageTitle=Email Verification diff --git a/src/main/java/edu/harvard/iq/dataverse/GuestbookResponseServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/GuestbookResponseServiceBean.java index 23a33b0cbf6..e9a26d808bb 100644 --- a/src/main/java/edu/harvard/iq/dataverse/GuestbookResponseServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/GuestbookResponseServiceBean.java @@ -363,15 +363,6 @@ public String getUserName(User user) { AuthenticatedUser authUser = (AuthenticatedUser) user; return authUser.getName(); } - - try { - if (user.isBuiltInUser()) { - BuiltinUser builtinUser = (BuiltinUser) user; - return builtinUser.getDisplayName(); - } - } catch (Exception e) { - return ""; - } return "Guest"; } @@ -380,14 +371,6 @@ public String getUserEMail(User user) { AuthenticatedUser authUser = (AuthenticatedUser) user; return authUser.getEmail(); } - try { - if (user.isBuiltInUser()) { - BuiltinUser builtinUser = (BuiltinUser) user; - return builtinUser.getEmail(); - } - } catch (Exception e) { - return ""; - } return ""; } @@ -396,15 +379,6 @@ public String getUserInstitution(User user) { AuthenticatedUser authUser = (AuthenticatedUser) user; return authUser.getAffiliation(); } - - try { - if (user.isBuiltInUser()) { - BuiltinUser builtinUser = (BuiltinUser) user; - return builtinUser.getAffiliation(); - } - } catch (Exception e) { - return ""; - } return ""; } @@ -413,15 +387,6 @@ public String getUserPosition(User user) { AuthenticatedUser authUser = (AuthenticatedUser) user; return authUser.getPosition(); } - try { - if (user.isBuiltInUser()) { - BuiltinUser builtinUser = (BuiltinUser) user; - return builtinUser.getPosition(); - } - } catch (Exception e) { - return ""; - } - return ""; } diff --git a/src/main/java/edu/harvard/iq/dataverse/ManageGuestbooksPage.java b/src/main/java/edu/harvard/iq/dataverse/ManageGuestbooksPage.java index 320a16e013c..1dd5712cbcd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/ManageGuestbooksPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/ManageGuestbooksPage.java @@ -1,8 +1,3 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package edu.harvard.iq.dataverse; import edu.harvard.iq.dataverse.engine.command.exception.CommandException; diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticatedUserDisplayInfo.java b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticatedUserDisplayInfo.java index a18f7af0b03..08c11702ffa 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticatedUserDisplayInfo.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticatedUserDisplayInfo.java @@ -22,6 +22,14 @@ public AuthenticatedUserDisplayInfo(String firstName, String lastName, String em this.lastName = lastName; this.position = position; } + + public AuthenticatedUserDisplayInfo() { + super("","",""); + firstName=""; + lastName=""; + position=""; + } + /** * Copy constructor (old school!) diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationProvider.java b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationProvider.java index 41a6477cd09..1b7cc87b702 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationProvider.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationProvider.java @@ -3,8 +3,12 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; /** - * Objects that can authenticate users - for credentials, they provide persistent user id that can be used to - * lookup an {@link AuthenticatedUser} using {@link AuthenticatedUserLookup} objects. + * Objects that can authenticate users. The authentication process yields a unique + * identifier for the user in the user directory this provider represents. + * + * Providers can have optional functionalities, such as updating user data and verifying email addresses. This abilities + * can be queried using the {@code isXXXAllowed()} methods. If an implementation returns {@code true} + * from one of these methods, it has to implement the matching methods. * * {@code AuthenticationPrvider}s are normally registered at startup in {@link AuthenticationServiceBean#startup()}. * @@ -15,5 +19,54 @@ public interface AuthenticationProvider { String getId(); AuthenticationProviderDisplayInfo getInfo(); - + + default boolean isPasswordUpdateAllowed() { return false; }; + default boolean isUserInfoUpdateAllowed() { return false; }; + default boolean isUserDeletionAllowed() { return false; }; + + /** + * Some providers (e.g organizational ones) provide verified email addresses. + * @return {@code true} if we can treat email addresses coming from this provider as verified, {@code false} otherwise. + */ + default boolean isEmailVerified() { return false; }; + + /** + * Updates the password of the user whose id is passed. + * @param userIdInProvider User id in the provider. NOT the {@link AuthenticatedUser#id}, which is internal to the installation. + * @param newPassword password, in clear text + * @throws UnsupportedOperationException if the provider does not support updating passwords. + * @see #isPasswordUpdateAllowed() + */ + default void updatePassword( String userIdInProvider, String newPassword ) { + throw new UnsupportedOperationException(this.toString() + " does not implement password updates"); + }; + + /** + * Verifies that the passed password matches the user's. Note that this method is has tri-state return + * value ({@link Boolean} rather than a {@code boolean}). A {@code null} returned means that the user + * was not found. + * @param userIdInProvider User id in the provider. NOT the {@link AuthenticatedUser#id}, which is internal to the installation. + * @param password The password string we test + * @return {@code True} if the passwords match; {@code False} if they don't; {@code null} if the user was not found. + * @throws UnsupportedOperationException if the provider does not support updating passwords. + * @see #isPasswordUpdateAllowed() + */ + default Boolean verifyPassword( String userIdInProvider, String password ) { + throw new UnsupportedOperationException(this.toString() + " does not implement password updates"); + }; + + /** + * Updates the password of the user whose id is passed. + * @param userIdInProvider User id in the provider. NOT the {@link AuthenticatedUser#id}, which is internal to the installation. + * @param updatedUserData + * @throws UnsupportedOperationException + * @see #isUserInfoUpdateAllowed() + */ + default void updateUserInfo( String userIdInProvider, AuthenticatedUserDisplayInfo updatedUserData ) { + throw new UnsupportedOperationException(this.toString() + " does not implement account detail updates"); + }; + + default void deleteUser( String userIdInProvider ) { + throw new UnsupportedOperationException(this.toString() + " does not implement account deletions"); + } } 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 cc5051502fb..ed5b55907ac 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java @@ -100,9 +100,8 @@ public void startup() { registerProviderFactory( new BuiltinAuthenticationProviderFactory(builtinUserServiceBean) ); registerProviderFactory( new EchoAuthenticationProviderFactory() ); registerProviderFactory( new OAuth2AuthenticationProviderFactory() ); - /** - * Register shib provider factory here. Test enable/disable via Admin API, etc. - */ + + // Register shib provider factory here. Test enable/disable via Admin API, etc. new ShibAuthenticationProvider(); } catch (AuthorizationSetupException ex) { logger.log(Level.SEVERE, "Exception setting up the authentication provider factories: " + ex.getMessage(), ex); @@ -254,13 +253,13 @@ public void deleteAuthenticatedUser(Object pk) { */ em.remove(confirmEmailData); } - for (UserNotification notification : userNotificationService.findByUser(user.getId())) { - userNotificationService.delete(notification); - } - if (user.isBuiltInUser()) { - BuiltinUser builtin = builtinUserServiceBean.findByUserName(user.getUserIdentifier()); - em.remove(builtin); + userNotificationService.findByUser(user.getId()).forEach(userNotificationService::delete); + + AuthenticationProvider prv = lookupProvider(user); + if ( prv != null && prv.isUserDeletionAllowed() ) { + prv.deleteUser(user.getAuthenticatedUserLookup().getPersistentUserId()); } + actionLogSvc.log( new ActionLogRecord(ActionLogRecord.ActionType.Auth, "deleteUser") .setInfo(user.getUserIdentifier())); em.remove(user.getAuthenticatedUserLookup()); @@ -330,7 +329,11 @@ public AuthenticatedUser authenticate( String authenticationProviderId, Authenti } } - public boolean isEmailAvailable(String email) { + /** + * @param email + * @return {@code true} iff the none of the authenticated users has the passed email address. + */ + public boolean isEmailAddressAvailable(String email) { return em.createNamedQuery("AuthenticatedUser.findByEmail", AuthenticatedUser.class) .setParameter("email", email) .getResultList().isEmpty(); @@ -352,6 +355,10 @@ public AuthenticatedUser lookupUser(String authPrvId, String userPersistentId) { } } + public AuthenticationProvider lookupProvider( AuthenticatedUser user ) { + return authenticationProviders.get(user.getAuthenticatedUserLookup().getAuthenticationProviderId()); + } + public ApiToken findApiToken(String token) { try { return em.createNamedQuery("ApiToken.findByTokenString", ApiToken.class) @@ -362,8 +369,6 @@ public ApiToken findApiToken(String token) { } } - - public ApiToken findApiTokenByUser(AuthenticatedUser au) { if (au == null) { return null; @@ -525,10 +530,14 @@ public AuthenticatedUser createAuthenticatedUser(UserRecordIdentifier userRecord actionLogSvc.log( new ActionLogRecord(ActionLogRecord.ActionType.Auth, "createUser") .setInfo(authenticatedUser.getIdentifier())); - return authenticatedUser; } + /** + * Checks whether the {@code idtf} is already taken by another {@link AuthenticatedUser}. + * @param idtf + * @return {@code true} iff there's already a user by that username. + */ public boolean identifierExists( String idtf ) { return em.createNamedQuery("AuthenticatedUser.countOfIdentifier", Number.class) .setParameter("identifier", idtf) diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/RoleAssigneeDisplayInfo.java b/src/main/java/edu/harvard/iq/dataverse/authorization/RoleAssigneeDisplayInfo.java index 97dc4f0b83e..821d707ce92 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/RoleAssigneeDisplayInfo.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/RoleAssigneeDisplayInfo.java @@ -35,19 +35,16 @@ public String getAffiliation() { return affiliation; } - public RoleAssigneeDisplayInfo setTitle(String title) { + public void setTitle(String title) { this.title = title; - return this; } - public RoleAssigneeDisplayInfo setEmailAddress(String emailAddress) { + public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; - return this; } - public RoleAssigneeDisplayInfo setAffiliation(String affiliation) { + public void setAffiliation(String affiliation) { this.affiliation = affiliation; - return this; } @Override diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/UserLister.java b/src/main/java/edu/harvard/iq/dataverse/authorization/UserLister.java deleted file mode 100644 index ccf6323ce08..00000000000 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/UserLister.java +++ /dev/null @@ -1,10 +0,0 @@ -package edu.harvard.iq.dataverse.authorization; - -import edu.harvard.iq.dataverse.authorization.users.User; -import java.util.List; - -public interface UserLister { - - public List listUsers(); - -} diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinAuthenticationProvider.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinAuthenticationProvider.java index 83fec85023f..b9fad9aebae 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinAuthenticationProvider.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinAuthenticationProvider.java @@ -1,22 +1,15 @@ package edu.harvard.iq.dataverse.authorization.providers.builtin; -import edu.harvard.iq.dataverse.DvObject; +import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.authorization.AuthenticationProviderDisplayInfo; import edu.harvard.iq.dataverse.authorization.AuthenticationRequest; import edu.harvard.iq.dataverse.authorization.AuthenticationResponse; import edu.harvard.iq.dataverse.authorization.CredentialsAuthenticationProvider; -import edu.harvard.iq.dataverse.authorization.UserLister; -import edu.harvard.iq.dataverse.authorization.groups.GroupProvider; -import edu.harvard.iq.dataverse.authorization.users.User; import java.util.Arrays; import java.util.List; import static edu.harvard.iq.dataverse.authorization.CredentialsAuthenticationProvider.Credential; -import edu.harvard.iq.dataverse.authorization.RoleAssignee; -import edu.harvard.iq.dataverse.authorization.groups.Group; -import edu.harvard.iq.dataverse.engine.command.DataverseRequest; import edu.harvard.iq.dataverse.passwordreset.PasswordResetException; import edu.harvard.iq.dataverse.util.BundleUtil; -import java.util.Set; /** * An authentication provider built into the application. Uses JPA and the @@ -24,7 +17,7 @@ * * @author michael */ -public class BuiltinAuthenticationProvider implements CredentialsAuthenticationProvider, UserLister, GroupProvider { +public class BuiltinAuthenticationProvider implements CredentialsAuthenticationProvider { public static final String PROVIDER_ID = "builtin"; private static String KEY_USERNAME_OR_EMAIL; @@ -40,11 +33,6 @@ public BuiltinAuthenticationProvider( BuiltinUserServiceBean aBean ) { CREDENTIALS_LIST = Arrays.asList(new Credential(KEY_USERNAME_OR_EMAIL), new Credential(KEY_PASSWORD, true)); } - @Override - public List listUsers() { - throw new UnsupportedOperationException("Not supported yet."); - } - @Override public String getId() { return PROVIDER_ID; @@ -55,6 +43,61 @@ public AuthenticationProviderDisplayInfo getInfo() { return new AuthenticationProviderDisplayInfo(getId(), "Build-in Provider", "Internal user repository"); } + @Override + public boolean isPasswordUpdateAllowed() { + return true; + } + + @Override + public boolean isUserInfoUpdateAllowed() { + return true; + } + + @Override + public boolean isUserDeletionAllowed() { + return true; + } + + @Override + public void deleteUser(String userIdInProvider) { + bean.removeUser(userIdInProvider); + } + + @Override + public void updatePassword(String userIdInProvider, String newPassword) { + BuiltinUser biUser = bean.findByUserName( userIdInProvider ); + biUser.updateEncryptedPassword(PasswordEncryption.get().encrypt(newPassword), + PasswordEncryption.getLatestVersionNumber()); + bean.save(biUser); + } + + @Override + public void updateUserInfo(String userIdInProvider, AuthenticatedUserDisplayInfo updatedUserData) { + BuiltinUser biUser = bean.findByUserName( userIdInProvider ); + biUser.setFirstName(updatedUserData.getFirstName()); + biUser.setLastName(updatedUserData.getLastName()); + biUser.setEmail( updatedUserData.getEmailAddress()); + biUser.setAffiliation( updatedUserData.getAffiliation() ); + biUser.setPosition(updatedUserData.getPosition()); + + bean.save(biUser); + } + + /** + * Validates that the passed password is indeed the password of the user. + * @param userIdInProvider + * @param password + * @return {@code true} if the password matches the user's password; {@code false} otherwise. + */ + @Override + public Boolean verifyPassword( String userIdInProvider, String password ) { + BuiltinUser biUser = bean.findByUserName( userIdInProvider ); + if ( biUser == null ) return null; + return PasswordEncryption.getVersion(biUser.getPasswordEncryptionVersion()) + .check(password, biUser.getEncryptedPassword()); + } + + @Override public AuthenticationResponse authenticate( AuthenticationRequest authReq ) { BuiltinUser u = bean.findByUsernameOrEmail(authReq.getCredential(KEY_USERNAME_OR_EMAIL) ); @@ -85,33 +128,4 @@ public List getRequiredCredentials() { return CREDENTIALS_LIST; } - @Override - public String getGroupProviderAlias() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public String getGroupProviderInfo() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Set groupsFor(RoleAssignee u, DvObject o) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Set groupsFor(DataverseRequest u, DvObject o) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Group get(String groupAlias) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public Set findGlobalGroups() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUser.java index 15aac6772f1..244f3828753 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUser.java @@ -2,6 +2,7 @@ import edu.harvard.iq.dataverse.ValidateEmail; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; +import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; @@ -143,6 +144,20 @@ public String getDisplayName(){ return this.getFirstName() + " " + this.getLastName(); } + public void applyDisplayInfo( AuthenticatedUserDisplayInfo inf ) { + setFirstName(inf.getFirstName()); + setLastName(inf.getLastName()); + if ( nonEmpty(inf.getEmailAddress()) ) { + setEmail(inf.getEmailAddress()); + } + if ( nonEmpty(inf.getAffiliation()) ) { + setAffiliation( inf.getAffiliation() ); + } + if ( nonEmpty(inf.getPosition()) ) { + setPosition( inf.getPosition()); + } + } + public AuthenticatedUserDisplayInfo getDisplayInfo() { return new AuthenticatedUserDisplayInfo(getFirstName(), getLastName(), getEmail(), getAffiliation(), getPosition() ); } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUserServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUserServiceBean.java index 1bad489f58c..afb5fc62b39 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUserServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUserServiceBean.java @@ -1,7 +1,6 @@ package edu.harvard.iq.dataverse.authorization.providers.builtin; import edu.harvard.iq.dataverse.search.IndexServiceBean; -import edu.harvard.iq.dataverse.authorization.users.User; import edu.harvard.iq.dataverse.passwordreset.PasswordResetData; import edu.harvard.iq.dataverse.passwordreset.PasswordResetException; import edu.harvard.iq.dataverse.passwordreset.PasswordResetInitResponse; @@ -45,7 +44,7 @@ public String encryptPassword(String plainText) { return PasswordEncryption.get().encrypt(plainText); } - public BuiltinUser save(BuiltinUser dataverseUser) { + public BuiltinUser save(BuiltinUser aUser) { /** * Trim the email address no matter what the user entered or is entered * on their behalf in the case of Shibboleth assertions. @@ -53,14 +52,14 @@ public BuiltinUser save(BuiltinUser dataverseUser) { * @todo Why doesn't Bean Validation report that leading and trailing * whitespace in an email address is a problem? */ - dataverseUser.setEmail(dataverseUser.getEmail().trim()); + aUser.setEmail(aUser.getEmail().trim()); /** * We throw a proper IllegalArgumentException here because otherwise * from the API you get a 500 response and "Can't save user: null". */ ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); - Set> violations = validator.validate(dataverseUser); + Set> violations = validator.validate(aUser); if (violations.size() > 0) { StringBuilder sb = new StringBuilder(); violations.stream().forEach((violation) -> { @@ -68,16 +67,16 @@ public BuiltinUser save(BuiltinUser dataverseUser) { }); throw new IllegalArgumentException("BuiltinUser could not be saved to due constraint violations: " + sb); } - if ( dataverseUser.getId() == null ) { + if ( aUser.getId() == null ) { // see that the username is unique if ( em.createNamedQuery("BuiltinUser.findByUserName") - .setParameter("userName", dataverseUser.getUserName()).getResultList().size() > 0 ) { - throw new IllegalArgumentException( "BuiltinUser with username '" + dataverseUser.getUserName() + "' already exists."); + .setParameter("userName", aUser.getUserName()).getResultList().size() > 0 ) { + throw new IllegalArgumentException( "BuiltinUser with username '" + aUser.getUserName() + "' already exists."); } - em.persist( dataverseUser ); - return dataverseUser; + em.persist( aUser ); + return aUser; } else { - return em.merge(dataverseUser); + return em.merge(aUser); } } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUserPage.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java similarity index 69% rename from src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUserPage.java rename to src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java index 5dddaf6432f..306a2898195 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinUserPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/DataverseUserPage.java @@ -1,8 +1,3 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package edu.harvard.iq.dataverse.authorization.providers.builtin; import edu.harvard.iq.dataverse.DataFile; @@ -11,7 +6,6 @@ import edu.harvard.iq.dataverse.DatasetServiceBean; import edu.harvard.iq.dataverse.DatasetVersionServiceBean; import edu.harvard.iq.dataverse.Dataverse; -import edu.harvard.iq.dataverse.DataverseHeaderFragment; import edu.harvard.iq.dataverse.DataverseServiceBean; import edu.harvard.iq.dataverse.DataverseSession; import edu.harvard.iq.dataverse.DvObject; @@ -22,6 +16,8 @@ import edu.harvard.iq.dataverse.UserNotification; import static edu.harvard.iq.dataverse.UserNotification.Type.CREATEDV; import edu.harvard.iq.dataverse.UserNotificationServiceBean; +import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; +import edu.harvard.iq.dataverse.authorization.AuthenticationProvider; import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; import edu.harvard.iq.dataverse.authorization.UserRecordIdentifier; import edu.harvard.iq.dataverse.authorization.groups.Group; @@ -29,7 +25,6 @@ import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import edu.harvard.iq.dataverse.confirmemail.ConfirmEmailData; import edu.harvard.iq.dataverse.confirmemail.ConfirmEmailException; -import edu.harvard.iq.dataverse.confirmemail.ConfirmEmailInitResponse; import edu.harvard.iq.dataverse.confirmemail.ConfirmEmailServiceBean; import edu.harvard.iq.dataverse.confirmemail.ConfirmEmailUtil; import edu.harvard.iq.dataverse.mydata.MyDataPage; @@ -46,6 +41,7 @@ import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -64,16 +60,14 @@ /** * - * @author xyang */ @ViewScoped @Named("DataverseUserPage") -public class BuiltinUserPage implements java.io.Serializable { +public class DataverseUserPage implements java.io.Serializable { - private static final Logger logger = Logger.getLogger(BuiltinUserPage.class.getCanonicalName()); + private static final Logger logger = Logger.getLogger(DataverseUserPage.class.getCanonicalName()); public enum EditMode { - CREATE, EDIT, CHANGE_PASSWORD, FORGOT }; @@ -108,11 +102,9 @@ public enum EditMode { @Inject PermissionsWrapper permissionsWrapper; - @EJB - AuthenticationServiceBean authSvc; - + private AuthenticatedUserDisplayInfo userDisplayInfo; private AuthenticatedUser currentUser; - private BuiltinUser builtinUser; + private transient AuthenticationProvider userAuthProvider; private EditMode editMode; private String redirectPage = "dataverse.xhtml"; @@ -126,132 +118,34 @@ public enum EditMode { private int activeIndex; private String selectTab = "somedata"; UIInput usernameField; + private String username; - public EditMode getChangePasswordMode () { - return EditMode.CHANGE_PASSWORD; - } - - public AuthenticatedUser getCurrentUser() { - return currentUser; - } - - public void setCurrentUser(AuthenticatedUser currentUser) { - this.currentUser = currentUser; - } - - public BuiltinUser getBuiltinUser() { - return builtinUser; - } - - public void setBuiltinUser(BuiltinUser builtinUser) { - this.builtinUser = builtinUser; - } - - public EditMode getEditMode() { - return editMode; - } - - public void setEditMode(EditMode editMode) { - this.editMode = editMode; - } - - public String getRedirectPage() { - return redirectPage; - } - - public void setRedirectPage(String redirectPage) { - this.redirectPage = redirectPage; - } - - public String getInputPassword() { - return inputPassword; - } - - public void setInputPassword(String inputPassword) { - this.inputPassword = inputPassword; - } - - public String getCurrentPassword() { - return currentPassword; - } - - public void setCurrentPassword(String currentPassword) { - this.currentPassword = currentPassword; - } - - public Long getDataverseId() { - - if (dataverseId == null) { - dataverseId = dataverseService.findRootDataverse().getId(); - } - return dataverseId; - } - - public void setDataverseId(Long dataverseId) { - this.dataverseId = dataverseId; - } - - - - public List getNotificationsList() { - return notificationsList; - } - - public void setNotificationsList(List notificationsList) { - this.notificationsList = notificationsList; - } - - public int getActiveIndex() { - return activeIndex; - } - - public void setActiveIndex(int activeIndex) { - this.activeIndex = activeIndex; - } - - public String getSelectTab() { - return selectTab; - } - - public void setSelectTab(String selectTab) { - this.selectTab = selectTab; - } - - public UIInput getUsernameField() { - return usernameField; - } - - public void setUsernameField(UIInput usernameField) { - this.usernameField = usernameField; - } - public String init() { // prevent creating a user if signup not allowed. boolean safeDefaultIfKeyNotFound = true; boolean signupAllowed = settingsWrapper.isTrueForKey(SettingsServiceBean.Key.AllowSignUp.toString(), safeDefaultIfKeyNotFound); - logger.fine("signup is allowed: " + signupAllowed); if (editMode == EditMode.CREATE && !signupAllowed) { return "/403.xhtml"; } if (editMode == EditMode.CREATE) { - if (!session.getUser().isAuthenticated()) { // in create mode for new user + if (session.getUser().isAuthenticated()) { + editMode = null; // we can't be in create mode for an existing user + + } else { + // in create mode for new user JH.addMessage(FacesMessage.SEVERITY_INFO, BundleUtil.getStringFromBundle("user.signup.tip")); - builtinUser = new BuiltinUser(); + userDisplayInfo = new AuthenticatedUserDisplayInfo(); return ""; - } else { - editMode = null; // we can't be in create mode for an existing user } } if ( session.getUser().isAuthenticated() ) { - currentUser = (AuthenticatedUser) session.getUser(); - notificationsList = userNotificationService.findByUser(((AuthenticatedUser)currentUser).getId()); - if (currentUser.isBuiltInUser()) { - builtinUser = builtinUserService.findByUserName(currentUser.getUserIdentifier()); - } + setCurrentUser((AuthenticatedUser) session.getUser()); + notificationsList = userNotificationService.findByUser(currentUser.getId()); + switch (selectTab) { case "notifications": activeIndex = 1; @@ -296,20 +190,11 @@ public void forgotPassword(ActionEvent e) { public void validateUserName(FacesContext context, UIComponent toValidate, Object value) { String userName = (String) value; - boolean userNameFound = false; - BuiltinUser user = builtinUserService.findByUserName(userName); - if (editMode == EditMode.CREATE) { - if (user != null) { - userNameFound = true; - } - } else { - if (user != null && !user.getId().equals(builtinUser.getId())) { - userNameFound = true; - } - } - if (userNameFound) { + boolean userNameFound = authenticationService.identifierExists(userName); + + if (editMode == EditMode.CREATE && userNameFound) { ((UIInput) toValidate).setValid(false); - FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, JH.localize("user.username.taken"), null); + FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("user.username.taken"), null); context.addMessage(toValidate.getClientId(context), message); } } @@ -317,72 +202,22 @@ public void validateUserName(FacesContext context, UIComponent toValidate, Objec public void validateUserEmail(FacesContext context, UIComponent toValidate, Object value) { String userEmail = (String) value; boolean userEmailFound = false; - BuiltinUser user = builtinUserService.findByEmail(userEmail); AuthenticatedUser aUser = authenticationService.getAuthenticatedUserByEmail(userEmail); if (editMode == EditMode.CREATE) { - if (user != null || aUser != null) { + if (aUser != null) { userEmailFound = true; } } else { - //In edit mode... - if (user != null || aUser != null){ - userEmailFound = true; - } - //if there's a match on edit make sure that the email belongs to the + // In edit mode... + // if there's a match on edit make sure that the email belongs to the // user doing the editing by checking ids - if ((user != null && user.getId().equals(builtinUser.getId())) || (aUser!=null && aUser.getId().equals(builtinUser.getId()))){ - userEmailFound = false; + if ( aUser!=null && ! aUser.getId().equals(currentUser.getId()) ){ + userEmailFound = true; } } if (userEmailFound) { ((UIInput) toValidate).setValid(false); - FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, JH.localize("user.email.taken"), null); - context.addMessage(toValidate.getClientId(context), message); - } - } - - - public void validateUserNameEmail(FacesContext context, UIComponent toValidate, Object value) { - String userName = (String) value; - boolean userNameFound = false; - BuiltinUser user = builtinUserService.findByUserName(userName); - if (user != null) { - userNameFound = true; - } else { - BuiltinUser user2 = builtinUserService.findByEmail(userName); - if (user2 != null) { - userNameFound = true; - } - } - if (!userNameFound) { - ((UIInput) toValidate).setValid(false); - FacesMessage message = new FacesMessage("Username or Email is incorrect."); - context.addMessage(toValidate.getClientId(context), message); - } - } - - public void validateCurrentPassword(FacesContext context, UIComponent toValidate, Object value) { - - String password = (String) value; - - if (StringUtils.isBlank(password)){ - logger.log(Level.WARNING, "current password is blank"); - - ((UIInput) toValidate).setValid(false); - FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, - "Password Error", "Password is blank: re-type it again."); - context.addMessage(toValidate.getClientId(context), message); - return; - - } else { - logger.log(Level.INFO, "current paswword is not blank"); - } - - - - if ( ! PasswordEncryption.getVersion(builtinUser.getPasswordEncryptionVersion()).check(password, builtinUser.getEncryptedPassword()) ) { - ((UIInput) toValidate).setValid(false); - FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Password Error", "Password is incorrect."); + FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("user.email.taken"), null); context.addMessage(toValidate.getClientId(context), message); } } @@ -398,10 +233,7 @@ public void validateNewPassword(FacesContext context, UIComponent toValidate, Ob "Password Error", "The new password is blank: re-type it again"); context.addMessage(toValidate.getClientId(context), message); return; - - } else { - logger.log(Level.INFO, "new paswword is not blank"); - } + } int minPasswordLength = 6; boolean forceNumber = true; @@ -419,49 +251,49 @@ public void validateNewPassword(FacesContext context, UIComponent toValidate, Ob } } - - - public void updatePassword(String userName) { - String plainTextPassword = PasswordEncryption.generateRandomPassword(); - BuiltinUser user = builtinUserService.findByUserName(userName); - if (user == null) { - user = builtinUserService.findByEmail(userName); - } - user.updateEncryptedPassword(PasswordEncryption.get().encrypt(plainTextPassword), PasswordEncryption.getLatestVersionNumber()); - builtinUserService.save(user); - } - public String save() { boolean passwordChanged = false; - boolean emailChanged = false; - if (editMode == EditMode.CREATE || editMode == EditMode.CHANGE_PASSWORD) { - if (inputPassword != null) { - builtinUser.updateEncryptedPassword(PasswordEncryption.get().encrypt(inputPassword), PasswordEncryption.getLatestVersionNumber()); + final AuthenticationProvider prv = getUserAuthProvider(); + if ( editMode == EditMode.CHANGE_PASSWORD ) { + if ( prv.isPasswordUpdateAllowed() ) { + if ( ! prv.verifyPassword(currentUser.getAuthenticatedUserLookup().getPersistentUserId(), currentPassword) ) { + FacesContext.getCurrentInstance().addMessage("currentPassword", + new FacesMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("user.error.wrongPassword"),null)); + return null; + } + prv.updatePassword(currentUser.getAuthenticatedUserLookup().getPersistentUserId(), inputPassword); passwordChanged = true; + } else { - // just defensive coding: for in case when the validator is not - // working - logger.log(Level.WARNING, "inputPassword is still null"); - FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, JH.localize("user.noPasswd"), null); - FacesContext context = FacesContext.getCurrentInstance(); - context.addMessage(null, message); + // erroneous state - we can't change the password for this user, so should not have gotten here. Log and bail out. + logger.log(Level.WARNING, "Attempt to change a password on {0}, whose provider ({1}) does not support password change", new Object[]{currentUser.getIdentifier(), prv}); + JH.addMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("user.error.cannotChangePassword")); return null; } } - builtinUser = builtinUserService.save(builtinUser); - + if (editMode == EditMode.CREATE) { - AuthenticatedUser au = authSvc.createAuthenticatedUser( + // Create a new built-in user. + BuiltinUser builtinUser = new BuiltinUser(); + builtinUser.setUserName( getUsername() ); + builtinUser.applyDisplayInfo(userDisplayInfo); + builtinUser.updateEncryptedPassword(PasswordEncryption.get().encrypt(inputPassword), + PasswordEncryption.getLatestVersionNumber()); + + AuthenticatedUser au = authenticationService.createAuthenticatedUser( new UserRecordIdentifier(BuiltinAuthenticationProvider.PROVIDER_ID, builtinUser.getUserName()), builtinUser.getUserName(), builtinUser.getDisplayInfo(), false); if ( au == null ) { // username exists getUsernameField().setValid(false); - FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, JH.localize("user.username.taken"), null); + FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, BundleUtil.getStringFromBundle("user.username.taken"), null); FacesContext context = FacesContext.getCurrentInstance(); context.addMessage(getUsernameField().getClientId(context), message); return null; } + + // Authenticated user registered. Save the new bulitin, and log in. + builtinUserService.save(builtinUser); session.setUser(au); userNotificationService.sendNotification(au, new Timestamp(new Date().getTime()), @@ -475,7 +307,7 @@ public String save() { try { redirectPage = URLDecoder.decode(redirectPage, "UTF-8"); } catch (UnsupportedEncodingException ex) { - Logger.getLogger(BuiltinUserPage.class.getName()).log(Level.SEVERE, null, ex); + logger.log(Level.SEVERE, "Server does not support 'UTF-8' encoding.", ex); redirectPage = "dataverse.xhtml&alias=" + dataverseService.findRootDataverse().getAlias(); } @@ -483,35 +315,31 @@ public String save() { return redirectPage + (!redirectPage.contains("?") ? "?" : "&") + "faces-redirect=true"; - } else { String emailBeforeUpdate = currentUser.getEmail(); - AuthenticatedUser savedUser = authSvc.updateAuthenticatedUser(currentUser, builtinUser.getDisplayInfo()); + AuthenticatedUser savedUser = authenticationService.updateAuthenticatedUser(currentUser, userDisplayInfo); String emailAfterUpdate = savedUser.getEmail(); - if (!emailBeforeUpdate.equals(emailAfterUpdate)) { - emailChanged = true; - } editMode = null; - String msg = "Your account information has been successfully updated."; - if (passwordChanged) { - msg = "Your account password has been successfully changed."; - } - if (emailChanged) { - ConfirmEmailUtil confirmEmailUtil = new ConfirmEmailUtil(); - String expTime = confirmEmailUtil.friendlyExpirationTime(systemConfig.getMinutesUntilConfirmEmailTokenExpires()); - msg = msg + " Your email address has changed and must be re-verified. Please check your inbox at " + currentUser.getEmail() + " and follow the link we've sent. \n\nAlso, please note that the link will only work for the next " + expTime + " before it has expired."; - boolean sendEmail = true; + StringBuilder msg = new StringBuilder( passwordChanged ? "Your account password has been successfully changed." + : "Your account information has been successfully updated."); + if (!emailBeforeUpdate.equals(emailAfterUpdate)) { + String expTime = ConfirmEmailUtil.friendlyExpirationTime(systemConfig.getMinutesUntilConfirmEmailTokenExpires()); + msg.append(" Your email address has changed and must be re-verified. Please check your inbox at ") + .append(currentUser.getEmail()) + .append(" and follow the link we've sent. \n\nAlso, please note that the link will only work for the next ") + .append(expTime) + .append(" before it has expired."); // delete unexpired token, if it exists (clean slate) confirmEmailService.deleteTokenForUser(currentUser); try { - ConfirmEmailInitResponse confirmEmailInitResponse = confirmEmailService.beginConfirm(currentUser); + confirmEmailService.beginConfirm(currentUser); } catch (ConfirmEmailException ex) { - logger.info("Unable to send email confirmation link to user id " + savedUser.getId()); + logger.log(Level.INFO, "Unable to send email confirmation link to user id {0}", savedUser.getId()); } session.setUser(currentUser); - JsfHelper.addSuccessMessage(msg); + JsfHelper.addSuccessMessage(msg.toString()); } else { - JsfHelper.addFlashMessage(msg); + JsfHelper.addFlashMessage(msg.toString()); } return null; } @@ -526,16 +354,11 @@ public String cancel() { return null; } - public void submit(ActionEvent e) { - updatePassword(builtinUser.getUserName()); - editMode = null; - } - public String remove(Long notificationId) { UserNotification userNotification = userNotificationService.find(notificationId); userNotificationService.delete(userNotification); for (UserNotification uNotification : notificationsList) { - if (uNotification.getId() == userNotification.getId()) { + if (Objects.equals(uNotification.getId(), userNotification.getId())) { notificationsList.remove(uNotification); break; } @@ -630,47 +453,161 @@ public void displayNotification() { public void sendConfirmEmail() { logger.fine("called sendConfirmEmail()"); String userEmail = currentUser.getEmail(); - ConfirmEmailUtil confirmEmailUtil = new ConfirmEmailUtil(); try { confirmEmailService.beginConfirm(currentUser); List args = Arrays.asList( userEmail, - confirmEmailUtil.friendlyExpirationTime(systemConfig.getMinutesUntilConfirmEmailTokenExpires())); + ConfirmEmailUtil.friendlyExpirationTime(systemConfig.getMinutesUntilConfirmEmailTokenExpires())); JsfHelper.addSuccessMessage(BundleUtil.getStringFromBundle("confirmEmail.submitRequest.success", args)); } catch (ConfirmEmailException ex) { - Logger.getLogger(BuiltinUserPage.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(DataverseUserPage.class.getName()).log(Level.SEVERE, null, ex); } } + /** + * Determines whether the button to send a verification email appears on user page + * @return + */ public boolean showVerifyEmailButton() { - /** - * Determines whether the button to send a verification email appears on user page - */ - if (confirmEmailService.findSingleConfirmEmailDataByUser(currentUser) == null - && currentUser.getEmailConfirmed() == null) { - return true; - } - return false; + final Timestamp emailConfirmed = currentUser.getEmailConfirmed(); + final ConfirmEmailData confirmedDate = confirmEmailService.findSingleConfirmEmailDataByUser(currentUser); + return (!getUserAuthProvider().isEmailVerified()) + && confirmedDate == null + && emailConfirmed == null; } public boolean isEmailIsVerified() { - if (currentUser.getEmailConfirmed() != null && confirmEmailService.findSingleConfirmEmailDataByUser(currentUser) == null) { - return true; - } else return false; + return currentUser.getEmailConfirmed() != null && confirmEmailService.findSingleConfirmEmailDataByUser(currentUser) == null; } public boolean isEmailNotVerified() { - if (currentUser.getEmailConfirmed() == null || confirmEmailService.findSingleConfirmEmailDataByUser(currentUser) != null) { - return true; - } else return false; + return currentUser.getEmailConfirmed() == null || confirmEmailService.findSingleConfirmEmailDataByUser(currentUser) != null; } public boolean isEmailGrandfathered() { - ConfirmEmailUtil confirmEmailUtil = new ConfirmEmailUtil(); - if (currentUser.getEmailConfirmed() == confirmEmailUtil.getGrandfatheredTime()) { - return true; - } else return false; + return currentUser.getEmailConfirmed().equals(ConfirmEmailUtil.getGrandfatheredTime()); + } + + AuthenticationProvider getUserAuthProvider() { + if ( userAuthProvider == null ) { + userAuthProvider = authenticationService.lookupProvider(currentUser); + } + return userAuthProvider; + } + + public boolean isPasswordEditable() { + return getUserAuthProvider().isPasswordUpdateAllowed(); + } + + public boolean isAccountDetailsEditable() { + return getUserAuthProvider().isUserInfoUpdateAllowed(); + } + + public AuthenticatedUserDisplayInfo getUserDisplayInfo() { + return userDisplayInfo; + } + + public void setUserDisplayInfo(AuthenticatedUserDisplayInfo userDisplayInfo) { + this.userDisplayInfo = userDisplayInfo; + } + + public EditMode getChangePasswordMode () { + return EditMode.CHANGE_PASSWORD; + } + + public AuthenticatedUser getCurrentUser() { + return currentUser; + } + + public void setCurrentUser(AuthenticatedUser currentUser) { + this.currentUser = currentUser; + userDisplayInfo = currentUser.getDisplayInfo(); + username = currentUser.getUserIdentifier(); + } + + public EditMode getEditMode() { + return editMode; + } + + public void setEditMode(EditMode editMode) { + this.editMode = editMode; + } + + public String getRedirectPage() { + return redirectPage; + } + + public void setRedirectPage(String redirectPage) { + this.redirectPage = redirectPage; + } + + public String getInputPassword() { + return inputPassword; + } + + public void setInputPassword(String inputPassword) { + this.inputPassword = inputPassword; + } + + public String getCurrentPassword() { + return currentPassword; + } + + public void setCurrentPassword(String currentPassword) { + this.currentPassword = currentPassword; + } + + public Long getDataverseId() { + + if (dataverseId == null) { + dataverseId = dataverseService.findRootDataverse().getId(); + } + return dataverseId; + } + + public void setDataverseId(Long dataverseId) { + this.dataverseId = dataverseId; + } + + public List getNotificationsList() { + return notificationsList; + } + + public void setNotificationsList(List notificationsList) { + this.notificationsList = notificationsList; + } + + public int getActiveIndex() { + return activeIndex; + } + + public void setActiveIndex(int activeIndex) { + this.activeIndex = activeIndex; + } + + public String getSelectTab() { + return selectTab; + } + + public void setSelectTab(String selectTab) { + this.selectTab = selectTab; + } + + public UIInput getUsernameField() { + return usernameField; + } + + public void setUsernameField(UIInput usernameField) { + this.usernameField = usernameField; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; } -} +} \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/PasswordEncryption.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/PasswordEncryption.java index 5eeddf97ca2..4e268e7e225 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/PasswordEncryption.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/builtin/PasswordEncryption.java @@ -63,7 +63,12 @@ public String encrypt(String plainText) { @Override public boolean check(String plainText, String hashed) { - return BCrypt.checkpw(plainText, hashed); + try { + return BCrypt.checkpw(plainText, hashed); + } catch (java.lang.IllegalArgumentException iae ) { + // the password was probably not hashed using bcrypt. + return false; + } } }; @@ -78,6 +83,9 @@ public boolean check(String plainText, String hashed) { */ private PasswordEncryption() {} + /** + * @return The current version of the password hashing algorithm. + */ public static Algorithm get() { return getVersion( getLatestVersionNumber() ); } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java index 5321d466560..4f9565c8eae 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java @@ -10,8 +10,6 @@ import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.authorization.AuthenticationProvider; import edu.harvard.iq.dataverse.authorization.AuthenticationProviderDisplayInfo; -import edu.harvard.iq.dataverse.authorization.AuthenticationRequest; -import edu.harvard.iq.dataverse.authorization.AuthenticationResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -132,6 +130,18 @@ public OAuth2UserRecord getUserRecord(String code, String state, String redirect } } + @Override + public boolean isUserInfoUpdateAllowed() { + return true; + } + + @Override + public void updateUserInfo(String userIdInProvider, AuthenticatedUserDisplayInfo updatedUserData) { + // ignore - no account info is stored locally. + // We override this to prevent the UnsupportedOperationException thrown by + // the default implementation. + } + @Override public AuthenticationProviderDisplayInfo getInfo() { return new AuthenticationProviderDisplayInfo(getId(), getTitle(), getSubTitle()); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java index bff26fe991f..2e11d97ab0f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java @@ -92,7 +92,7 @@ public String testAction() { } public boolean isEmailAvailable() { - return authenticationSvc.isEmailAvailable(getSelectedEmail()); + return authenticationSvc.isEmailAddressAvailable(getSelectedEmail()); } public boolean isEmailValid() { diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java index 2b259df2611..c23b548ede4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java @@ -92,11 +92,6 @@ public void exchangeCodeForToken() throws IOException { FacesContext.getCurrentInstance().getExternalContext().redirect("/oauth2/firstLogin.xhtml"); } else { - // update profile - override fields user fills on first login - final AuthenticatedUserDisplayInfo updateInfo = new AuthenticatedUserDisplayInfo(oauthUser.getDisplayInfo()); - updateInfo.setEmailAddress(null); - - dvUser = authenticationSvc.updateAuthenticatedUser(dvUser, updateInfo); // login the user and redirect to HOME. session.setUser(dvUser); FacesContext.getCurrentInstance().getExternalContext().redirect("/"); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java index 52700721f0d..8e4253430be 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/AuthenticatedUser.java @@ -4,7 +4,6 @@ import edu.harvard.iq.dataverse.ValidateEmail; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserLookup; -import edu.harvard.iq.dataverse.authorization.RoleAssigneeDisplayInfo; import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinAuthenticationProvider; import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty; import java.io.Serializable; @@ -97,8 +96,6 @@ public String getIdentifier() { return IDENTIFIER_PREFIX + userIdentifier; } - - @OneToMany(mappedBy = "user", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST}) private List datasetLocks; @@ -111,7 +108,7 @@ public void setDatasetLocks(List datasetLocks) { } @Override - public RoleAssigneeDisplayInfo getDisplayInfo() { + public AuthenticatedUserDisplayInfo getDisplayInfo() { return new AuthenticatedUserDisplayInfo(firstName, lastName, email, affiliation, position); } @@ -217,15 +214,6 @@ public void setModificationTime(Timestamp modificationTime) { this.modificationTime = modificationTime; } - public boolean isBuiltInUser() { - String authProviderString = authenticatedUserLookup.getAuthenticationProviderId(); - if (authProviderString != null && authProviderString.equals(BuiltinAuthenticationProvider.PROVIDER_ID)) { - return true; - } - - return false; - } - @OneToOne(mappedBy = "authenticatedUser") private AuthenticatedUserLookup authenticatedUserLookup; diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/GuestUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/GuestUser.java index b2fd3194f70..f16fa5afe36 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/GuestUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/GuestUser.java @@ -28,11 +28,6 @@ public RoleAssigneeDisplayInfo getDisplayInfo() { @Override public boolean isAuthenticated() { return false; } - @Override - public boolean isBuiltInUser(){ - return false; - } - @Override public boolean isSuperuser() { return false; diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/PrivateUrlUser.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/PrivateUrlUser.java index 88e1f8ffc83..59c3240fdfa 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/PrivateUrlUser.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/PrivateUrlUser.java @@ -30,21 +30,18 @@ public long getDatasetId() { } /** - * @return By always returning false for isAuthenticated(), we prevent a + * By always returning false for isAuthenticated(), we prevent a * name from appearing in the corner as well as preventing an account page * and MyData from being accessible. The user can still navigate to the home * page but can only see published datasets. + * + * @return {@code false}. */ @Override public boolean isAuthenticated() { return false; } - @Override - public boolean isBuiltInUser() { - return false; - } - @Override public boolean isSuperuser() { return false; diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/users/User.java b/src/main/java/edu/harvard/iq/dataverse/authorization/users/User.java index 29863361a30..ea35f87d178 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/users/User.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/users/User.java @@ -12,11 +12,6 @@ public interface User extends RoleAssignee, Serializable { public boolean isAuthenticated(); - // TODO remove this, should be handled in a more generic fashion, - // e.g. getUserProvider and get the provider's URL from there. This - // would allow Shib-based editing as well. - public boolean isBuiltInUser(); - public boolean isSuperuser(); } diff --git a/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailServiceBean.java index e21ba1f98b3..bbe520682e3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailServiceBean.java @@ -93,13 +93,12 @@ private ConfirmEmailInitResponse sendConfirm(AuthenticatedUser aUser, boolean se * change. */ private void sendLinkOnEmailChange(AuthenticatedUser aUser, String confirmationUrl) throws ConfirmEmailException { - ConfirmEmailUtil confirmEmailUtil = new ConfirmEmailUtil(); String messageBody = BundleUtil.getStringFromBundle("notification.email.changeEmail", Arrays.asList( aUser.getFirstName(), confirmationUrl, - confirmEmailUtil.friendlyExpirationTime(systemConfig.getMinutesUntilConfirmEmailTokenExpires()) + ConfirmEmailUtil.friendlyExpirationTime(systemConfig.getMinutesUntilConfirmEmailTokenExpires()) )); - logger.fine("messageBody:" + messageBody); + logger.log(Level.FINE, "messageBody:{0}", messageBody); try { String toAddress = aUser.getEmail(); @@ -220,7 +219,6 @@ public ConfirmEmailData createToken(AuthenticatedUser au) { } public String optionalConfirmEmailAddonMsg(AuthenticatedUser user) { - ConfirmEmailUtil confirmEmailUtil = new ConfirmEmailUtil(); final String emptyString = ""; if (user == null) { logger.info("Can't return confirm email message. AuthenticatedUser was null!"); @@ -235,7 +233,7 @@ public String optionalConfirmEmailAddonMsg(AuthenticatedUser user) { logger.info("Can't return confirm email message. No ConfirmEmailData for user id " + user.getId()); return emptyString; } - String expTime = confirmEmailUtil.friendlyExpirationTime(systemConfig.getMinutesUntilConfirmEmailTokenExpires()); + String expTime = ConfirmEmailUtil.friendlyExpirationTime(systemConfig.getMinutesUntilConfirmEmailTokenExpires()); String confirmEmailUrl = systemConfig.getDataverseSiteUrl() + "/confirmemail.xhtml?token=" + confirmEmailData.getToken(); List args = Arrays.asList(confirmEmailUrl, expTime); String optionalConfirmEmailMsg = BundleUtil.getStringFromBundle("notification.email.welcomeConfirmEmailAddOn", args); diff --git a/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailUtil.java b/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailUtil.java index d2f84b956df..5f0fcd0433b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailUtil.java +++ b/src/main/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailUtil.java @@ -2,17 +2,22 @@ import edu.harvard.iq.dataverse.util.BundleUtil; import java.sql.Timestamp; -import java.util.Date; public class ConfirmEmailUtil { - + + private ConfirmEmailUtil(){ + // prevent instance creation, this class has only static methods anyway. + } + + private static final Timestamp GRANDFATHERED_TIME = Timestamp.valueOf("2000-01-01 00:00:00.0"); + + /** + * Currently set to Y2K as an easter egg to easily set apart + * grandfathered accounts from post-launch accounts. + * @return + */ public static Timestamp getGrandfatheredTime() { - /** - * Currently set to Y2K as an easter egg to easily set apart - * grandfathered accounts from post-launch accounts. - */ - Timestamp grandfatheredTime = Timestamp.valueOf("2000-01-01 00:00:00.0"); - return grandfatheredTime; + return GRANDFATHERED_TIME; } public static String friendlyExpirationTime(int expirationInt) { diff --git a/src/main/webapp/dataverseuser.xhtml b/src/main/webapp/dataverseuser.xhtml index 30c726e2e45..f8f3b213cda 100644 --- a/src/main/webapp/dataverseuser.xhtml +++ b/src/main/webapp/dataverseuser.xhtml @@ -28,25 +28,26 @@
-
+
- +
- +
@@ -515,7 +516,7 @@
- +
@@ -526,8 +527,11 @@
- - + +
diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinAuthenticationProviderTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinAuthenticationProviderTest.java new file mode 100644 index 00000000000..6a1283d844d --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/builtin/BuiltinAuthenticationProviderTest.java @@ -0,0 +1,115 @@ +package edu.harvard.iq.dataverse.authorization.providers.builtin; + +import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; +import edu.harvard.iq.dataverse.mocks.MockBuiltinUserServiceBean; +import org.junit.Test; +import static org.junit.Assert.*; +import org.junit.Before; + +/** + * + * @author michael + */ +public class BuiltinAuthenticationProviderTest { + + BuiltinAuthenticationProvider sut = null; + MockBuiltinUserServiceBean bean = null; + + @Before + public void setup() { + bean = new MockBuiltinUserServiceBean(); + sut = new BuiltinAuthenticationProvider(bean); + } + + /** + * Test of getId method, of class BuiltinAuthenticationProvider. + */ + @Test + public void testGetId() { + assertEquals("builtin", sut.getId()); + } + + /** + * Test of getInfo method, of class BuiltinAuthenticationProvider. + */ + @Test + public void testGetInfo() { + String expResult = "builtin"; + String result = sut.getInfo().getId(); + assertEquals(expResult, result); + } + + /** + * Test of isPasswordUpdateAllowed method, of class BuiltinAuthenticationProvider. + */ + @Test + public void testIsPasswordUpdateAllowed() { + assertTrue( sut.isPasswordUpdateAllowed() ); + } + + /** + * Test of isUserInfoUpdateAllowed method, of class BuiltinAuthenticationProvider. + */ + @Test + public void testIsUserInfoUpdateAllowed() { + assertTrue( sut.isUserInfoUpdateAllowed() ); + } + + /** + * Test of isUserDeletionAllowed method, of class BuiltinAuthenticationProvider. + */ + @Test + public void testIsUserDeletionAllowed() { + assertTrue( sut.isUserDeletionAllowed() ); + } + + /** + * Test of deleteUser method, of class BuiltinAuthenticationProvider. + */ + @Test + public void testDeleteUser() { + BuiltinUser u = makeBuiltInUser(); + assertTrue( bean.users.isEmpty() ); + bean.save(u); + assertFalse( bean.users.isEmpty() ); + + sut.deleteUser( u.getUserName() ); + + assertTrue( bean.users.isEmpty() ); + } + + /** + * Test of updatePassword method, of class BuiltinAuthenticationProvider. + */ + @Test + public void testUpdatePassword() { + BuiltinUser user = bean.save(makeBuiltInUser()); + final String newPassword = "newPassword"; + assertFalse( sut.verifyPassword(user.getUserName(), newPassword) ); + sut.updatePassword(user.getUserName(), newPassword); + assertTrue( sut.verifyPassword(user.getUserName(), newPassword)); + } + + /** + * Test of updateUserInfo method, of class BuiltinAuthenticationProvider. + */ + @Test + public void testUpdateUserInfo() { + BuiltinUser user = bean.save(makeBuiltInUser()); + AuthenticatedUserDisplayInfo newInfo = new AuthenticatedUserDisplayInfo("nf", "nl", "ema@il.com", "newAffi", "newPos"); + sut.updateUserInfo(user.getUserName(), newInfo); + assertEquals( newInfo, user.getDisplayInfo() ); + } + + private BuiltinUser makeBuiltInUser() { + BuiltinUser user = new BuiltinUser(); + user.setFirstName("Firsty"); + user.setLastName("Last"); + user.setEmail("email@host.com"); + user.setAffiliation("an institute"); + user.setPosition("a position"); + user.updateEncryptedPassword("password", PasswordEncryption.getLatestVersionNumber()); + return user; + } + +} diff --git a/src/test/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailUtilTest.java b/src/test/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailUtilTest.java index 5a2a13bbbd9..78d64130e86 100644 --- a/src/test/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailUtilTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/confirmemail/ConfirmEmailUtilTest.java @@ -8,34 +8,32 @@ public class ConfirmEmailUtilTest { @Test public void testFriendlyExpirationTime() { - ConfirmEmailUtil confirmEmailUtil = new ConfirmEmailUtil(); System.out.println("Friendly expiration timestamp / measurement test"); - System.out.println("1440 Minutes: " + confirmEmailUtil.friendlyExpirationTime(1440)); + System.out.println("1440 Minutes: " + ConfirmEmailUtil.friendlyExpirationTime(1440)); assertEquals("24 hours", ConfirmEmailUtil.friendlyExpirationTime(1440)); - System.out.println("60 Minutes: " + confirmEmailUtil.friendlyExpirationTime(60)); + System.out.println("60 Minutes: " + ConfirmEmailUtil.friendlyExpirationTime(60)); assertEquals("1 hour", ConfirmEmailUtil.friendlyExpirationTime(60)); - System.out.println("30 Minutes: " + confirmEmailUtil.friendlyExpirationTime(30)); + System.out.println("30 Minutes: " + ConfirmEmailUtil.friendlyExpirationTime(30)); assertEquals("30 minutes", ConfirmEmailUtil.friendlyExpirationTime(30)); - System.out.println("90 Minutes: " + confirmEmailUtil.friendlyExpirationTime(90)); - assertEquals("1.5 hours", confirmEmailUtil.friendlyExpirationTime(90)); - System.out.println("2880 minutes: " + confirmEmailUtil.friendlyExpirationTime(2880)); - assertEquals("48 hours", confirmEmailUtil.friendlyExpirationTime(2880)); - System.out.println("150 minutes: " + confirmEmailUtil.friendlyExpirationTime(150)); - assertEquals("2.5 hours", confirmEmailUtil.friendlyExpirationTime(150)); - System.out.println("165 minutes: " + confirmEmailUtil.friendlyExpirationTime(165)); - assertEquals("2.75 hours", confirmEmailUtil.friendlyExpirationTime(165)); - System.out.println("1 Minute: " + confirmEmailUtil.friendlyExpirationTime(1)); - assertEquals("1 minute", confirmEmailUtil.friendlyExpirationTime(1)); + System.out.println("90 Minutes: " + ConfirmEmailUtil.friendlyExpirationTime(90)); + assertEquals("1.5 hours", ConfirmEmailUtil.friendlyExpirationTime(90)); + System.out.println("2880 minutes: " + ConfirmEmailUtil.friendlyExpirationTime(2880)); + assertEquals("48 hours", ConfirmEmailUtil.friendlyExpirationTime(2880)); + System.out.println("150 minutes: " + ConfirmEmailUtil.friendlyExpirationTime(150)); + assertEquals("2.5 hours", ConfirmEmailUtil.friendlyExpirationTime(150)); + System.out.println("165 minutes: " + ConfirmEmailUtil.friendlyExpirationTime(165)); + assertEquals("2.75 hours", ConfirmEmailUtil.friendlyExpirationTime(165)); + System.out.println("1 Minute: " + ConfirmEmailUtil.friendlyExpirationTime(1)); + assertEquals("1 minute", ConfirmEmailUtil.friendlyExpirationTime(1)); System.out.println(); } @Test public void testGrandfatheredTime() { - ConfirmEmailUtil confirmEmailUtil = new ConfirmEmailUtil(); System.out.println(); System.out.println("Grandfathered account timestamp test"); - System.out.println("Grandfathered Time (y2k): " + confirmEmailUtil.getGrandfatheredTime()); - assertEquals(Timestamp.valueOf("2000-01-01 00:00:00.0"), confirmEmailUtil.getGrandfatheredTime()); + System.out.println("Grandfathered Time (y2k): " + ConfirmEmailUtil.getGrandfatheredTime()); + assertEquals(Timestamp.valueOf("2000-01-01 00:00:00.0"), ConfirmEmailUtil.getGrandfatheredTime()); System.out.println(); } diff --git a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreatePrivateUrlCommandTest.java b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreatePrivateUrlCommandTest.java index a71ad732d8d..348f3e7b2dd 100644 --- a/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreatePrivateUrlCommandTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/engine/command/impl/CreatePrivateUrlCommandTest.java @@ -152,7 +152,6 @@ public void testCreatePrivateUrlSuccessfully() throws CommandException { PrivateUrlUser expectedUser = new PrivateUrlUser(dataset.getId()); assertEquals(expectedUser.getIdentifier(), privateUrl.getRoleAssignment().getAssigneeIdentifier()); assertEquals(expectedUser.isSuperuser(), false); - assertEquals(expectedUser.isBuiltInUser(), false); assertEquals(expectedUser.isAuthenticated(), false); assertEquals(expectedUser.getDisplayInfo().getTitle(), "Private URL Enabled"); assertNotNull(privateUrl.getToken()); diff --git a/src/test/java/edu/harvard/iq/dataverse/mocks/MockBuiltinUserServiceBean.java b/src/test/java/edu/harvard/iq/dataverse/mocks/MockBuiltinUserServiceBean.java new file mode 100644 index 00000000000..36e223da9e2 --- /dev/null +++ b/src/test/java/edu/harvard/iq/dataverse/mocks/MockBuiltinUserServiceBean.java @@ -0,0 +1,37 @@ +package edu.harvard.iq.dataverse.mocks; + +import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUser; +import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUserServiceBean; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author michael + */ +public class MockBuiltinUserServiceBean extends BuiltinUserServiceBean { + + public final Map users = new HashMap<>(); + + @Override + public BuiltinUser findByUserName(String userName) { + return users.get(userName); + } + + @Override + public BuiltinUser save(BuiltinUser aUser) { + if ( aUser.getId() == null ) { + aUser.setId( MocksFactory.nextId() ); + } + users.put( aUser.getUserName(), aUser ); + return aUser; + } + + @Override + public void removeUser(String userName) { + users.remove(userName); + } + + + +} diff --git a/src/test/java/edu/harvard/iq/dataverse/mocks/MocksFactory.java b/src/test/java/edu/harvard/iq/dataverse/mocks/MocksFactory.java index 82730f92bbf..142e1f5a1bf 100644 --- a/src/test/java/edu/harvard/iq/dataverse/mocks/MocksFactory.java +++ b/src/test/java/edu/harvard/iq/dataverse/mocks/MocksFactory.java @@ -146,10 +146,10 @@ public static Dataset makeDataset() { final List metadatas = new ArrayList<>(10); final List categories = ds.getCategories(); Random rand = new Random(); - for ( DataFile df : files ) { + files.forEach( df ->{ df.getFileMetadata().addCategory(categories.get(rand.nextInt(categories.size()))); metadatas.add( df.getFileMetadata() ); - } + }); ds.setFiles(files); final DatasetVersion initialVersion = ds.getVersions().get(0); initialVersion.setFileMetadatas(metadatas); @@ -171,10 +171,10 @@ public static DatasetVersion makeDatasetVersion(List categorie final List files = makeFiles(10); final List metadatas = new ArrayList<>(10); Random rand = new Random(); - for ( DataFile df : files ) { + files.forEach(df -> { df.getFileMetadata().addCategory(categories.get(rand.nextInt(categories.size()))); metadatas.add( df.getFileMetadata() ); - } + }); retVal.setFileMetadatas(metadatas); List fields = new ArrayList<>();