mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 21:27:40 +00:00
GUACAMOLE-36: Record and maintain password history.
This commit is contained in:
@@ -72,6 +72,20 @@ public interface PasswordPolicy {
|
|||||||
*/
|
*/
|
||||||
int getMaximumAge() throws GuacamoleException;
|
int getMaximumAge() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of previous passwords remembered for each user. If
|
||||||
|
* greater than zero, users will be prohibited from reusing their past
|
||||||
|
* passwords.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The number of previous passwords remembered for each user.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the password history size cannot be parsed from
|
||||||
|
* guacamole.properties.
|
||||||
|
*/
|
||||||
|
int getHistorySize() throws GuacamoleException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether both uppercase and lowercase characters must be present
|
* Returns whether both uppercase and lowercase characters must be present
|
||||||
* in new passwords. If true, passwords which do not have at least one
|
* in new passwords. If true, passwords which do not have at least one
|
||||||
|
@@ -26,6 +26,7 @@ import java.util.regex.Pattern;
|
|||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||||
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
|
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
|
||||||
|
import org.apache.guacamole.auth.jdbc.user.PasswordRecordMapper;
|
||||||
import org.apache.guacamole.auth.jdbc.user.PasswordRecordModel;
|
import org.apache.guacamole.auth.jdbc.user.PasswordRecordModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,6 +43,12 @@ public class PasswordPolicyService {
|
|||||||
@Inject
|
@Inject
|
||||||
private JDBCEnvironment environment;
|
private JDBCEnvironment environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapper for creating/retrieving previously-set passwords.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private PasswordRecordMapper passwordRecordMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regular expression which matches only if the string contains at least one
|
* Regular expression which matches only if the string contains at least one
|
||||||
* lowercase character.
|
* lowercase character.
|
||||||
@@ -235,4 +242,32 @@ public class PasswordPolicyService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records the password that was associated with the given user at the time
|
||||||
|
* the user was queried, such that future attempts to set that same password
|
||||||
|
* for that user will be denied. The number of passwords remembered for each
|
||||||
|
* user is limited by the password policy.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user whose previous password should be recorded.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the password policy cannot be parsed.
|
||||||
|
*/
|
||||||
|
public void recordPreviousPassword(ModeledUser user)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
// Retrieve password policy from environment
|
||||||
|
PasswordPolicy policy = environment.getPasswordPolicy();
|
||||||
|
|
||||||
|
// Nothing to do if history is not being recorded
|
||||||
|
int historySize = policy.getHistorySize();
|
||||||
|
if (historySize <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Store previous password in history
|
||||||
|
passwordRecordMapper.insert(user.getPreviousPassword(), historySize);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -242,6 +242,9 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
|||||||
// Always verify password complexity
|
// Always verify password complexity
|
||||||
passwordPolicyService.verifyPassword(object.getIdentifier(), object.getPassword());
|
passwordPolicyService.verifyPassword(object.getIdentifier(), object.getPassword());
|
||||||
|
|
||||||
|
// Store previous password in history
|
||||||
|
passwordPolicyService.recordPreviousPassword(object);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -71,6 +71,19 @@ public class MySQLPasswordPolicy implements PasswordPolicy {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The property which specifies the number of previous passwords remembered
|
||||||
|
* for each user. If set to zero, the default, then this restriction does
|
||||||
|
* not apply.
|
||||||
|
*/
|
||||||
|
private static final IntegerGuacamoleProperty HISTORY_SIZE =
|
||||||
|
new IntegerGuacamoleProperty() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() { return "mysql-user-password-history-size"; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The property which specifies whether all user passwords must have at
|
* The property which specifies whether all user passwords must have at
|
||||||
* least one lowercase character and one uppercase character. By default,
|
* least one lowercase character and one uppercase character. By default,
|
||||||
@@ -155,6 +168,11 @@ public class MySQLPasswordPolicy implements PasswordPolicy {
|
|||||||
return environment.getProperty(MAX_AGE, 0);
|
return environment.getProperty(MAX_AGE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHistorySize() throws GuacamoleException {
|
||||||
|
return environment.getProperty(HISTORY_SIZE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMultipleCaseRequired() throws GuacamoleException {
|
public boolean isMultipleCaseRequired() throws GuacamoleException {
|
||||||
return environment.getProperty(REQUIRE_MULTIPLE_CASE, false);
|
return environment.getProperty(REQUIRE_MULTIPLE_CASE, false);
|
||||||
|
@@ -63,7 +63,19 @@
|
|||||||
#{record.passwordHash,jdbcType=BINARY},
|
#{record.passwordHash,jdbcType=BINARY},
|
||||||
#{record.passwordSalt,jdbcType=BINARY},
|
#{record.passwordSalt,jdbcType=BINARY},
|
||||||
#{record.passwordDate,jdbcType=TIMESTAMP}
|
#{record.passwordDate,jdbcType=TIMESTAMP}
|
||||||
)
|
);
|
||||||
|
|
||||||
|
DELETE FROM guacamole_user_password_history
|
||||||
|
WHERE password_history_id <= (
|
||||||
|
SELECT password_history_id
|
||||||
|
FROM (
|
||||||
|
SELECT password_history_id
|
||||||
|
FROM guacamole_user_password_history
|
||||||
|
WHERE user_id = #{record.userID,jdbcType=INTEGER}
|
||||||
|
ORDER BY password_date DESC
|
||||||
|
LIMIT 1 OFFSET #{maxHistorySize}
|
||||||
|
) old_password_record
|
||||||
|
);
|
||||||
|
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
@@ -71,6 +71,19 @@ public class PostgreSQLPasswordPolicy implements PasswordPolicy {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The property which specifies the number of previous passwords remembered
|
||||||
|
* for each user. If set to zero, the default, then this restriction does
|
||||||
|
* not apply.
|
||||||
|
*/
|
||||||
|
private static final IntegerGuacamoleProperty HISTORY_SIZE =
|
||||||
|
new IntegerGuacamoleProperty() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() { return "postgresql-user-password-history-size"; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The property which specifies whether all user passwords must have at
|
* The property which specifies whether all user passwords must have at
|
||||||
* least one lowercase character and one uppercase character. By default,
|
* least one lowercase character and one uppercase character. By default,
|
||||||
@@ -155,6 +168,11 @@ public class PostgreSQLPasswordPolicy implements PasswordPolicy {
|
|||||||
return environment.getProperty(MAX_AGE, 0);
|
return environment.getProperty(MAX_AGE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHistorySize() throws GuacamoleException {
|
||||||
|
return environment.getProperty(HISTORY_SIZE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMultipleCaseRequired() throws GuacamoleException {
|
public boolean isMultipleCaseRequired() throws GuacamoleException {
|
||||||
return environment.getProperty(REQUIRE_MULTIPLE_CASE, false);
|
return environment.getProperty(REQUIRE_MULTIPLE_CASE, false);
|
||||||
|
@@ -63,7 +63,16 @@
|
|||||||
#{record.passwordHash,jdbcType=BINARY},
|
#{record.passwordHash,jdbcType=BINARY},
|
||||||
#{record.passwordSalt,jdbcType=BINARY},
|
#{record.passwordSalt,jdbcType=BINARY},
|
||||||
#{record.passwordDate,jdbcType=TIMESTAMP}
|
#{record.passwordDate,jdbcType=TIMESTAMP}
|
||||||
)
|
);
|
||||||
|
|
||||||
|
DELETE FROM guacamole_user_password_history
|
||||||
|
WHERE password_history_id IN (
|
||||||
|
SELECT password_history_id
|
||||||
|
FROM guacamole_user_password_history
|
||||||
|
WHERE user_id = #{record.userID,jdbcType=INTEGER}
|
||||||
|
ORDER BY password_date DESC
|
||||||
|
OFFSET #{maxHistorySize}
|
||||||
|
);
|
||||||
|
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user