Skip to content

Commit

Permalink
Merge pull request #3931 from IQSS/3246-user-login
Browse files Browse the repository at this point in the history
#3246: added last login/creation time/last API use for authenticateduser
  • Loading branch information
kcondon authored Jun 27, 2017
2 parents ba61257 + 5aaeb2e commit 982b9db
Show file tree
Hide file tree
Showing 18 changed files with 557 additions and 804 deletions.
2 changes: 1 addition & 1 deletion scripts/database/upgrades/upgrade_v4.6.2_to_v4.7.sql
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
--Uncomment to preserve "Dataverse" at end of each dataverse name.
--UPDATE dataverse SET name = name || ' Dataverse';
--UPDATE dataverse SET name = name || ' Dataverse';
7 changes: 7 additions & 0 deletions scripts/database/upgrades/upgrade_v4.7_to_v4.7.1.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Adding new columns for "createdtime", "lastlogintime", and "lastapiusetime"
-- Default "createdtime" to 1/1/2000
-- Dropping "modificationtime" as it is inconsistent between user auths and best replaced by the new columns.
ALTER TABLE authenticateduser ADD COLUMN createdtime TIMESTAMP NOT NULL DEFAULT '01-01-2000 00:00:00';
ALTER TABLE authenticateduser ADD COLUMN lastlogintime TIMESTAMP DEFAULT NULL;
ALTER TABLE authenticateduser ADD COLUMN lastapiusetime TIMESTAMP DEFAULT NULL;
ALTER TABLE authenticateduser DROP COLUMN modificationtime;
24 changes: 22 additions & 2 deletions src/main/java/edu/harvard/iq/dataverse/UserServiceBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.search.IndexServiceBean;
import java.sql.Timestamp;
import java.util.Date;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
Expand All @@ -24,15 +26,33 @@ public AuthenticatedUser find(Object pk) {
return (AuthenticatedUser) em.find(AuthenticatedUser.class, pk);
}

public AuthenticatedUser save( AuthenticatedUser user ) {
if ( user.getId() == null ) {

public AuthenticatedUser save(AuthenticatedUser user) {
if (user.getId() == null) {
em.persist(this);
} else {
if (user.getCreatedTime() == null) {
user.setCreatedTime(new Timestamp(new Date().getTime())); // default new creation time
user.setLastLoginTime(user.getCreatedTime()); // sets initial lastLoginTime to creation time
logger.info("Creation time null! Setting user creation time to now");
}
user = em.merge(user);
}
em.flush();

return user;
}

public AuthenticatedUser updateLastLogin(AuthenticatedUser user) {
//assumes that AuthenticatedUser user already exists
user.setLastLoginTime(new Timestamp(new Date().getTime()));

return save(user);
}

public AuthenticatedUser updateLastApiUseTime(AuthenticatedUser user) {
//assumes that AuthenticatedUser user already exists
user.setLastApiUseTime(new Timestamp(new Date().getTime()));
return save(user);
}
}
10 changes: 7 additions & 3 deletions src/main/java/edu/harvard/iq/dataverse/api/AbstractApiBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,14 @@ protected AuthenticatedUser findAuthenticatedUserOrDie() throws WrappedResponse
return findAuthenticatedUserOrDie(getRequestApiKey());
}


private AuthenticatedUser findAuthenticatedUserOrDie( String key ) throws WrappedResponse {
AuthenticatedUser u = authSvc.lookupUser(key);
if ( u != null ) {
return u;
AuthenticatedUser authUser = authSvc.lookupUser(key);
if ( authUser != null ) {
System.out.println("Updating lastApiUseTime for authenticated user via abstractapibean");
authUser = userSvc.updateLastApiUseTime(authUser);

return authUser;
}
throw new WrappedResponse( badApiKey(key) );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public AuthenticatedUser auth(AuthCredentials authCredentials) throws SwordAuthE
logger.fine(msg);
throw new SwordAuthException(msg);
} else {

authenticatedUserFromToken = userSvc.updateLastApiUseTime(authenticatedUserFromToken);
return authenticatedUserFromToken;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package edu.harvard.iq.dataverse.authorization;

import edu.harvard.iq.dataverse.UserNotificationServiceBean;
import edu.harvard.iq.dataverse.UserServiceBean;
import edu.harvard.iq.dataverse.search.IndexServiceBean;
import edu.harvard.iq.dataverse.actionlogging.ActionLogRecord;
import edu.harvard.iq.dataverse.actionlogging.ActionLogServiceBean;
Expand Down Expand Up @@ -95,6 +96,9 @@ public class AuthenticationServiceBean {
@EJB
PasswordResetServiceBean passwordResetServiceBean;

@EJB
UserServiceBean userService;

@PersistenceContext(unitName = "VDCNet-ejbPU")
private EntityManager em;

Expand Down Expand Up @@ -321,13 +325,17 @@ public AuthenticatedUser authenticate( String authenticationProviderId, Authenti
// yay! see if we already have this user.
AuthenticatedUser user = lookupUser(authenticationProviderId, resp.getUserId());

if (user != null){
user = userService.updateLastLogin(user);
}

/**
* @todo Why does a method called "authenticate" have the potential
* to call "createAuthenticatedUser"? Isn't the creation of a user a
* different action than authenticating?
*
* @todo Wouldn't this be more readable with if/else rather than
* ternary?
* ternary? (please)
*/
return ( user == null ) ?
AuthenticationServiceBean.this.createAuthenticatedUser(
Expand Down Expand Up @@ -433,14 +441,12 @@ public AuthenticatedUser lookupUser( String apiToken ) {
}

public AuthenticatedUser save( AuthenticatedUser user ) {
user.setModificationTime(getCurrentTimestamp());
em.persist(user);
em.flush();
return user;
}

public AuthenticatedUser update( AuthenticatedUser user ) {
user.setModificationTime(getCurrentTimestamp());
return em.merge(user);
}

Expand Down Expand Up @@ -493,12 +499,16 @@ public boolean updateProvider( AuthenticatedUser authenticatedUser, String authe
* @throws EJBException which may wrap an ConstraintViolationException if the proposed user does not pass bean validation.
*/
public AuthenticatedUser createAuthenticatedUser(UserRecordIdentifier userRecordId,
String proposedAuthenticatedUserIdentifier,
AuthenticatedUserDisplayInfo userDisplayInfo,
boolean generateUniqueIdentifier) {
String proposedAuthenticatedUserIdentifier,
AuthenticatedUserDisplayInfo userDisplayInfo,
boolean generateUniqueIdentifier) {
AuthenticatedUser authenticatedUser = new AuthenticatedUser();
authenticatedUser.applyDisplayInfo(userDisplayInfo);
// set account creation time & initial login time (same timestamp)
authenticatedUser.setCreatedTime(new Timestamp(new Date().getTime()));
authenticatedUser.setLastLoginTime(authenticatedUser.getCreatedTime());

authenticatedUser.applyDisplayInfo(userDisplayInfo);

// we have no desire for leading or trailing whitespace in identifiers
if (proposedAuthenticatedUserIdentifier != null) {
proposedAuthenticatedUserIdentifier = proposedAuthenticatedUserIdentifier.trim();
Expand Down Expand Up @@ -535,7 +545,7 @@ public AuthenticatedUser createAuthenticatedUser(UserRecordIdentifier userRecord
* better to do something like "startConfirmEmailProcessForNewUser". */
confirmEmailService.createToken(authenticatedUser);
}

actionLogSvc.log( new ActionLogRecord(ActionLogRecord.ActionType.Auth, "createUser")
.setInfo(authenticatedUser.getIdentifier()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
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.UserServiceBean;
import edu.harvard.iq.dataverse.authorization.AuthUtil;
import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo;
import edu.harvard.iq.dataverse.authorization.AuthenticationProvider;
Expand Down Expand Up @@ -82,6 +83,8 @@ public enum EditMode {
@EJB
UserNotificationServiceBean userNotificationService;
@EJB
UserServiceBean userService;
@EJB
DatasetServiceBean datasetService;
@EJB
DataFileServiceBean fileService;
Expand Down Expand Up @@ -307,14 +310,17 @@ public String save() {
new UserRecordIdentifier(BuiltinAuthenticationProvider.PROVIDER_ID, builtinUser.getUserName()),
builtinUser.getUserName(), builtinUser.getDisplayInfo(), false);
if ( au == null ) {
// username exists
// Username already exists, show an error message
getUsernameField().setValid(false);
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;
}

// The Authenticated User was just created via the UI, add an initial login timestamp
au = userService.updateLastLogin(au);

// Authenticated user registered. Save the new bulitin, and log in.
builtinUserService.save(builtinUser);
session.setUser(au);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static edu.harvard.iq.dataverse.util.StringUtil.nonEmpty;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.persistence.CascadeType;
Expand Down Expand Up @@ -73,19 +74,26 @@ public class AuthenticatedUser implements User, Serializable {
private String email;
private String affiliation;
private String position;

@NotBlank(message = "Please enter your last name.")
private String lastName;

@NotBlank(message = "Please enter your first name.")
private String firstName;

@Column(nullable = true)
private Timestamp emailConfirmed;
private boolean superuser;
//TODO: add the word time after next 3 columns
@Column(nullable=false)
private Timestamp createdTime;

@Column(nullable=true)
private Timestamp lastLoginTime; // last user login timestamp

/**
* @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;
@Column(nullable=true)
private Timestamp lastApiUseTime; // last API use with user's token

private boolean superuser;

/**
* @todo Consider storing a hash of *all* potentially interesting Shibboleth
Expand Down Expand Up @@ -213,10 +221,6 @@ public void setSuperuser(boolean superuser) {
this.superuser = superuser;
}

public void setModificationTime(Timestamp modificationTime) {
this.modificationTime = modificationTime;
}

@OneToOne(mappedBy = "authenticatedUser")
private AuthenticatedUserLookup authenticatedUserLookup;

Expand Down Expand Up @@ -262,4 +266,47 @@ public String getSortByString() {
return this.getLastName() + " " + this.getFirstName() + " " + this.getUserIdentifier();
}

}
/**
*
* @param lastLoginTime
*/
public void setLastLoginTime(Timestamp lastLoginTime){

this.lastLoginTime = lastLoginTime;
}

/**
* @param lastLoginTime
*/
public Timestamp getLastLoginTime(){
return this.lastLoginTime;
}


public void setCreatedTime(Timestamp createdTime){
this.createdTime = createdTime;
}

public Timestamp getCreatedTime(){
return this.createdTime;
}


/**
*
* @param lastApiUseTime
*/
public void setLastApiUseTime(Timestamp lastApiUseTime){
this.lastApiUseTime = lastApiUseTime;
}

/**
*
* @param lastApiUseTime
*/
public Timestamp getLastApiUseTime(){

return this.lastApiUseTime;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ public static JsonObjectBuilder jsonForAuthUser(AuthenticatedUser authenticatedU
.add("position", authenticatedUser.getPosition())
.add("persistentUserId", authenticatedUser.getAuthenticatedUserLookup().getPersistentUserId())
.add("emailLastConfirmed", authenticatedUser.getEmailConfirmed())
.add("createdTime", authenticatedUser.getCreatedTime())
.add("lastLoginTime", authenticatedUser.getLastLoginTime())
.add("lastApiUseTime", authenticatedUser.getLastApiUseTime())
.add("authenticationProviderId", authenticatedUser.getAuthenticatedUserLookup().getAuthenticationProviderId());
}

Expand Down
39 changes: 0 additions & 39 deletions src/main/webapp/file_replace/dataset_file_list.xhtml

This file was deleted.

Loading

0 comments on commit 982b9db

Please sign in to comment.