mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUAC-1176: Implement password reset logic within UserService, like the rest of user auth.
This commit is contained in:
@@ -24,17 +24,10 @@ package org.glyptodon.guacamole.auth.jdbc.user;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Arrays;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.form.Field;
|
||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service which creates new UserContext instances for valid users based on
|
||||
@@ -44,11 +37,6 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class UserContextService {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
|
||||
|
||||
/**
|
||||
* Service for accessing users.
|
||||
*/
|
||||
@@ -61,42 +49,6 @@ public class UserContextService {
|
||||
@Inject
|
||||
private Provider<UserContext> userContextProvider;
|
||||
|
||||
/**
|
||||
* The name of the HTTP password parameter to expect if the user is
|
||||
* changing their expired password upon login.
|
||||
*/
|
||||
private static final String NEW_PASSWORD_PARAMETER = "new-password";
|
||||
|
||||
/**
|
||||
* The password field to provide the user when their password is expired
|
||||
* and must be changed.
|
||||
*/
|
||||
private static final Field NEW_PASSWORD = new Field(NEW_PASSWORD_PARAMETER, "New password", Field.Type.PASSWORD);
|
||||
|
||||
/**
|
||||
* The name of the HTTP password confirmation parameter to expect if the
|
||||
* user is changing their expired password upon login.
|
||||
*/
|
||||
private static final String CONFIRM_NEW_PASSWORD_PARAMETER = "confirm-new-password";
|
||||
|
||||
/**
|
||||
* The password confirmation field to provide the user when their password
|
||||
* is expired and must be changed.
|
||||
*/
|
||||
private static final Field CONFIRM_NEW_PASSWORD = new Field(CONFIRM_NEW_PASSWORD_PARAMETER, "Confirm new password", Field.Type.PASSWORD);
|
||||
|
||||
/**
|
||||
* Information describing the expected credentials if a user's password is
|
||||
* expired. If a user's password is expired, it must be changed during the
|
||||
* login process.
|
||||
*/
|
||||
private static final CredentialsInfo EXPIRED_PASSWORD = new CredentialsInfo(Arrays.asList(
|
||||
CredentialsInfo.USERNAME,
|
||||
CredentialsInfo.PASSWORD,
|
||||
NEW_PASSWORD,
|
||||
CONFIRM_NEW_PASSWORD
|
||||
));
|
||||
|
||||
/**
|
||||
* Authenticates the user having the given credentials, returning a new
|
||||
* UserContext instance only if the credentials are valid. If the
|
||||
@@ -120,38 +72,7 @@ public class UserContextService {
|
||||
|
||||
// Authenticate user
|
||||
ModeledUser user = userService.retrieveUser(credentials);
|
||||
if (user != null && !user.getModel().isDisabled()) {
|
||||
|
||||
// Update password if password is expired
|
||||
if (user.getModel().isExpired()) {
|
||||
|
||||
// Pull new password from HTTP request
|
||||
HttpServletRequest request = credentials.getRequest();
|
||||
String newPassword = request.getParameter(NEW_PASSWORD_PARAMETER);
|
||||
String confirmNewPassword = request.getParameter(CONFIRM_NEW_PASSWORD_PARAMETER);
|
||||
|
||||
// Require new password if account is expired
|
||||
if (newPassword == null || confirmNewPassword == null) {
|
||||
logger.info("The password of user \"{}\" has expired and must be reset.", user.getIdentifier());
|
||||
throw new GuacamoleInsufficientCredentialsException("Password expired", EXPIRED_PASSWORD);
|
||||
}
|
||||
|
||||
// New password must be different from old password
|
||||
if (newPassword.equals(credentials.getPassword()))
|
||||
throw new GuacamoleClientException("LOGIN.ERROR_PASSWORD_SAME");
|
||||
|
||||
// New password must not be blank
|
||||
if (newPassword.isEmpty())
|
||||
throw new GuacamoleClientException("LOGIN.ERROR_PASSWORD_BLANK");
|
||||
|
||||
// Confirm that the password was entered correctly twice
|
||||
if (!newPassword.equals(confirmNewPassword))
|
||||
throw new GuacamoleClientException("LOGIN.ERROR_PASSWORD_MISMATCH");
|
||||
|
||||
// STUB: Change password if new password given
|
||||
logger.info("Resetting expired password of user \"{}\".", user.getIdentifier());
|
||||
|
||||
}
|
||||
if (user != null) {
|
||||
|
||||
// Upon successful authentication, return new user context
|
||||
UserContext context = userContextProvider.get();
|
||||
|
@@ -27,6 +27,7 @@ import com.google.inject.Provider;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
|
||||
import org.glyptodon.guacamole.auth.jdbc.base.ModeledDirectoryObjectService;
|
||||
@@ -37,11 +38,16 @@ import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
|
||||
import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionModel;
|
||||
import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionMapper;
|
||||
import org.glyptodon.guacamole.auth.jdbc.security.PasswordEncryptionService;
|
||||
import org.glyptodon.guacamole.form.Field;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
@@ -51,6 +57,11 @@ import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
||||
*/
|
||||
public class UserService extends ModeledDirectoryObjectService<ModeledUser, User, UserModel> {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
|
||||
|
||||
/**
|
||||
* All user permissions which are implicitly granted to the new user upon
|
||||
* creation.
|
||||
@@ -59,7 +70,43 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
ObjectPermission.Type.READ,
|
||||
ObjectPermission.Type.UPDATE
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The name of the HTTP password parameter to expect if the user is
|
||||
* changing their expired password upon login.
|
||||
*/
|
||||
private static final String NEW_PASSWORD_PARAMETER = "new-password";
|
||||
|
||||
/**
|
||||
* The password field to provide the user when their password is expired
|
||||
* and must be changed.
|
||||
*/
|
||||
private static final Field NEW_PASSWORD = new Field(NEW_PASSWORD_PARAMETER, "New password", Field.Type.PASSWORD);
|
||||
|
||||
/**
|
||||
* The name of the HTTP password confirmation parameter to expect if the
|
||||
* user is changing their expired password upon login.
|
||||
*/
|
||||
private static final String CONFIRM_NEW_PASSWORD_PARAMETER = "confirm-new-password";
|
||||
|
||||
/**
|
||||
* The password confirmation field to provide the user when their password
|
||||
* is expired and must be changed.
|
||||
*/
|
||||
private static final Field CONFIRM_NEW_PASSWORD = new Field(CONFIRM_NEW_PASSWORD_PARAMETER, "Confirm new password", Field.Type.PASSWORD);
|
||||
|
||||
/**
|
||||
* Information describing the expected credentials if a user's password is
|
||||
* expired. If a user's password is expired, it must be changed during the
|
||||
* login process.
|
||||
*/
|
||||
private static final CredentialsInfo EXPIRED_PASSWORD = new CredentialsInfo(Arrays.asList(
|
||||
CredentialsInfo.USERNAME,
|
||||
CredentialsInfo.PASSWORD,
|
||||
NEW_PASSWORD,
|
||||
CONFIRM_NEW_PASSWORD
|
||||
));
|
||||
|
||||
/**
|
||||
* Mapper for accessing users.
|
||||
*/
|
||||
@@ -213,7 +260,9 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
|
||||
/**
|
||||
* Retrieves the user corresponding to the given credentials from the
|
||||
* database.
|
||||
* database. If the user account is expired, and the credentials contain
|
||||
* the necessary additional parameters to reset the user's password, the
|
||||
* password is reset.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials to use when locating the user.
|
||||
@@ -221,8 +270,12 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
* @return
|
||||
* The existing ModeledUser object if the credentials given are valid,
|
||||
* null otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the provided credentials to not conform to expectations.
|
||||
*/
|
||||
public ModeledUser retrieveUser(Credentials credentials) {
|
||||
public ModeledUser retrieveUser(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get username and password
|
||||
String username = credentials.getUsername();
|
||||
@@ -233,19 +286,55 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
if (userModel == null)
|
||||
return null;
|
||||
|
||||
// If password hash matches, return the retrieved user
|
||||
byte[] hash = encryptionService.createPasswordHash(password, userModel.getPasswordSalt());
|
||||
if (Arrays.equals(hash, userModel.getPasswordHash())) {
|
||||
// If user is disabled, pretend user does not exist
|
||||
if (userModel.isDisabled())
|
||||
return null;
|
||||
|
||||
// Return corresponding user, set up cyclic reference
|
||||
ModeledUser user = getObjectInstance(null, userModel);
|
||||
user.setCurrentUser(new AuthenticatedUser(user, credentials));
|
||||
return user;
|
||||
// Verify provided password is correct
|
||||
byte[] hash = encryptionService.createPasswordHash(password, userModel.getPasswordSalt());
|
||||
if (!Arrays.equals(hash, userModel.getPasswordHash()))
|
||||
return null;
|
||||
|
||||
// Create corresponding user object, set up cyclic reference
|
||||
ModeledUser user = getObjectInstance(null, userModel);
|
||||
user.setCurrentUser(new AuthenticatedUser(user, credentials));
|
||||
|
||||
// Update password if password is expired
|
||||
if (userModel.isExpired()) {
|
||||
|
||||
// Pull new password from HTTP request
|
||||
HttpServletRequest request = credentials.getRequest();
|
||||
String newPassword = request.getParameter(NEW_PASSWORD_PARAMETER);
|
||||
String confirmNewPassword = request.getParameter(CONFIRM_NEW_PASSWORD_PARAMETER);
|
||||
|
||||
// Require new password if account is expired
|
||||
if (newPassword == null || confirmNewPassword == null) {
|
||||
logger.info("The password of user \"{}\" has expired and must be reset.", username);
|
||||
throw new GuacamoleInsufficientCredentialsException("LOGIN.INFO_PASSWORD_EXPIRED", EXPIRED_PASSWORD);
|
||||
}
|
||||
|
||||
// New password must be different from old password
|
||||
if (newPassword.equals(credentials.getPassword()))
|
||||
throw new GuacamoleClientException("LOGIN.ERROR_PASSWORD_SAME");
|
||||
|
||||
// New password must not be blank
|
||||
if (newPassword.isEmpty())
|
||||
throw new GuacamoleClientException("LOGIN.ERROR_PASSWORD_BLANK");
|
||||
|
||||
// Confirm that the password was entered correctly twice
|
||||
if (!newPassword.equals(confirmNewPassword))
|
||||
throw new GuacamoleClientException("LOGIN.ERROR_PASSWORD_MISMATCH");
|
||||
|
||||
// Change password and reset expiration flag
|
||||
userModel.setExpired(false);
|
||||
user.setPassword(newPassword);
|
||||
userMapper.update(userModel);
|
||||
logger.info("Expired password of user \"{}\" has been reset.", username);
|
||||
|
||||
}
|
||||
|
||||
// Otherwise, the credentials do not match
|
||||
return null;
|
||||
// Return now-authenticated user
|
||||
return user;
|
||||
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,8 @@
|
||||
"ERROR_PASSWORD_SAME" : "The new password must be different from the expired password.",
|
||||
"ERROR_PASSWORD_MISMATCH" : "@:APP.ERROR_PASSWORD_MISMATCH",
|
||||
|
||||
"INFO_PASSWORD_EXPIRED" : "Your password has expired and must be reset. Please enter a new password to continue.",
|
||||
|
||||
"FIELD_HEADER_NEW_PASSWORD" : "New password",
|
||||
"FIELD_HEADER_CONFIRM_NEW_PASSWORD" : "Confirm new password"
|
||||
|
||||
|
Reference in New Issue
Block a user