diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/security/PasswordPolicyService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/security/PasswordPolicyService.java index a47c03894..dfa980c0b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/security/PasswordPolicyService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/security/PasswordPolicyService.java @@ -26,6 +26,7 @@ import java.util.regex.Pattern; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.auth.jdbc.JDBCEnvironment; import org.apache.guacamole.auth.jdbc.user.ModeledUser; +import org.apache.guacamole.auth.jdbc.user.PasswordRecordModel; /** * Service which verifies compliance with the password policy configured via @@ -161,9 +162,14 @@ public class PasswordPolicyService { */ private long getPasswordAge(ModeledUser user) { + // If no password was set, then no time has elapsed + PasswordRecordModel previousPassword = user.getPreviousPassword(); + if (previousPassword == null) + return 0; + // Pull both current time and the time the password was last reset long currentTime = System.currentTimeMillis(); - long lastResetTime = user.getPreviousPasswordDate().getTime(); + long lastResetTime = previousPassword.getPasswordDate().getTime(); // Calculate the number of days elapsed since the password was last reset return TimeUnit.DAYS.convert(currentTime - lastResetTime, TimeUnit.MILLISECONDS); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index 2f1e58382..18a13eccb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -189,10 +189,10 @@ public class ModeledUser extends ModeledDirectoryObject implements Us private String password = null; /** - * The time and date that this user's password was previously set (prior to - * being queried). If the user is new, this will be null. + * The data associated with this user's password at the time this user was + * queried. If the user is new, this will be null. */ - private Timestamp previousPasswordDate = null; + private PasswordRecordModel previousPassword = null; /** * Creates a new, empty ModeledUser. @@ -202,8 +202,13 @@ public class ModeledUser extends ModeledDirectoryObject implements Us @Override public void setModel(UserModel model) { + super.setModel(model); - this.previousPasswordDate = model.getPasswordDate(); + + // Store previous password, if any + if (model.getPasswordHash() != null) + this.previousPassword = new PasswordRecordModel(model); + } @Override @@ -240,19 +245,19 @@ public class ModeledUser extends ModeledDirectoryObject implements Us } /** - * Returns the time and date that this user's password was previously set. - * If the user is new, this will be null. Unlike getPasswordDate() of - * UserModel (which is updated automatically along with the password salt - * and hash whenever setPassword() is invoked), this value is unaffected by - * calls to setPassword(), and will always be the value stored in the - * database at the time this user was queried. + * Returns the data associated with this user's previous password as a + * password record. If the user is new, this will be null. Unlike the other + * password-related functions of UserModel, this data returned by this + * function is historical and is unaffected by calls to setPassword(). It + * will always return the values stored in the database at the time this + * user was queried. * * @return - * The time and date that this user's password was previously set, or - * null if the user is new. + * The data associated with this user's previous password, or null if + * the user is new. */ - public Timestamp getPreviousPasswordDate() { - return previousPasswordDate; + public PasswordRecordModel getPreviousPassword() { + return previousPassword; } /** diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/PasswordRecordModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/PasswordRecordModel.java new file mode 100644 index 000000000..4b34f8038 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/PasswordRecordModel.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.user; + +import java.sql.Timestamp; + +/** + * A single password record representing a previous password of a particular + * user, along with the time/date that password was set. + * + * @author Michael Jumper + */ +public class PasswordRecordModel { + + /** + * The database ID of the user associated with this password record. + */ + private Integer userID; + + /** + * The hash of the password and salt. + */ + private byte[] passwordHash; + + /** + * The random salt that was appended to the password prior to hashing. + */ + private byte[] passwordSalt; + + /** + * The date and time when this password was first set for the associated + * user. + */ + private Timestamp passwordDate; + + /** + * Creates a new, empty PasswordRecordModel. + */ + public PasswordRecordModel() { + } + + /** + * Creates a new PasswordRecordModel associated with the given user and + * populated with that user's password hash and salt. + * + * @param user + * The user to associate with this PasswordRecordModel. + */ + public PasswordRecordModel(UserModel user) { + this.userID = user.getObjectID(); + this.passwordHash = user.getPasswordHash(); + this.passwordSalt = user.getPasswordSalt(); + this.passwordDate = user.getPasswordDate(); + } + + /** + * Returns the database ID of the user associated with this password + * record. + * + * @return + * The database ID of the user associated with this password record. + */ + public Integer getUserID() { + return userID; + } + + /** + * Sets the database ID of the user associated with this password record. + * + * @param userID + * The database ID of the user to associate with this password + * record. + */ + public void setUserID(Integer userID) { + this.userID = userID; + } + + /** + * Returns the hash of the password and password salt. + * + * @return + * The hash of the password and password salt. + */ + public byte[] getPasswordHash() { + return passwordHash; + } + + /** + * Sets the hash of the password and password salt. + * + * @param passwordHash + * The hash of the password and password salt. + */ + public void setPasswordHash(byte[] passwordHash) { + this.passwordHash = passwordHash; + } + + /** + * Returns the random salt that was used when generating the password hash. + * + * @return + * The random salt that was used when generating the password hash. + */ + public byte[] getPasswordSalt() { + return passwordSalt; + } + + /** + * Sets the random salt that was used when generating the password hash. + * + * @param passwordSalt + * The random salt used when generating the password hash. + */ + public void setPasswordSalt(byte[] passwordSalt) { + this.passwordSalt = passwordSalt; + } + + /** + * Returns the date that this password was first set for the associated + * user. + * + * @return + * The date that this password was first set for the associated user. + */ + public Timestamp getPasswordDate() { + return passwordDate; + } + + /** + * Sets the date that this password was first set for the associated user. + * + * @param passwordDate + * The date that this password was first set for the associated user. + */ + public void setPasswordDate(Timestamp passwordDate) { + this.passwordDate = passwordDate; + } + +}