GUAC-586: Implement AuthenticatedUser. Refactor to support authenticateUser(), etc. within the database AuthenticationProvider implementations.

This commit is contained in:
Michael Jumper
2015-08-23 23:55:42 -07:00
parent 90ae5b0e17
commit 6eee1e758c
5 changed files with 172 additions and 35 deletions

View File

@@ -25,6 +25,7 @@ package org.glyptodon.guacamole.auth.jdbc.user;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
import org.glyptodon.guacamole.net.auth.Credentials;
/**
@@ -32,7 +33,7 @@ import org.glyptodon.guacamole.net.auth.Credentials;
*
* @author Michael Jumper
*/
public class AuthenticatedUser {
public class AuthenticatedUser implements org.glyptodon.guacamole.net.auth.AuthenticatedUser {
/**
* The user that authenticated.
@@ -44,6 +45,11 @@ public class AuthenticatedUser {
*/
private final Credentials credentials;
/**
* The AuthenticationProvider that authenticated this user.
*/
private final AuthenticationProvider authenticationProvider;
/**
* The host from which this user authenticated.
*/
@@ -106,13 +112,18 @@ public class AuthenticatedUser {
* Creates a new AuthenticatedUser associating the given user with their
* corresponding credentials.
*
* @param authenticationProvider
* The AuthenticationProvider that has authenticated the given user.
*
* @param user
* The user this object should represent.
*
* @param credentials
* The credentials given by the user when they authenticated.
*/
public AuthenticatedUser(ModeledUser user, Credentials credentials) {
public AuthenticatedUser(AuthenticationProvider authenticationProvider,
ModeledUser user, Credentials credentials) {
this.authenticationProvider = authenticationProvider;
this.user = user;
this.credentials = credentials;
this.remoteHost = getRemoteHost(credentials);
@@ -134,6 +145,7 @@ public class AuthenticatedUser {
* @return
* The credentials given during authentication by this user.
*/
@Override
public Credentials getCredentials() {
return credentials;
}
@@ -148,4 +160,19 @@ public class AuthenticatedUser {
return remoteHost;
}
@Override
public AuthenticationProvider getAuthenticationProvider() {
return authenticationProvider;
}
@Override
public String getIdentifier() {
return user.getIdentifier();
}
@Override
public void setIdentifier(String identifier) {
user.setIdentifier(identifier);
}
}

View File

@@ -25,17 +25,19 @@ package org.glyptodon.guacamole.auth.jdbc.user;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
import org.glyptodon.guacamole.net.auth.Credentials;
import org.glyptodon.guacamole.net.auth.credentials.CredentialsInfo;
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
/**
* Service which creates new UserContext instances for valid users based on
* credentials.
* Service which authenticates users based on credentials and provides for
* the creation of corresponding, new UserContext objects for authenticated
* users.
*
* @author Michael Jumper
*/
public class UserContextService {
public class AuthenticationProviderService {
/**
* Service for accessing users.
@@ -51,11 +53,44 @@ public class UserContextService {
/**
* Authenticates the user having the given credentials, returning a new
* UserContext instance only if the credentials are valid. If the
* AuthenticatedUser instance only if the credentials are valid. If the
* credentials are invalid or expired, an appropriate GuacamoleException
* will be thrown.
*
* @param authenticationProvider
* The AuthenticationProvider on behalf of which the user is being
* authenticated.
*
* @param credentials
* The credentials to use to produce the AuthenticatedUser.
*
* @return
* A new AuthenticatedUser instance for the user identified by the
* given credentials.
*
* @throws GuacamoleException
* If an error occurs during authentication, or if the given
* credentials are invalid or expired.
*/
public AuthenticatedUser authenticateUser(AuthenticationProvider authenticationProvider,
Credentials credentials) throws GuacamoleException {
// Authenticate user
AuthenticatedUser user = userService.retrieveAuthenticatedUser(authenticationProvider, credentials);
if (user != null)
return user;
// Otherwise, unauthorized
throw new GuacamoleInvalidCredentialsException("Invalid login", CredentialsInfo.USERNAME_PASSWORD);
}
/**
* Returning a new UserContext instance for the given already-authenticated
* user. A new placeholder account will be created for any user that does
* not already exist within the database.
*
* @param authenticatedUser
* The credentials to use to produce the UserContext.
*
* @return
@@ -66,23 +101,18 @@ public class UserContextService {
* If an error occurs during authentication, or if the given
* credentials are invalid or expired.
*/
public org.glyptodon.guacamole.net.auth.UserContext
getUserContext(Credentials credentials)
public UserContext getUserContext(org.glyptodon.guacamole.net.auth.AuthenticatedUser authenticatedUser)
throws GuacamoleException {
// Authenticate user
ModeledUser user = userService.retrieveUser(credentials);
if (user != null) {
// Retrieve user account for already-authenticated user
ModeledUser user = userService.retrieveUser(authenticatedUser);
if (user == null)
return null;
// Upon successful authentication, return new user context
UserContext context = userContextProvider.get();
context.init(user.getCurrentUser());
return context;
}
// Otherwise, unauthorized
throw new GuacamoleInvalidCredentialsException("Invalid login", CredentialsInfo.USERNAME_PASSWORD);
// Link to user context
UserContext context = userContextProvider.get();
context.init(user.getCurrentUser());
return context;
}

View File

@@ -40,6 +40,7 @@ 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.form.PasswordField;
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.credentials.CredentialsInfo;
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
@@ -265,18 +266,22 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
* the necessary additional parameters to reset the user's password, the
* password is reset.
*
* @param authenticationProvider
* The AuthenticationProvider on behalf of which the user is being
* retrieved.
*
* @param credentials
* The credentials to use when locating the user.
*
* @return
* The existing ModeledUser object if the credentials given are valid,
* null otherwise.
* An AuthenticatedUser containing 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)
throws GuacamoleException {
public AuthenticatedUser retrieveAuthenticatedUser(AuthenticationProvider authenticationProvider,
Credentials credentials) throws GuacamoleException {
// Get username and password
String username = credentials.getUsername();
@@ -298,7 +303,7 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
// Create corresponding user object, set up cyclic reference
ModeledUser user = getObjectInstance(null, userModel);
user.setCurrentUser(new AuthenticatedUser(user, credentials));
user.setCurrentUser(new AuthenticatedUser(authenticationProvider, user, credentials));
// Verify user account is still valid as of today
if (!user.isAccountValid())
@@ -343,6 +348,41 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
}
// Return now-authenticated user
return user.getCurrentUser();
}
/**
* Retrieves the user corresponding to the given AuthenticatedUser from the
* database. If no such user exists, a placeholder entry will be created
* first.
*
* @param authenticatedUser
* The AuthenticatedUser to retrieve the corresponding ModeledUser of.
*
* @return
* The ModeledUser which corresponds to the given AuthenticatedUser,
* created first if necessary.
*/
public ModeledUser retrieveUser(org.glyptodon.guacamole.net.auth.AuthenticatedUser authenticatedUser) {
// If we already queried this user, return that rather than querying again
if (authenticatedUser instanceof AuthenticatedUser)
return ((AuthenticatedUser) authenticatedUser).getUser();
// Get username
String username = authenticatedUser.getIdentifier();
// Retrieve corresponding user model, if such a user exists
UserModel userModel = userMapper.selectOne(username);
if (userModel == null)
return null;
// Create corresponding user object, set up cyclic reference
ModeledUser user = getObjectInstance(null, userModel);
user.setCurrentUser(new AuthenticatedUser(authenticatedUser.getAuthenticationProvider(), user, authenticatedUser.getCredentials()));
// Return already-authenticated user
return user;
}