package edu.harvard.iq.dataverse.authorization.users; import edu.harvard.iq.dataverse.DatasetLock; 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 java.io.Serializable; import java.sql.Timestamp; import java.util.List; import java.util.Objects; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.Transient; import javax.validation.constraints.NotNull; @NamedQueries({ @NamedQuery( name="AuthenticatedUser.findAll", query="select au from AuthenticatedUser au"), @NamedQuery( name="AuthenticatedUser.findSuperUsers", query="SELECT au FROM AuthenticatedUser au WHERE au.superuser = TRUE"), @NamedQuery( name="AuthenticatedUser.findByIdentifier", query="select au from AuthenticatedUser au WHERE au.userIdentifier=:identifier"), @NamedQuery( name="AuthenticatedUser.findByEmail", query="select au from AuthenticatedUser au WHERE LOWER(au.email)=LOWER(:email)"), @NamedQuery( name="AuthenticatedUser.countOfIdentifier", query="SELECT COUNT(a) FROM AuthenticatedUser a WHERE a.userIdentifier=:identifier"), @NamedQuery( name="AuthenticatedUser.filter", query="select au from AuthenticatedUser au WHERE (" + "au.userIdentifier like :query OR " + "lower(concat(au.firstName,' ',au.lastName)) like lower(:query))"), @NamedQuery( name="AuthenticatedUser.findAdminUser", query="select au from AuthenticatedUser au WHERE " + "au.superuser = true " + "order by au.id") }) @Entity public class AuthenticatedUser implements User, Serializable { public static final String IDENTIFIER_PREFIX = "@"; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; /** * @todo Shouldn't there be some constraints on what the userIdentifier is * allowed to be? It can't be as restrictive as the "userName" field on * BuiltinUser because we can't predict what Shibboleth Identity Providers * (IdPs) will send (typically in the "eppn" SAML assertion) but perhaps * spaces, for example, should be disallowed. Right now "elisah.da mota" can * be persisted as a userIdentifier per * https://github.com/IQSS/dataverse/issues/2945 */ @NotNull @Column(nullable = false, unique=true) private String userIdentifier; @ValidateEmail(message = "Please enter a valid email address.") @NotNull @Column(nullable = false, unique=true) private String email; private String affiliation; private String position; private String lastName; private String firstName; @Column(nullable = true) private Timestamp emailConfirmed; private boolean superuser; /** * @todo Remove? Check for accuracy? For Solr JOINs we used to care about * the modification times of users but now we don't index users at all. */ private Timestamp modificationTime; /** * @todo Consider storing a hash of *all* potentially interesting Shibboleth * attribute key/value pairs, not just the Identity Provider (IdP). */ @Transient private String shibIdentityProvider; @Override public String getIdentifier() { return IDENTIFIER_PREFIX + userIdentifier; } @OneToMany(mappedBy = "user", cascade={CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST}) private List<DatasetLock> datasetLocks; public List<DatasetLock> getDatasetLocks() { return datasetLocks; } public void setDatasetLocks(List<DatasetLock> datasetLocks) { this.datasetLocks = datasetLocks; } @Override public RoleAssigneeDisplayInfo getDisplayInfo() { return new AuthenticatedUserDisplayInfo(firstName, lastName, email, affiliation, position); } /** * Takes the passed info object and updated the internal fields according to it. * @param inf the info from which we update the fields. */ public void applyDisplayInfo( AuthenticatedUserDisplayInfo inf ) { setFirstName(inf.getFirstName()); setLastName(inf.getLastName()); setEmail(inf.getEmailAddress()); setAffiliation( inf.getAffiliation() ); setPosition( inf.getPosition()); } @Override public boolean isAuthenticated() { return true; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserIdentifier() { return userIdentifier; } public void setUserIdentifier(String userIdentifier) { this.userIdentifier = userIdentifier; } public String getName() { return firstName + " " + lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getAffiliation() { return affiliation; } public void setAffiliation(String affiliation) { this.affiliation = affiliation; } public String getPosition() { return position; } public void setPosition(String position) { this.position = position; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public Timestamp getEmailConfirmed() { return emailConfirmed; } public void setEmailConfirmed(Timestamp emailConfirmed) { this.emailConfirmed = emailConfirmed; } @Override public boolean isSuperuser() { return superuser; } public void setSuperuser(boolean superuser) { this.superuser = superuser; } 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; public AuthenticatedUserLookup getAuthenticatedUserLookup() { return authenticatedUserLookup; } public void setAuthenticatedUserLookup(AuthenticatedUserLookup authenticatedUserLookup) { this.authenticatedUserLookup = authenticatedUserLookup; } @Override public int hashCode() { int hash = 0; hash += (id != null ? id.hashCode() : 0); return hash; } @Override public boolean equals(Object object) { // TODO: Warning - this method won't work in the case the id fields are not set if (!(object instanceof AuthenticatedUser)) { return false; } AuthenticatedUser other = (AuthenticatedUser) object; return Objects.equals(getId(), other.getId()); } public String getShibIdentityProvider() { return shibIdentityProvider; } public void setShibIdentityProvider(String shibIdentityProvider) { this.shibIdentityProvider = shibIdentityProvider; } @Override public String toString() { return "[AuthenticatedUser identifier:" + getIdentifier() + "]"; } public String getSortByString() { return this.getLastName() + " " + this.getFirstName() + " " + this.getUserIdentifier(); } }