Skip to content

Commit

Permalink
Rewrite of AuthenticatedUser and its provider hierarchy to query prov…
Browse files Browse the repository at this point in the history
…idr capability capability rather than look at classes. Refactoring of the DataverseUserPage to adjust itself to the capabilities of the current user's provider.
  • Loading branch information
michbarsinai committed Oct 21, 2016
1 parent 692f1f1 commit c64fd62
Show file tree
Hide file tree
Showing 29 changed files with 649 additions and 493 deletions.
28 changes: 28 additions & 0 deletions doc/Architecture/update-user-account-info.puml
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions src/main/java/Bundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}

Expand All @@ -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 "";
}

Expand All @@ -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 "";
}

Expand All @@ -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 "";
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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!)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()}.
*
Expand All @@ -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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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();
Expand All @@ -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)
Expand All @@ -362,8 +369,6 @@ public ApiToken findApiToken(String token) {
}
}



public ApiToken findApiTokenByUser(AuthenticatedUser au) {
if (au == null) {
return null;
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

This file was deleted.

Loading

0 comments on commit c64fd62

Please sign in to comment.