mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
Merge pull request #250 from glyptodon/multiple-ext
GUAC-586: Load multiple AuthenticationProviders
This commit is contained in:
@@ -63,6 +63,7 @@ import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermis
|
||||
import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionService;
|
||||
import org.glyptodon.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.mybatis.guice.MyBatisModule;
|
||||
import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
|
||||
|
||||
@@ -86,19 +87,31 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
|
||||
*/
|
||||
private final GuacamoleTunnelService tunnelService;
|
||||
|
||||
/**
|
||||
* The AuthenticationProvider which is using this module to configure
|
||||
* injection.
|
||||
*/
|
||||
private final AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* Creates a new JDBC authentication provider module that configures the
|
||||
* various injected base classes using the given environment, and provides
|
||||
* connections using the given socket service.
|
||||
*
|
||||
* @param authProvider
|
||||
* The AuthenticationProvider which is using this module to configure
|
||||
* injection.
|
||||
*
|
||||
* @param environment
|
||||
* The environment to use to configure injected classes.
|
||||
*
|
||||
* @param tunnelService
|
||||
* The tunnel service to use to provide tunnels sockets for connections.
|
||||
*/
|
||||
public JDBCAuthenticationProviderModule(Environment environment,
|
||||
public JDBCAuthenticationProviderModule(AuthenticationProvider authProvider,
|
||||
Environment environment,
|
||||
GuacamoleTunnelService tunnelService) {
|
||||
this.authProvider = authProvider;
|
||||
this.environment = environment;
|
||||
this.tunnelService = tunnelService;
|
||||
}
|
||||
@@ -126,6 +139,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
|
||||
// Bind core implementations of guacamole-ext classes
|
||||
bind(ActiveConnectionDirectory.class);
|
||||
bind(ActiveConnectionPermissionSet.class);
|
||||
bind(AuthenticationProvider.class).toInstance(authProvider);
|
||||
bind(Environment.class).toInstance(environment);
|
||||
bind(ConnectionDirectory.class);
|
||||
bind(ConnectionGroupDirectory.class);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
||||
import org.glyptodon.guacamole.form.Form;
|
||||
import org.glyptodon.guacamole.net.auth.ActiveConnection;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
@@ -51,6 +52,12 @@ import org.glyptodon.guacamole.net.auth.User;
|
||||
public class UserContext extends RestrictedObject
|
||||
implements org.glyptodon.guacamole.net.auth.UserContext {
|
||||
|
||||
/**
|
||||
* The AuthenticationProvider that created this UserContext.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* User directory restricted by the permissions of the user associated
|
||||
* with this context.
|
||||
@@ -103,6 +110,11 @@ public class UserContext extends RestrictedObject
|
||||
return getCurrentUser().getUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationProvider getAuthenticationProvider() {
|
||||
return authProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directory<User> getUserDirectory() throws GuacamoleException {
|
||||
return userDirectory;
|
||||
|
@@ -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,40 @@ 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.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* The AuthenticatedUser to retrieve the corresponding ModeledUser of.
|
||||
*
|
||||
* @return
|
||||
* The ModeledUser which corresponds to the given AuthenticatedUser, or
|
||||
* null if no such user exists.
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
|
@@ -31,9 +31,10 @@ import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule;
|
||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.ConfigurableGuacamoleTunnelService;
|
||||
import org.glyptodon.guacamole.auth.jdbc.user.UserContextService;
|
||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticationProviderService;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
import org.glyptodon.guacamole.environment.LocalEnvironment;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -184,25 +185,50 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider {
|
||||
new MySQLAuthenticationProviderModule(environment),
|
||||
|
||||
// Configure JDBC authentication core
|
||||
new JDBCAuthenticationProviderModule(environment, getTunnelService(environment))
|
||||
new JDBCAuthenticationProviderModule(this, environment,
|
||||
getTunnelService(environment))
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext getUserContext(Credentials credentials)
|
||||
public String getIdentifier() {
|
||||
return "mysql";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedUser authenticateUser(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Create AuthenticatedUser based on credentials, if valid
|
||||
AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
|
||||
return authProviderService.authenticateUser(this, credentials);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
// No need to update authenticated users
|
||||
return authenticatedUser;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext getUserContext(AuthenticatedUser authenticatedUser)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Create UserContext based on credentials, if valid
|
||||
UserContextService userContextService = injector.getInstance(UserContextService.class);
|
||||
return userContextService.getUserContext(credentials);
|
||||
AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
|
||||
return authProviderService.getUserContext(authenticatedUser);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext updateUserContext(UserContext context,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
AuthenticatedUser authenticatedUser) throws GuacamoleException {
|
||||
|
||||
// No need to update the context
|
||||
return context;
|
||||
|
@@ -31,9 +31,10 @@ import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule;
|
||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.ConfigurableGuacamoleTunnelService;
|
||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.glyptodon.guacamole.auth.jdbc.user.UserContextService;
|
||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticationProviderService;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
import org.glyptodon.guacamole.environment.LocalEnvironment;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -184,25 +185,50 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider
|
||||
new PostgreSQLAuthenticationProviderModule(environment),
|
||||
|
||||
// Configure JDBC authentication core
|
||||
new JDBCAuthenticationProviderModule(environment, getTunnelService(environment))
|
||||
new JDBCAuthenticationProviderModule(this, environment,
|
||||
getTunnelService(environment))
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext getUserContext(Credentials credentials)
|
||||
public String getIdentifier() {
|
||||
return "postgresql";
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedUser authenticateUser(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Create AuthenticatedUser based on credentials, if valid
|
||||
AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
|
||||
return authProviderService.authenticateUser(this, credentials);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
// No need to update authenticated users
|
||||
return authenticatedUser;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext getUserContext(AuthenticatedUser authenticatedUser)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Create UserContext based on credentials, if valid
|
||||
UserContextService userContextService = injector.getInstance(UserContextService.class);
|
||||
return userContextService.getUserContext(credentials);
|
||||
AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
|
||||
return authProviderService.getUserContext(authenticatedUser);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext updateUserContext(UserContext context,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
AuthenticatedUser authenticatedUser) throws GuacamoleException {
|
||||
|
||||
// No need to update the context
|
||||
return context;
|
||||
|
@@ -74,6 +74,11 @@ public class LDAPAuthenticationProvider extends SimpleAuthenticationProvider {
|
||||
environment = new LocalEnvironment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "ldap";
|
||||
}
|
||||
|
||||
// Courtesy of OWASP: https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
|
||||
private static String escapeLDAPSearchFilter(String filter) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
@@ -122,6 +122,11 @@ public class NoAuthenticationProvider extends SimpleAuthenticationProvider {
|
||||
environment = new LocalEnvironment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "noauth";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the configuration file, as defined within guacamole.properties.
|
||||
*
|
||||
|
@@ -119,7 +119,8 @@ public class LocalEnvironment implements Environment {
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleServerException("Error reading guacamole.properties", e);
|
||||
logger.warn("The guacamole.properties file within GUACAMOLE_HOME cannot be read: {}", e.getMessage());
|
||||
logger.debug("Error reading guacamole.properties.", e);
|
||||
}
|
||||
|
||||
// Read all protocols
|
||||
@@ -190,11 +191,8 @@ public class LocalEnvironment implements Environment {
|
||||
*
|
||||
* @return
|
||||
* A map of all available protocols.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while reading the various protocol JSON files.
|
||||
*/
|
||||
private Map<String, ProtocolInfo> readProtocols() throws GuacamoleException {
|
||||
private Map<String, ProtocolInfo> readProtocols() {
|
||||
|
||||
// Map of all available protocols
|
||||
Map<String, ProtocolInfo> protocols = new HashMap<String, ProtocolInfo>();
|
||||
|
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.auth;
|
||||
|
||||
|
||||
/**
|
||||
* Basic implementation of an AuthenticatedUser which uses the username to
|
||||
* determine equality. Username comparison is case-sensitive.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public abstract class AbstractAuthenticatedUser implements AuthenticatedUser {
|
||||
|
||||
/**
|
||||
* The name of this user.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (username == null) return 0;
|
||||
return username.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
// Not equal if null or not a User
|
||||
if (obj == null) return false;
|
||||
if (!(obj instanceof AbstractAuthenticatedUser)) return false;
|
||||
|
||||
// Get username
|
||||
String objUsername = ((AbstractAuthenticatedUser) obj).username;
|
||||
|
||||
// If null, equal only if this username is null
|
||||
if (objUsername == null) return username == null;
|
||||
|
||||
// Otherwise, equal only if strings are identical
|
||||
return objUsername.equals(username);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -20,50 +20,32 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.rest.auth;
|
||||
package org.glyptodon.guacamole.net.auth;
|
||||
|
||||
|
||||
/**
|
||||
* A simple object to represent an auth token/userID pair in the API.
|
||||
*
|
||||
* @author James Muehlner
|
||||
* A user of the Guacamole web application who has been authenticated by an
|
||||
* AuthenticationProvider.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class APIAuthToken {
|
||||
|
||||
/**
|
||||
* The auth token.
|
||||
*/
|
||||
private final String authToken;
|
||||
|
||||
|
||||
/**
|
||||
* The user ID.
|
||||
*/
|
||||
private final String userID;
|
||||
public interface AuthenticatedUser extends Identifiable {
|
||||
|
||||
/**
|
||||
* Get the auth token.
|
||||
* @return The auth token.
|
||||
* Returns the AuthenticationProvider that authenticated this user.
|
||||
*
|
||||
* @return
|
||||
* The AuthenticationProvider that authenticated this user.
|
||||
*/
|
||||
public String getAuthToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
AuthenticationProvider getAuthenticationProvider();
|
||||
|
||||
/**
|
||||
* Get the user ID.
|
||||
* @return The user ID.
|
||||
* Returns the credentials that the user provided when they successfully
|
||||
* authenticated.
|
||||
*
|
||||
* @return
|
||||
* The credentials provided by the user when they authenticated.
|
||||
*/
|
||||
public String getUserID() {
|
||||
return userID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new APIAuthToken Object with the given auth token.
|
||||
*
|
||||
* @param authToken The auth token to create the new APIAuthToken with.
|
||||
* @param userID The ID of the user owning the given token.
|
||||
*/
|
||||
public APIAuthToken(String authToken, String userID) {
|
||||
this.authToken = authToken;
|
||||
this.userID = userID;
|
||||
}
|
||||
Credentials getCredentials();
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -25,46 +25,124 @@ package org.glyptodon.guacamole.net.auth;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
|
||||
/**
|
||||
* Provides means of accessing and managing the available
|
||||
* GuacamoleConfiguration objects and User objects. Access to each configuration
|
||||
* and each user is limited by a given Credentials object.
|
||||
* Provides means of authorizing users and for accessing and managing data
|
||||
* associated with those users. Access to such data is limited according to the
|
||||
* AuthenticationProvider implementation.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public interface AuthenticationProvider {
|
||||
|
||||
/**
|
||||
* Returns the UserContext of the user authorized by the given credentials.
|
||||
* Returns the identifier which uniquely and consistently identifies this
|
||||
* AuthenticationProvider implementation. This identifier may not be null
|
||||
* and must be unique across all AuthenticationProviders loaded by the
|
||||
* Guacamole web application.
|
||||
*
|
||||
* @param credentials The credentials to use to retrieve the environment.
|
||||
* @return The UserContext of the user authorized by the given credentials,
|
||||
* or null if the credentials are not authorized.
|
||||
*
|
||||
* @throws GuacamoleException If an error occurs while creating the
|
||||
* UserContext.
|
||||
* @return
|
||||
* The unique identifier assigned to this AuthenticationProvider, which
|
||||
* may not be null.
|
||||
*/
|
||||
UserContext getUserContext(Credentials credentials)
|
||||
String getIdentifier();
|
||||
|
||||
/**
|
||||
* Returns an AuthenticatedUser representing the user authenticated by the
|
||||
* given credentials, if any.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials to use for authentication.
|
||||
*
|
||||
* @return
|
||||
* An AuthenticatedUser representing the user authenticated by the
|
||||
* given credentials, if any, or null if the credentials are invalid.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while authenticating the user, or if access is
|
||||
* temporarily, permanently, or conditionally denied, such as if the
|
||||
* supplied credentials are insufficient or invalid.
|
||||
*/
|
||||
AuthenticatedUser authenticateUser(Credentials credentials)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns a new or updated UserContext for the user authorized by the
|
||||
* give credentials and having the given existing UserContext. Note that
|
||||
* because this function will be called for all future requests after
|
||||
* initial authentication, including tunnel requests, care must be taken
|
||||
* to avoid using functions of HttpServletRequest which invalidate the
|
||||
* entire request body, such as getParameter().
|
||||
*
|
||||
* @param context The existing UserContext belonging to the user in
|
||||
* question.
|
||||
* @param credentials The credentials to use to retrieve or update the
|
||||
* environment.
|
||||
* @return The updated UserContext, which need not be the same as the
|
||||
* UserContext given, or null if the user is no longer authorized.
|
||||
*
|
||||
* @throws GuacamoleException If an error occurs while updating the
|
||||
* UserContext.
|
||||
* Returns a new or updated AuthenticatedUser for the given credentials
|
||||
* already having produced the given AuthenticatedUser. Note that because
|
||||
* this function will be called for all future requests after initial
|
||||
* authentication, including tunnel requests, care must be taken to avoid
|
||||
* using functions of HttpServletRequest which invalidate the entire request
|
||||
* body, such as getParameter(). Doing otherwise may cause the
|
||||
* GuacamoleHTTPTunnelServlet to fail.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials to use for authentication.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* An AuthenticatedUser object representing the user authenticated by
|
||||
* an arbitrary set of credentials. The AuthenticatedUser may come from
|
||||
* this AuthenticationProvider or any other installed
|
||||
* AuthenticationProvider.
|
||||
*
|
||||
* @return
|
||||
* An updated AuthenticatedUser representing the user authenticated by
|
||||
* the given credentials, if any, or null if the credentials are
|
||||
* invalid.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while updating the AuthenticatedUser.
|
||||
*/
|
||||
UserContext updateUserContext(UserContext context, Credentials credentials)
|
||||
AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the UserContext of the user authenticated by the given
|
||||
* credentials.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* An AuthenticatedUser object representing the user authenticated by
|
||||
* an arbitrary set of credentials. The AuthenticatedUser may come from
|
||||
* this AuthenticationProvider or any other installed
|
||||
* AuthenticationProvider.
|
||||
*
|
||||
* @return
|
||||
* A UserContext describing the permissions, connection, connection
|
||||
* groups, etc. accessible or associated with the given authenticated
|
||||
* user, or null if this AuthenticationProvider refuses to provide any
|
||||
* such data.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while creating the UserContext.
|
||||
*/
|
||||
UserContext getUserContext(AuthenticatedUser authenticatedUser)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns a new or updated UserContext for the given AuthenticatedUser
|
||||
* already having the given UserContext. Note that because this function
|
||||
* will be called for all future requests after initial authentication,
|
||||
* including tunnel requests, care must be taken to avoid using functions
|
||||
* of HttpServletRequest which invalidate the entire request body, such as
|
||||
* getParameter(). Doing otherwise may cause the GuacamoleHTTPTunnelServlet
|
||||
* to fail.
|
||||
*
|
||||
* @param context
|
||||
* The existing UserContext belonging to the user in question.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* An AuthenticatedUser object representing the user authenticated by
|
||||
* an arbitrary set of credentials. The AuthenticatedUser may come from
|
||||
* this AuthenticationProvider or any other installed
|
||||
* AuthenticationProvider.
|
||||
*
|
||||
* @return
|
||||
* An updated UserContext describing the permissions, connection,
|
||||
* connection groups, etc. accessible or associated with the given
|
||||
* authenticated user, or null if this AuthenticationProvider refuses
|
||||
* to provide any such data.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while updating the UserContext.
|
||||
*/
|
||||
UserContext updateUserContext(UserContext context,
|
||||
AuthenticatedUser authenticatedUser) throws GuacamoleException;
|
||||
|
||||
}
|
||||
|
@@ -43,6 +43,16 @@ public interface UserContext {
|
||||
*/
|
||||
User self();
|
||||
|
||||
/**
|
||||
* Returns the AuthenticationProvider which created this UserContext, which
|
||||
* may not be the same AuthenticationProvider that authenticated the user
|
||||
* associated with this UserContext.
|
||||
*
|
||||
* @return
|
||||
* The AuthenticationProvider that created this UserContext.
|
||||
*/
|
||||
AuthenticationProvider getAuthenticationProvider();
|
||||
|
||||
/**
|
||||
* Retrieves a Directory which can be used to view and manipulate other
|
||||
* users, but only as allowed by the permissions given to the user of this
|
||||
|
@@ -23,8 +23,11 @@
|
||||
package org.glyptodon.guacamole.net.auth.simple;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.AbstractAuthenticatedUser;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
@@ -62,12 +65,100 @@ public abstract class SimpleAuthenticationProvider
|
||||
getAuthorizedConfigurations(Credentials credentials)
|
||||
throws GuacamoleException;
|
||||
|
||||
@Override
|
||||
public UserContext getUserContext(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
/**
|
||||
* AuthenticatedUser which contains its own predefined set of authorized
|
||||
* configurations.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
private class SimpleAuthenticatedUser extends AbstractAuthenticatedUser {
|
||||
|
||||
// Get username, if any
|
||||
String username = credentials.getUsername();
|
||||
/**
|
||||
* The credentials provided when this AuthenticatedUser was
|
||||
* authenticated.
|
||||
*/
|
||||
private final Credentials credentials;
|
||||
|
||||
/**
|
||||
* The GuacamoleConfigurations that this AuthenticatedUser is
|
||||
* authorized to use.
|
||||
*/
|
||||
private final Map<String, GuacamoleConfiguration> configs;
|
||||
|
||||
/**
|
||||
* Creates a new SimpleAuthenticatedUser associated with the given
|
||||
* credentials and having access to the given Map of
|
||||
* GuacamoleConfigurations.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials provided by the user when they authenticated.
|
||||
*
|
||||
* @param configs
|
||||
* A Map of all GuacamoleConfigurations for which this user has
|
||||
* access. The keys of this Map are Strings which uniquely identify
|
||||
* each configuration.
|
||||
*/
|
||||
public SimpleAuthenticatedUser(Credentials credentials, Map<String, GuacamoleConfiguration> configs) {
|
||||
|
||||
// Store credentials and configurations
|
||||
this.credentials = credentials;
|
||||
this.configs = configs;
|
||||
|
||||
// Pull username from credentials if it exists
|
||||
String username = credentials.getUsername();
|
||||
if (username != null && !username.isEmpty())
|
||||
setIdentifier(username);
|
||||
|
||||
// Otherwise generate a random username
|
||||
else
|
||||
setIdentifier(UUID.randomUUID().toString());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map containing all GuacamoleConfigurations that this user
|
||||
* is authorized to use. The keys of this Map are Strings which
|
||||
* uniquely identify each configuration.
|
||||
*
|
||||
* @return
|
||||
* A Map of all configurations for which this user is authorized.
|
||||
*/
|
||||
public Map<String, GuacamoleConfiguration> getAuthorizedConfigurations() {
|
||||
return configs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationProvider getAuthenticationProvider() {
|
||||
return SimpleAuthenticationProvider.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credentials getCredentials() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an arbitrary credentials object, returns a Map containing all
|
||||
* configurations authorized by those credentials, filtering those
|
||||
* configurations using a TokenFilter and the standard credential tokens
|
||||
* (like ${GUAC_USERNAME} and ${GUAC_PASSWORD}). The keys of this Map
|
||||
* are Strings which uniquely identify each configuration.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials to use to retrieve authorized configurations.
|
||||
*
|
||||
* @return
|
||||
* A Map of all configurations authorized by the given credentials, or
|
||||
* null if the credentials given are not authorized.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving configurations.
|
||||
*/
|
||||
private Map<String, GuacamoleConfiguration>
|
||||
getFilteredAuthorizedConfigurations(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get configurations
|
||||
Map<String, GuacamoleConfiguration> configs =
|
||||
@@ -80,24 +171,90 @@ public abstract class SimpleAuthenticationProvider
|
||||
// Build credential TokenFilter
|
||||
TokenFilter tokenFilter = new TokenFilter();
|
||||
StandardTokens.addStandardTokens(tokenFilter, credentials);
|
||||
|
||||
|
||||
// Filter each configuration
|
||||
for (GuacamoleConfiguration config : configs.values())
|
||||
tokenFilter.filterValues(config.getParameters());
|
||||
|
||||
// Return user context restricted to authorized configs
|
||||
if (username != null && !username.isEmpty())
|
||||
return new SimpleUserContext(username, configs);
|
||||
|
||||
// If there is no associated username, let SimpleUserContext generate one
|
||||
else
|
||||
return new SimpleUserContext(configs);
|
||||
return configs;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user who has already been authenticated, returns a Map
|
||||
* containing all configurations for which that user is authorized,
|
||||
* filtering those configurations using a TokenFilter and the standard
|
||||
* credential tokens (like ${GUAC_USERNAME} and ${GUAC_PASSWORD}). The keys
|
||||
* of this Map are Strings which uniquely identify each configuration.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* The user whose authorized configurations are to be retrieved.
|
||||
*
|
||||
* @return
|
||||
* A Map of all configurations authorized for use by the given user, or
|
||||
* null if the user is not authorized to use any configurations.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving configurations.
|
||||
*/
|
||||
private Map<String, GuacamoleConfiguration>
|
||||
getFilteredAuthorizedConfigurations(AuthenticatedUser authenticatedUser)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Pull cached configurations, if any
|
||||
if (authenticatedUser instanceof SimpleAuthenticatedUser)
|
||||
return ((SimpleAuthenticatedUser) authenticatedUser).getAuthorizedConfigurations();
|
||||
|
||||
// Otherwise, pull using credentials
|
||||
return getFilteredAuthorizedConfigurations(authenticatedUser.getCredentials());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedUser authenticateUser(final Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get configurations
|
||||
Map<String, GuacamoleConfiguration> configs =
|
||||
getFilteredAuthorizedConfigurations(credentials);
|
||||
|
||||
// Return as unauthorized if not authorized to retrieve configs
|
||||
if (configs == null)
|
||||
return null;
|
||||
|
||||
return new SimpleAuthenticatedUser(credentials, configs);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext getUserContext(AuthenticatedUser authenticatedUser)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get configurations
|
||||
Map<String, GuacamoleConfiguration> configs =
|
||||
getFilteredAuthorizedConfigurations(authenticatedUser);
|
||||
|
||||
// Return as unauthorized if not authorized to retrieve configs
|
||||
if (configs == null)
|
||||
return null;
|
||||
|
||||
// Return user context restricted to authorized configs
|
||||
return new SimpleUserContext(this, authenticatedUser.getIdentifier(), configs);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
// Simply return the given user, updating nothing
|
||||
return authenticatedUser;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext updateUserContext(UserContext context,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
AuthenticatedUser authorizedUser) throws GuacamoleException {
|
||||
|
||||
// Simply return the given context, updating nothing
|
||||
return context;
|
||||
|
@@ -30,6 +30,7 @@ import java.util.UUID;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.form.Form;
|
||||
import org.glyptodon.guacamole.net.auth.ActiveConnection;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
@@ -50,7 +51,12 @@ public class SimpleUserContext implements UserContext {
|
||||
* The unique identifier of the root connection group.
|
||||
*/
|
||||
private static final String ROOT_IDENTIFIER = "ROOT";
|
||||
|
||||
|
||||
/**
|
||||
* The AuthenticationProvider that created this UserContext.
|
||||
*/
|
||||
private final AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* Reference to the user whose permissions dictate the configurations
|
||||
* accessible within this UserContext.
|
||||
@@ -84,24 +90,35 @@ public class SimpleUserContext implements UserContext {
|
||||
* Creates a new SimpleUserContext which provides access to only those
|
||||
* configurations within the given Map. The username is assigned
|
||||
* arbitrarily.
|
||||
*
|
||||
* @param configs A Map of all configurations for which the user associated
|
||||
* with this UserContext has read access.
|
||||
*
|
||||
* @param authProvider
|
||||
* The AuthenticationProvider creating this UserContext.
|
||||
*
|
||||
* @param configs
|
||||
* A Map of all configurations for which the user associated with this
|
||||
* UserContext has read access.
|
||||
*/
|
||||
public SimpleUserContext(Map<String, GuacamoleConfiguration> configs) {
|
||||
this(UUID.randomUUID().toString(), configs);
|
||||
public SimpleUserContext(AuthenticationProvider authProvider,
|
||||
Map<String, GuacamoleConfiguration> configs) {
|
||||
this(authProvider, UUID.randomUUID().toString(), configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SimpleUserContext for the user with the given username
|
||||
* which provides access to only those configurations within the given Map.
|
||||
*
|
||||
* @param username The username of the user associated with this
|
||||
* UserContext.
|
||||
* @param configs A Map of all configurations for which the user associated
|
||||
* with this UserContext has read access.
|
||||
*
|
||||
* @param authProvider
|
||||
* The AuthenticationProvider creating this UserContext.
|
||||
*
|
||||
* @param username
|
||||
* The username of the user associated with this UserContext.
|
||||
*
|
||||
* @param configs
|
||||
* A Map of all configurations for which the user associated with
|
||||
* this UserContext has read access.
|
||||
*/
|
||||
public SimpleUserContext(String username, Map<String, GuacamoleConfiguration> configs) {
|
||||
public SimpleUserContext(AuthenticationProvider authProvider,
|
||||
String username, Map<String, GuacamoleConfiguration> configs) {
|
||||
|
||||
Collection<String> connectionIdentifiers = new ArrayList<String>(configs.size());
|
||||
Collection<String> connectionGroupIdentifiers = Collections.singleton(ROOT_IDENTIFIER);
|
||||
@@ -138,7 +155,10 @@ public class SimpleUserContext implements UserContext {
|
||||
this.userDirectory = new SimpleUserDirectory(self);
|
||||
this.connectionDirectory = new SimpleConnectionDirectory(connections);
|
||||
this.connectionGroupDirectory = new SimpleConnectionGroupDirectory(Collections.singleton(this.rootGroup));
|
||||
|
||||
|
||||
// Associate provided AuthenticationProvider
|
||||
this.authProvider = authProvider;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,6 +166,11 @@ public class SimpleUserContext implements UserContext {
|
||||
return self;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationProvider getAuthenticationProvider() {
|
||||
return authProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directory<User> getUserDirectory()
|
||||
throws GuacamoleException {
|
||||
|
@@ -36,7 +36,7 @@ import org.glyptodon.guacamole.net.auth.simple.SimpleAuthenticationProvider;
|
||||
import org.glyptodon.guacamole.net.basic.auth.Authorization;
|
||||
import org.glyptodon.guacamole.net.basic.auth.UserMapping;
|
||||
import org.glyptodon.guacamole.xml.DocumentHandler;
|
||||
import org.glyptodon.guacamole.net.basic.xml.user_mapping.UserMappingTagHandler;
|
||||
import org.glyptodon.guacamole.net.basic.xml.usermapping.UserMappingTagHandler;
|
||||
import org.glyptodon.guacamole.properties.FileGuacamoleProperty;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
@@ -58,17 +58,19 @@ public class BasicFileAuthenticationProvider extends SimpleAuthenticationProvide
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private Logger logger = LoggerFactory.getLogger(BasicFileAuthenticationProvider.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(BasicFileAuthenticationProvider.class);
|
||||
|
||||
/**
|
||||
* The time the user mapping file was last modified.
|
||||
* The time the user mapping file was last modified. If the file has never
|
||||
* been read, and thus no modification time exists, this will be
|
||||
* Long.MIN_VALUE.
|
||||
*/
|
||||
private long mod_time;
|
||||
private long lastModified = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* The parsed UserMapping read when the user mapping file was last parsed.
|
||||
*/
|
||||
private UserMapping user_mapping;
|
||||
private UserMapping cachedUserMapping;
|
||||
|
||||
/**
|
||||
* Guacamole server environment.
|
||||
@@ -103,30 +105,48 @@ public class BasicFileAuthenticationProvider extends SimpleAuthenticationProvide
|
||||
environment = new LocalEnvironment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "default";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a UserMapping containing all authorization data given within
|
||||
* the XML file specified by the "basic-user-mapping" property in
|
||||
* guacamole.properties. If the XML file has been modified or has not yet
|
||||
* been read, this function may reread the file.
|
||||
*
|
||||
* @return A UserMapping containing all authorization data within the
|
||||
* user mapping XML file.
|
||||
* @throws GuacamoleException If the user mapping property is missing or
|
||||
* an error occurs while parsing the XML file.
|
||||
* @return
|
||||
* A UserMapping containing all authorization data within the user
|
||||
* mapping XML file, or null if the file cannot be found/parsed.
|
||||
*/
|
||||
private UserMapping getUserMapping() throws GuacamoleException {
|
||||
private UserMapping getUserMapping() {
|
||||
|
||||
// Get user mapping file, defaulting to GUACAMOLE_HOME/user-mapping.xml
|
||||
File user_mapping_file = environment.getProperty(BASIC_USER_MAPPING);
|
||||
if (user_mapping_file == null)
|
||||
user_mapping_file = new File(environment.getGuacamoleHome(), DEFAULT_USER_MAPPING);
|
||||
File userMappingFile;
|
||||
try {
|
||||
userMappingFile = environment.getProperty(BASIC_USER_MAPPING);
|
||||
if (userMappingFile == null)
|
||||
userMappingFile = new File(environment.getGuacamoleHome(), DEFAULT_USER_MAPPING);
|
||||
}
|
||||
|
||||
// If user_mapping not yet read, or user_mapping has been modified, reread
|
||||
if (user_mapping == null ||
|
||||
(user_mapping_file.exists()
|
||||
&& mod_time < user_mapping_file.lastModified())) {
|
||||
// Abort if property cannot be parsed
|
||||
catch (GuacamoleException e) {
|
||||
logger.warn("Unable to read user mapping filename from properties: {}", e.getMessage());
|
||||
logger.debug("Error parsing user mapping property.", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug("Reading user mapping file: \"{}\"", user_mapping_file);
|
||||
// Abort if user mapping does not exist
|
||||
if (!userMappingFile.exists()) {
|
||||
logger.debug("User mapping file \"{}\" does not exist and will not be read.", userMappingFile);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Refresh user mapping if file has changed
|
||||
if (lastModified < userMappingFile.lastModified()) {
|
||||
|
||||
logger.debug("Reading user mapping file: \"{}\"", userMappingFile);
|
||||
|
||||
// Parse document
|
||||
try {
|
||||
@@ -144,26 +164,34 @@ public class BasicFileAuthenticationProvider extends SimpleAuthenticationProvide
|
||||
parser.setContentHandler(contentHandler);
|
||||
|
||||
// Read and parse file
|
||||
InputStream input = new BufferedInputStream(new FileInputStream(user_mapping_file));
|
||||
InputStream input = new BufferedInputStream(new FileInputStream(userMappingFile));
|
||||
parser.parse(new InputSource(input));
|
||||
input.close();
|
||||
|
||||
// Store mod time and user mapping
|
||||
mod_time = user_mapping_file.lastModified();
|
||||
user_mapping = userMappingHandler.asUserMapping();
|
||||
lastModified = userMappingFile.lastModified();
|
||||
cachedUserMapping = userMappingHandler.asUserMapping();
|
||||
|
||||
}
|
||||
|
||||
// If the file is unreadable, return no mapping
|
||||
catch (IOException e) {
|
||||
throw new GuacamoleException("Error reading basic user mapping file.", e);
|
||||
logger.warn("Unable to read user mapping file \"{}\": {}", userMappingFile, e.getMessage());
|
||||
logger.debug("Error reading user mapping file.", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the file cannot be parsed, return no mapping
|
||||
catch (SAXException e) {
|
||||
throw new GuacamoleException("Error parsing basic user mapping XML.", e);
|
||||
logger.warn("User mapping file \"{}\" is not valid: {}", userMappingFile, e.getMessage());
|
||||
logger.debug("Error parsing user mapping file.", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return (possibly cached) user mapping
|
||||
return user_mapping;
|
||||
return cachedUserMapping;
|
||||
|
||||
}
|
||||
|
||||
@@ -172,6 +200,11 @@ public class BasicFileAuthenticationProvider extends SimpleAuthenticationProvide
|
||||
getAuthorizedConfigurations(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Abort authorization if no user mapping exists
|
||||
UserMapping userMapping = getUserMapping();
|
||||
if (userMapping == null)
|
||||
return null;
|
||||
|
||||
// Validate and return info for given user and pass
|
||||
Authorization auth = getUserMapping().getAuthorization(credentials.getUsername());
|
||||
if (auth != null && auth.validate(credentials.getUsername(), credentials.getPassword()))
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,18 +22,15 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -51,19 +48,15 @@ public class GuacamoleSession {
|
||||
private static final Logger logger = LoggerFactory.getLogger(GuacamoleSession.class);
|
||||
|
||||
/**
|
||||
* The credentials provided when the user authenticated.
|
||||
* The user associated with this session.
|
||||
*/
|
||||
private Credentials credentials;
|
||||
private AuthenticatedUser authenticatedUser;
|
||||
|
||||
/**
|
||||
* The user context associated with this session.
|
||||
* All UserContexts associated with this session. Each
|
||||
* AuthenticationProvider may provide its own UserContext.
|
||||
*/
|
||||
private UserContext userContext;
|
||||
|
||||
/**
|
||||
* The current clipboard state.
|
||||
*/
|
||||
private final ClipboardState clipboardState = new ClipboardState();
|
||||
private List<UserContext> userContexts;
|
||||
|
||||
/**
|
||||
* All currently-active tunnels, indexed by tunnel UUID.
|
||||
@@ -76,80 +69,110 @@ public class GuacamoleSession {
|
||||
private long lastAccessedTime;
|
||||
|
||||
/**
|
||||
* Creates a new Guacamole session associated with the given user context.
|
||||
* Creates a new Guacamole session associated with the given
|
||||
* AuthenticatedUser and UserContexts.
|
||||
*
|
||||
* @param environment
|
||||
* The environment of the Guacamole server associated with this new
|
||||
* session.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials provided by the user during login.
|
||||
* @param authenticatedUser
|
||||
* The authenticated user to associate this session with.
|
||||
*
|
||||
* @param userContext
|
||||
* The user context to associate this session with.
|
||||
* @param userContexts
|
||||
* The List of UserContexts to associate with this session.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error prevents the session from being created.
|
||||
*/
|
||||
public GuacamoleSession(Environment environment, Credentials credentials,
|
||||
UserContext userContext) throws GuacamoleException {
|
||||
public GuacamoleSession(Environment environment,
|
||||
AuthenticatedUser authenticatedUser,
|
||||
List<UserContext> userContexts)
|
||||
throws GuacamoleException {
|
||||
this.lastAccessedTime = System.currentTimeMillis();
|
||||
this.credentials = credentials;
|
||||
this.userContext = userContext;
|
||||
this.authenticatedUser = authenticatedUser;
|
||||
this.userContexts = userContexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the credentials used when the user associated with this session
|
||||
* authenticated.
|
||||
* Returns the authenticated user associated with this session.
|
||||
*
|
||||
* @return
|
||||
* The credentials used when the user associated with this session
|
||||
* authenticated.
|
||||
* The authenticated user associated with this session.
|
||||
*/
|
||||
public Credentials getCredentials() {
|
||||
return credentials;
|
||||
public AuthenticatedUser getAuthenticatedUser() {
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the credentials associated with this session with the given
|
||||
* credentials.
|
||||
* Replaces the authenticated user associated with this session with the
|
||||
* given authenticated user.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials to associate with this session.
|
||||
* @param authenticatedUser
|
||||
* The authenticated user to associated with this session.
|
||||
*/
|
||||
public void setCredentials(Credentials credentials) {
|
||||
this.credentials = credentials;
|
||||
public void setAuthenticatedUser(AuthenticatedUser authenticatedUser) {
|
||||
this.authenticatedUser = authenticatedUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the UserContext associated with this session.
|
||||
*
|
||||
* @return The UserContext associated with this session.
|
||||
*/
|
||||
public UserContext getUserContext() {
|
||||
return userContext;
|
||||
|
||||
// Warn of deprecation
|
||||
logger.debug(
|
||||
"\n****************************************************************"
|
||||
+ "\n"
|
||||
+ "\n !!!! PLEASE DO NOT USE getUserContext() !!!!"
|
||||
+ "\n"
|
||||
+ "\n getUserContext() has been replaced by getUserContexts(), which"
|
||||
+ "\n properly handles multiple authentication providers. All use of"
|
||||
+ "\n the old getUserContext() must be removed before GUAC-586 can"
|
||||
+ "\n be considered complete."
|
||||
+ "\n"
|
||||
+ "\n****************************************************************"
|
||||
);
|
||||
|
||||
// Return the UserContext associated with the AuthenticationProvider
|
||||
// that authenticated the current user.
|
||||
String authProviderIdentifier = authenticatedUser.getAuthenticationProvider().getIdentifier();
|
||||
for (UserContext userContext : userContexts) {
|
||||
if (userContext.getAuthenticationProvider().getIdentifier().equals(authProviderIdentifier))
|
||||
return userContext;
|
||||
}
|
||||
|
||||
// If not found, return null
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the user context associated with this session with the given
|
||||
* user context.
|
||||
* Returns a list of all UserContexts associated with this session. Each
|
||||
* AuthenticationProvider currently loaded by Guacamole may provide its own
|
||||
* UserContext for any successfully-authenticated user.
|
||||
*
|
||||
* @param userContext
|
||||
* The user context to associate with this session.
|
||||
* @return
|
||||
* An unmodifiable list of all UserContexts associated with this
|
||||
* session.
|
||||
*/
|
||||
public void setUserContext(UserContext userContext) {
|
||||
this.userContext = userContext;
|
||||
public List<UserContext> getUserContexts() {
|
||||
return Collections.unmodifiableList(userContexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all UserContexts associated with this session with the given
|
||||
* List of UserContexts.
|
||||
*
|
||||
* @param userContexts
|
||||
* The List of UserContexts to associate with this session.
|
||||
*/
|
||||
public void setUserContexts(List<UserContext> userContexts) {
|
||||
this.userContexts = userContexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ClipboardState associated with this session.
|
||||
*
|
||||
* @return The ClipboardState associated with this session.
|
||||
*/
|
||||
public ClipboardState getClipboardState() {
|
||||
return clipboardState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this session has any associated active tunnels.
|
||||
*
|
||||
|
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic;
|
||||
|
||||
import java.util.List;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.io.GuacamoleReader;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleInstruction;
|
||||
|
||||
/**
|
||||
* GuacamoleReader implementation which watches for specific instructions,
|
||||
* maintaining state based on the observed instructions.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class MonitoringGuacamoleReader implements GuacamoleReader {
|
||||
|
||||
/**
|
||||
* The underlying GuacamoleReader.
|
||||
*/
|
||||
private final GuacamoleReader reader;
|
||||
|
||||
/**
|
||||
* Collection of all listeners which will receive events.
|
||||
*/
|
||||
private final ClipboardState clipboard;
|
||||
|
||||
/**
|
||||
* The index of the clipboard stream, if any.
|
||||
*/
|
||||
private String clipboard_stream_index = null;
|
||||
|
||||
/**
|
||||
* Creates a new MonitoringGuacamoleReader which watches the instructions
|
||||
* read by the given GuacamoleReader, firing events when specific
|
||||
* instructions are seen.
|
||||
*
|
||||
* @param clipboard The clipboard state to maintain.
|
||||
* @param reader The reader to observe.
|
||||
*/
|
||||
public MonitoringGuacamoleReader(ClipboardState clipboard,
|
||||
GuacamoleReader reader) {
|
||||
this.clipboard = clipboard;
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean available() throws GuacamoleException {
|
||||
return reader.available();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] read() throws GuacamoleException {
|
||||
|
||||
// Read single instruction, handle end-of-stream
|
||||
GuacamoleInstruction instruction = readInstruction();
|
||||
if (instruction == null)
|
||||
return null;
|
||||
|
||||
return instruction.toString().toCharArray();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleInstruction readInstruction() throws GuacamoleException {
|
||||
|
||||
// Read single instruction, handle end-of-stream
|
||||
GuacamoleInstruction instruction = reader.readInstruction();
|
||||
if (instruction == null)
|
||||
return null;
|
||||
|
||||
// If clipboard changing, reset clipboard state
|
||||
if (instruction.getOpcode().equals("clipboard")) {
|
||||
List<String> args = instruction.getArgs();
|
||||
if (args.size() >= 2) {
|
||||
clipboard_stream_index = args.get(0);
|
||||
clipboard.begin(args.get(1));
|
||||
}
|
||||
}
|
||||
|
||||
// Add clipboard blobs to existing streams
|
||||
else if (instruction.getOpcode().equals("blob")) {
|
||||
List<String> args = instruction.getArgs();
|
||||
if (args.size() >= 2 && args.get(0).equals(clipboard_stream_index)) {
|
||||
String base64 = args.get(1);
|
||||
clipboard.append(DatatypeConverter.parseBase64Binary(base64));
|
||||
}
|
||||
}
|
||||
|
||||
// Terminate and update clipboard at end of stream
|
||||
else if (instruction.getOpcode().equals("end")) {
|
||||
List<String> args = instruction.getArgs();
|
||||
if (args.size() >= 1 && args.get(0).equals(clipboard_stream_index)) {
|
||||
clipboard.commit();
|
||||
clipboard_stream_index = null;
|
||||
}
|
||||
}
|
||||
|
||||
return instruction;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -24,13 +24,11 @@ package org.glyptodon.guacamole.net.basic;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService;
|
||||
import java.util.List;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
import org.glyptodon.guacamole.io.GuacamoleReader;
|
||||
import org.glyptodon.guacamole.net.DelegatingGuacamoleTunnel;
|
||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
@@ -234,28 +232,6 @@ public class TunnelRequestService {
|
||||
*/
|
||||
private final long connectionStartTime = System.currentTimeMillis();
|
||||
|
||||
@Override
|
||||
public GuacamoleReader acquireReader() {
|
||||
|
||||
// Monitor instructions which pertain to server-side events, if necessary
|
||||
try {
|
||||
if (environment.getProperty(ClipboardRESTService.INTEGRATION_ENABLED, false)) {
|
||||
|
||||
ClipboardState clipboard = session.getClipboardState();
|
||||
return new MonitoringGuacamoleReader(clipboard, super.acquireReader());
|
||||
|
||||
}
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
logger.warn("Clipboard integration failed to initialize: {}", e.getMessage());
|
||||
logger.debug("Error setting up clipboard integration.", e);
|
||||
}
|
||||
|
||||
// Pass through by default.
|
||||
return super.acquireReader();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws GuacamoleException {
|
||||
|
||||
@@ -268,13 +244,13 @@ public class TunnelRequestService {
|
||||
// Connection identifiers
|
||||
case CONNECTION:
|
||||
logger.info("User \"{}\" disconnected from connection \"{}\". Duration: {} milliseconds",
|
||||
session.getUserContext().self().getIdentifier(), id, duration);
|
||||
session.getAuthenticatedUser().getIdentifier(), id, duration);
|
||||
break;
|
||||
|
||||
// Connection group identifiers
|
||||
case CONNECTION_GROUP:
|
||||
logger.info("User \"{}\" disconnected from connection group \"{}\". Duration: {} milliseconds",
|
||||
session.getUserContext().self().getIdentifier(), id, duration);
|
||||
session.getAuthenticatedUser().getIdentifier(), id, duration);
|
||||
break;
|
||||
|
||||
// Type is guaranteed to be one of the above
|
||||
|
@@ -23,7 +23,9 @@
|
||||
package org.glyptodon.guacamole.net.basic.extension;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.UUID;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
@@ -52,6 +54,12 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
|
||||
*/
|
||||
private final AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* The identifier to provide for the underlying authentication provider if
|
||||
* the authentication provider could not be loaded.
|
||||
*/
|
||||
private final String facadeIdentifier = UUID.randomUUID().toString();
|
||||
|
||||
/**
|
||||
* Creates a new AuthenticationProviderFacade which delegates all function
|
||||
* calls to an instance of the given AuthenticationProvider subclass. If
|
||||
@@ -118,7 +126,21 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext getUserContext(Credentials credentials)
|
||||
public String getIdentifier() {
|
||||
|
||||
// Ignore auth attempts if no auth provider could be loaded
|
||||
if (authProvider == null) {
|
||||
logger.warn("The authentication system could not be loaded. Please check for errors earlier in the logs.");
|
||||
return facadeIdentifier;
|
||||
}
|
||||
|
||||
// Delegate to underlying auth provider
|
||||
return authProvider.getIdentifier();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedUser authenticateUser(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Ignore auth attempts if no auth provider could be loaded
|
||||
@@ -128,13 +150,13 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
|
||||
}
|
||||
|
||||
// Delegate to underlying auth provider
|
||||
return authProvider.getUserContext(credentials);
|
||||
|
||||
return authProvider.authenticateUser(credentials);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext updateUserContext(UserContext context, Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
// Ignore auth attempts if no auth provider could be loaded
|
||||
if (authProvider == null) {
|
||||
@@ -143,7 +165,38 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
|
||||
}
|
||||
|
||||
// Delegate to underlying auth provider
|
||||
return authProvider.updateUserContext(context, credentials);
|
||||
return authProvider.updateAuthenticatedUser(authenticatedUser, credentials);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext getUserContext(AuthenticatedUser authenticatedUser)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Ignore auth attempts if no auth provider could be loaded
|
||||
if (authProvider == null) {
|
||||
logger.warn("User data retrieval attempt denied because the authentication system could not be loaded. Please check for errors earlier in the logs.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Delegate to underlying auth provider
|
||||
return authProvider.getUserContext(authenticatedUser);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext updateUserContext(UserContext context,
|
||||
AuthenticatedUser authenticatedUser)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Ignore auth attempts if no auth provider could be loaded
|
||||
if (authProvider == null) {
|
||||
logger.warn("User data refresh attempt denied because the authentication system could not be loaded. Please check for errors earlier in the logs.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Delegate to underlying auth provider
|
||||
return authProvider.updateUserContext(context, authenticatedUser);
|
||||
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.extension;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.servlet.ServletModule;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
@@ -91,10 +92,10 @@ public class ExtensionModule extends ServletModule {
|
||||
private final Environment environment;
|
||||
|
||||
/**
|
||||
* The currently-bound authentication provider, if any. At the moment, we
|
||||
* only support one authentication provider loaded at any one time.
|
||||
* All currently-bound authentication providers, if any.
|
||||
*/
|
||||
private Class<? extends AuthenticationProvider> boundAuthenticationProvider = null;
|
||||
private final List<AuthenticationProvider> boundAuthenticationProviders =
|
||||
new ArrayList<AuthenticationProvider>();
|
||||
|
||||
/**
|
||||
* Service for adding and retrieving language resources.
|
||||
@@ -179,40 +180,24 @@ public class ExtensionModule extends ServletModule {
|
||||
/**
|
||||
* Binds the given AuthenticationProvider class such that any service
|
||||
* requiring access to the AuthenticationProvider can obtain it via
|
||||
* injection.
|
||||
* injection, along with any other bound AuthenticationProviders.
|
||||
*
|
||||
* @param authenticationProvider
|
||||
* The AuthenticationProvider class to bind.
|
||||
*/
|
||||
private void bindAuthenticationProvider(Class<? extends AuthenticationProvider> authenticationProvider) {
|
||||
|
||||
// Choose auth provider for binding if not already chosen
|
||||
if (boundAuthenticationProvider == null)
|
||||
boundAuthenticationProvider = authenticationProvider;
|
||||
|
||||
// If an auth provider is already chosen, skip and warn
|
||||
else {
|
||||
logger.debug("Ignoring AuthenticationProvider \"{}\".", authenticationProvider);
|
||||
logger.warn("Only one authentication extension may be used at a time. Please "
|
||||
+ "make sure that only one authentication extension is present "
|
||||
+ "within the GUACAMOLE_HOME/" + EXTENSIONS_DIRECTORY + " "
|
||||
+ "directory, and that you are not also specifying the deprecated "
|
||||
+ "\"auth-provider\" property within guacamole.properties.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind authentication provider
|
||||
logger.debug("Binding AuthenticationProvider \"{}\".", authenticationProvider);
|
||||
bind(AuthenticationProvider.class).toInstance(new AuthenticationProviderFacade(authenticationProvider));
|
||||
logger.debug("[{}] Binding AuthenticationProvider \"{}\".",
|
||||
boundAuthenticationProviders.size(), authenticationProvider.getName());
|
||||
boundAuthenticationProviders.add(new AuthenticationProviderFacade(authenticationProvider));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds each of the the given AuthenticationProvider classes such that any
|
||||
* service requiring access to the AuthenticationProvider can obtain it via
|
||||
* injection. Note that, as multiple simultaneous authentication providers
|
||||
* are not currently supported, attempting to bind more than one
|
||||
* authentication provider will result in warnings being logged.
|
||||
* injection.
|
||||
*
|
||||
* @param authProviders
|
||||
* The AuthenticationProvider classes to bind.
|
||||
@@ -225,6 +210,18 @@ public class ExtensionModule extends ServletModule {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all currently-bound AuthenticationProvider instances.
|
||||
*
|
||||
* @return
|
||||
* A List of all currently-bound AuthenticationProvider. The List is
|
||||
* not modifiable.
|
||||
*/
|
||||
@Provides
|
||||
public List<AuthenticationProvider> getAuthenticationProviders() {
|
||||
return Collections.unmodifiableList(boundAuthenticationProviders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serves each of the given resources as a language resource. Language
|
||||
* resources are served from within the "/translations" directory as JSON
|
||||
@@ -415,11 +412,8 @@ public class ExtensionModule extends ServletModule {
|
||||
// Load all extensions
|
||||
loadExtensions(javaScriptResources, cssResources);
|
||||
|
||||
// Bind basic auth if nothing else chosen/provided
|
||||
if (boundAuthenticationProvider == null) {
|
||||
logger.info("Using default, \"basic\", XML-driven authentication.");
|
||||
bindAuthenticationProvider(BasicFileAuthenticationProvider.class);
|
||||
}
|
||||
// Always bind basic auth last
|
||||
bindAuthenticationProvider(BasicFileAuthenticationProvider.class);
|
||||
|
||||
// Dynamically generate app.js and app.css from extensions
|
||||
serve("/app.js").with(new ResourceServlet(new SequenceResource(javaScriptResources)));
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.rest;
|
||||
|
||||
import java.util.List;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
@@ -29,6 +30,7 @@ import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||
import org.glyptodon.guacamole.net.basic.rest.connectiongroup.APIConnectionGroup;
|
||||
|
||||
/**
|
||||
@@ -39,6 +41,43 @@ import org.glyptodon.guacamole.net.basic.rest.connectiongroup.APIConnectionGroup
|
||||
*/
|
||||
public class ObjectRetrievalService {
|
||||
|
||||
/**
|
||||
* Retrieves a single UserContext from the given GuacamoleSession, which
|
||||
* may contain multiple UserContexts.
|
||||
*
|
||||
* @param session
|
||||
* The GuacamoleSession to retrieve the UserContext from.
|
||||
*
|
||||
* @param identifier
|
||||
* The unique identifier of the AuthenticationProvider that created the
|
||||
* UserContext being retrieved. Only one UserContext per
|
||||
* AuthenticationProvider can exist.
|
||||
*
|
||||
* @return
|
||||
* The UserContext that was created by the AuthenticationProvider
|
||||
* having the given identifier.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the UserContext, or if the
|
||||
* UserContext does not exist.
|
||||
*/
|
||||
public UserContext retrieveUserContext(GuacamoleSession session,
|
||||
String identifier) throws GuacamoleException {
|
||||
|
||||
// Get list of UserContexts
|
||||
List<UserContext> userContexts = session.getUserContexts();
|
||||
|
||||
// Locate and return the UserContext associated with the
|
||||
// AuthenticationProvider having the given identifier, if any
|
||||
for (UserContext userContext : userContexts) {
|
||||
if (userContext.getAuthenticationProvider().getIdentifier().equals(identifier))
|
||||
return userContext;
|
||||
}
|
||||
|
||||
throw new GuacamoleResourceNotFoundException("Session not associated with authentication provider \"" + identifier + "\".");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a single user from the given user context.
|
||||
*
|
||||
|
@@ -28,7 +28,6 @@ import com.google.inject.servlet.ServletModule;
|
||||
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
|
||||
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.TokenRESTService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.activeconnection.ActiveConnectionRESTService;
|
||||
@@ -58,7 +57,6 @@ public class RESTServletModule extends ServletModule {
|
||||
|
||||
// Set up the API endpoints
|
||||
bind(ActiveConnectionRESTService.class);
|
||||
bind(ClipboardRESTService.class);
|
||||
bind(ConnectionGroupRESTService.class);
|
||||
bind(ConnectionRESTService.class);
|
||||
bind(LanguageRESTService.class);
|
||||
|
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.rest.auth;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A simple object which describes the result of an authentication operation,
|
||||
* including the resulting token.
|
||||
*
|
||||
* @author James Muehlner
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class APIAuthenticationResult {
|
||||
|
||||
/**
|
||||
* The unique token generated for the user that authenticated.
|
||||
*/
|
||||
private final String authToken;
|
||||
|
||||
/**
|
||||
* The username of the user that authenticated.
|
||||
*/
|
||||
private final String username;
|
||||
|
||||
/**
|
||||
* The unique identifier of the data source from which this user account
|
||||
* came. Although this user account may exist across several data sources
|
||||
* (AuthenticationProviders), this will be the unique identifier of the
|
||||
* AuthenticationProvider that authenticated this user for the current
|
||||
* session.
|
||||
*/
|
||||
private final String dataSource;
|
||||
|
||||
/**
|
||||
* The identifiers of all data sources available to this user.
|
||||
*/
|
||||
private final List<String> availableDataSources;
|
||||
|
||||
/**
|
||||
* Returns the unique authentication token which identifies the current
|
||||
* session.
|
||||
*
|
||||
* @return
|
||||
* The user's authentication token.
|
||||
*/
|
||||
public String getAuthToken() {
|
||||
return authToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user identified by the authentication token associated with
|
||||
* the current session.
|
||||
*
|
||||
* @return
|
||||
* The user identified by this authentication token.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of the data source associated with the user
|
||||
* account associated with the current session.
|
||||
*
|
||||
* @return
|
||||
* The unique identifier of the data source associated with the user
|
||||
* account associated with the current session.
|
||||
*/
|
||||
public String getDataSource() {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifiers of all data sources available to the user
|
||||
* associated with the current session.
|
||||
*
|
||||
* @return
|
||||
* The identifiers of all data sources available to the user associated
|
||||
* with the current session.
|
||||
*/
|
||||
public List<String> getAvailableDataSources() {
|
||||
return availableDataSources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new APIAuthenticationResult object containing the given data.
|
||||
*
|
||||
* @param authToken
|
||||
* The unique token generated for the user that authenticated, to be
|
||||
* used for the duration of their session.
|
||||
*
|
||||
* @param username
|
||||
* The username of the user owning the given token.
|
||||
*
|
||||
* @param dataSource
|
||||
* The unique identifier of the AuthenticationProvider which
|
||||
* authenticated the user.
|
||||
*
|
||||
* @param availableDataSources
|
||||
* The unique identifier of all AuthenticationProviders to which the
|
||||
* user now has access.
|
||||
*/
|
||||
public APIAuthenticationResult(String authToken, String username,
|
||||
String dataSource, List<String> availableDataSources) {
|
||||
this.authToken = authToken;
|
||||
this.username = username;
|
||||
this.dataSource = dataSource;
|
||||
this.availableDataSources = Collections.unmodifiableList(availableDataSources);
|
||||
}
|
||||
|
||||
}
|
@@ -23,6 +23,7 @@
|
||||
package org.glyptodon.guacamole.net.basic.rest.auth;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.List;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleUnauthorizedException;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
@@ -77,5 +78,24 @@ public class AuthenticationService {
|
||||
public UserContext getUserContext(String authToken) throws GuacamoleException {
|
||||
return getGuacamoleSession(authToken).getUserContext();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all UserContexts associated with a given auth token, if the auth
|
||||
* token represents a currently logged in user. Throws an unauthorized
|
||||
* error otherwise.
|
||||
*
|
||||
* @param authToken
|
||||
* The auth token to check against the map of logged in users.
|
||||
*
|
||||
* @return
|
||||
* A List of all UserContexts associated with the provided auth token.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the auth token does not correspond to any logged in user.
|
||||
*/
|
||||
public List<UserContext> getUserContexts(String authToken)
|
||||
throws GuacamoleException {
|
||||
return getGuacamoleSession(authToken).getUserContexts();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -24,6 +24,8 @@ package org.glyptodon.guacamole.net.basic.rest.auth;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.DELETE;
|
||||
@@ -37,11 +39,14 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleCredentialsException;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||
import org.glyptodon.guacamole.net.basic.rest.APIError;
|
||||
@@ -55,6 +60,7 @@ import org.slf4j.LoggerFactory;
|
||||
* A service for managing auth tokens via the Guacamole REST API.
|
||||
*
|
||||
* @author James Muehlner
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
@Path("/tokens")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@@ -67,10 +73,11 @@ public class TokenRESTService {
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* The authentication provider used to authenticate this user.
|
||||
* All configured authentication providers which can be used to
|
||||
* authenticate users or retrieve data associated with authenticated users.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationProvider authProvider;
|
||||
private List<AuthenticationProvider> authProviders;
|
||||
|
||||
/**
|
||||
* The map of auth tokens to sessions for the REST endpoints.
|
||||
@@ -136,53 +143,26 @@ public class TokenRESTService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates a user, generates an auth token, associates that auth token
|
||||
* with the user's UserContext for use by further requests. If an existing
|
||||
* token is provided, the authentication procedure will attempt to update
|
||||
* or reuse the provided token.
|
||||
*
|
||||
* Returns the credentials associated with the given request, using the
|
||||
* provided username and password.
|
||||
*
|
||||
* @param request
|
||||
* The request to use to derive the credentials.
|
||||
*
|
||||
* @param username
|
||||
* The username of the user who is to be authenticated.
|
||||
* The username to associate with the credentials, or null if the
|
||||
* username should be derived from the request.
|
||||
*
|
||||
* @param password
|
||||
* The password of the user who is to be authenticated.
|
||||
* The password to associate with the credentials, or null if the
|
||||
* password should be derived from the request.
|
||||
*
|
||||
* @param token
|
||||
* An optional existing auth token for the user who is to be
|
||||
* authenticated.
|
||||
*
|
||||
* @param consumedRequest
|
||||
* The HttpServletRequest associated with the login attempt. The
|
||||
* parameters of this request may not be accessible, as the request may
|
||||
* have been fully consumed by JAX-RS.
|
||||
*
|
||||
* @param parameters
|
||||
* A MultivaluedMap containing all parameters from the given HTTP
|
||||
* request. All request parameters must be made available through this
|
||||
* map, even if those parameters are no longer accessible within the
|
||||
* now-fully-consumed HTTP request.
|
||||
*
|
||||
* @return The auth token for the newly logged-in user.
|
||||
* @throws GuacamoleException If an error prevents successful login.
|
||||
* @return
|
||||
* A new Credentials object whose contents have been derived from the
|
||||
* given request, along with the provided username and password.
|
||||
*/
|
||||
@POST
|
||||
@AuthProviderRESTExposure
|
||||
public APIAuthToken createToken(@FormParam("username") String username,
|
||||
@FormParam("password") String password,
|
||||
@FormParam("token") String token,
|
||||
@Context HttpServletRequest consumedRequest,
|
||||
MultivaluedMap<String, String> parameters)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Reconstitute the HTTP request with the map of parameters
|
||||
HttpServletRequest request = new APIRequest(consumedRequest, parameters);
|
||||
|
||||
// Pull existing session if token provided
|
||||
GuacamoleSession existingSession;
|
||||
if (token != null)
|
||||
existingSession = tokenSessionMap.get(token);
|
||||
else
|
||||
existingSession = null;
|
||||
private Credentials getCredentials(HttpServletRequest request,
|
||||
String username, String password) {
|
||||
|
||||
// If no username/password given, try Authorization header
|
||||
if (username == null && password == null) {
|
||||
@@ -215,41 +195,151 @@ public class TokenRESTService {
|
||||
}
|
||||
|
||||
} // end Authorization header fallback
|
||||
|
||||
|
||||
// Build credentials
|
||||
Credentials credentials = new Credentials();
|
||||
credentials.setUsername(username);
|
||||
credentials.setPassword(password);
|
||||
credentials.setRequest(request);
|
||||
credentials.setSession(request.getSession(true));
|
||||
|
||||
UserContext userContext;
|
||||
try {
|
||||
|
||||
// Update existing user context if session already exists
|
||||
if (existingSession != null)
|
||||
userContext = authProvider.updateUserContext(existingSession.getUserContext(), credentials);
|
||||
return credentials;
|
||||
|
||||
/// Otherwise, generate a new user context
|
||||
else {
|
||||
}
|
||||
|
||||
userContext = authProvider.getUserContext(credentials);
|
||||
/**
|
||||
* Attempts authentication against all AuthenticationProviders, in order,
|
||||
* using the provided credentials. The first authentication failure takes
|
||||
* priority, but remaining AuthenticationProviders are attempted. If any
|
||||
* AuthenticationProvider succeeds, the resulting AuthenticatedUser is
|
||||
* returned, and no further AuthenticationProviders are tried.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials to use for authentication.
|
||||
*
|
||||
* @return
|
||||
* The AuthenticatedUser given by the highest-priority
|
||||
* AuthenticationProvider for which the given credentials are valid.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the given credentials are not valid for any
|
||||
* AuthenticationProvider, or if an error occurs while authenticating
|
||||
* the user.
|
||||
*/
|
||||
private AuthenticatedUser authenticateUser(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Log successful authentication
|
||||
if (userContext != null && logger.isInfoEnabled())
|
||||
logger.info("User \"{}\" successfully authenticated from {}.",
|
||||
userContext.self().getIdentifier(), getLoggableAddress(request));
|
||||
GuacamoleCredentialsException authFailure = null;
|
||||
|
||||
// Attempt authentication against each AuthenticationProvider
|
||||
for (AuthenticationProvider authProvider : authProviders) {
|
||||
|
||||
// Attempt authentication
|
||||
try {
|
||||
AuthenticatedUser authenticatedUser = authProvider.authenticateUser(credentials);
|
||||
if (authenticatedUser != null)
|
||||
return authenticatedUser;
|
||||
}
|
||||
|
||||
// Request standard username/password if no user context was produced
|
||||
if (userContext == null)
|
||||
throw new GuacamoleInvalidCredentialsException("Permission Denied.",
|
||||
CredentialsInfo.USERNAME_PASSWORD);
|
||||
// First failure takes priority for now
|
||||
catch (GuacamoleCredentialsException e) {
|
||||
if (authFailure == null)
|
||||
authFailure = e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If a specific failure occured, rethrow that
|
||||
if (authFailure != null)
|
||||
throw authFailure;
|
||||
|
||||
// Otherwise, request standard username/password
|
||||
throw new GuacamoleInvalidCredentialsException(
|
||||
"Permission Denied.",
|
||||
CredentialsInfo.USERNAME_PASSWORD
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-authenticates the given AuthenticatedUser against the
|
||||
* AuthenticationProvider that originally created it, using the given
|
||||
* Credentials.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* The AuthenticatedUser to re-authenticate.
|
||||
*
|
||||
* @param credentials
|
||||
* The Credentials to use to re-authenticate the user.
|
||||
*
|
||||
* @return
|
||||
* A AuthenticatedUser which may have been updated due to re-
|
||||
* authentication.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error prevents the user from being re-authenticated.
|
||||
*/
|
||||
private AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
// Get original AuthenticationProvider
|
||||
AuthenticationProvider authProvider = authenticatedUser.getAuthenticationProvider();
|
||||
|
||||
// Re-authenticate the AuthenticatedUser against the original AuthenticationProvider only
|
||||
authenticatedUser = authProvider.updateAuthenticatedUser(authenticatedUser, credentials);
|
||||
if (authenticatedUser == null)
|
||||
throw new GuacamoleSecurityException("User re-authentication failed.");
|
||||
|
||||
return authenticatedUser;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the AuthenticatedUser associated with the given session and
|
||||
* credentials, performing a fresh authentication and creating a new
|
||||
* AuthenticatedUser if necessary.
|
||||
*
|
||||
* @param existingSession
|
||||
* The current GuacamoleSession, or null if no session exists yet.
|
||||
*
|
||||
* @param credentials
|
||||
* The Credentials to use to authenticate the user.
|
||||
*
|
||||
* @return
|
||||
* The AuthenticatedUser associated with the given session and
|
||||
* credentials.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while authenticating or re-authenticating the
|
||||
* user.
|
||||
*/
|
||||
private AuthenticatedUser getAuthenticatedUser(GuacamoleSession existingSession,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
try {
|
||||
|
||||
// Re-authenticate user if session exists
|
||||
if (existingSession != null)
|
||||
return updateAuthenticatedUser(existingSession.getAuthenticatedUser(), credentials);
|
||||
|
||||
// Otherwise, attempt authentication as a new user
|
||||
AuthenticatedUser authenticatedUser = authenticateUser(credentials);
|
||||
if (logger.isInfoEnabled())
|
||||
logger.info("User \"{}\" successfully authenticated from {}.",
|
||||
authenticatedUser.getIdentifier(),
|
||||
getLoggableAddress(credentials.getRequest()));
|
||||
|
||||
return authenticatedUser;
|
||||
|
||||
}
|
||||
|
||||
// Log and rethrow any authentication errors
|
||||
catch (GuacamoleException e) {
|
||||
|
||||
// Get request and username for sake of logging
|
||||
HttpServletRequest request = credentials.getRequest();
|
||||
String username = credentials.getUsername();
|
||||
|
||||
// Log authentication failures with associated usernames
|
||||
if (username != null) {
|
||||
if (logger.isWarnEnabled())
|
||||
@@ -260,27 +350,172 @@ public class TokenRESTService {
|
||||
// Log anonymous authentication failures
|
||||
else if (logger.isDebugEnabled())
|
||||
logger.debug("Anonymous authentication attempt from {} failed.",
|
||||
getLoggableAddress(request), username);
|
||||
getLoggableAddress(request));
|
||||
|
||||
// Rethrow exception
|
||||
throw e;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all UserContexts associated with the given AuthenticatedUser,
|
||||
* updating existing UserContexts, if any. If no UserContexts are yet
|
||||
* associated with the given AuthenticatedUser, new UserContexts are
|
||||
* generated by polling each available AuthenticationProvider.
|
||||
*
|
||||
* @param existingSession
|
||||
* The current GuacamoleSession, or null if no session exists yet.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* The AuthenticatedUser that has successfully authenticated or re-
|
||||
* authenticated.
|
||||
*
|
||||
* @return
|
||||
* A List of all UserContexts associated with the given
|
||||
* AuthenticatedUser.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while creating or updating any UserContext.
|
||||
*/
|
||||
private List<UserContext> getUserContexts(GuacamoleSession existingSession,
|
||||
AuthenticatedUser authenticatedUser) throws GuacamoleException {
|
||||
|
||||
List<UserContext> userContexts = new ArrayList<UserContext>(authProviders.size());
|
||||
|
||||
// If UserContexts already exist, update them and add to the list
|
||||
if (existingSession != null) {
|
||||
|
||||
// Update all old user contexts
|
||||
List<UserContext> oldUserContexts = existingSession.getUserContexts();
|
||||
for (UserContext oldUserContext : oldUserContexts) {
|
||||
|
||||
// Update existing UserContext
|
||||
AuthenticationProvider authProvider = oldUserContext.getAuthenticationProvider();
|
||||
UserContext userContext = authProvider.updateUserContext(oldUserContext, authenticatedUser);
|
||||
|
||||
// Add to available data, if successful
|
||||
if (userContext != null)
|
||||
userContexts.add(userContext);
|
||||
|
||||
// If unsuccessful, log that this happened, as it may be a bug
|
||||
else
|
||||
logger.debug("AuthenticationProvider \"{}\" retroactively destroyed its UserContext.",
|
||||
authProvider.getClass().getName());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Otherwise, create new UserContexts from available AuthenticationProviders
|
||||
else {
|
||||
|
||||
// Get UserContexts from each available AuthenticationProvider
|
||||
for (AuthenticationProvider authProvider : authProviders) {
|
||||
|
||||
// Generate new UserContext
|
||||
UserContext userContext = authProvider.getUserContext(authenticatedUser);
|
||||
|
||||
// Add to available data, if successful
|
||||
if (userContext != null)
|
||||
userContexts.add(userContext);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return userContexts;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates a user, generates an auth token, associates that auth token
|
||||
* with the user's UserContext for use by further requests. If an existing
|
||||
* token is provided, the authentication procedure will attempt to update
|
||||
* or reuse the provided token.
|
||||
*
|
||||
* @param username
|
||||
* The username of the user who is to be authenticated.
|
||||
*
|
||||
* @param password
|
||||
* The password of the user who is to be authenticated.
|
||||
*
|
||||
* @param token
|
||||
* An optional existing auth token for the user who is to be
|
||||
* authenticated.
|
||||
*
|
||||
* @param consumedRequest
|
||||
* The HttpServletRequest associated with the login attempt. The
|
||||
* parameters of this request may not be accessible, as the request may
|
||||
* have been fully consumed by JAX-RS.
|
||||
*
|
||||
* @param parameters
|
||||
* A MultivaluedMap containing all parameters from the given HTTP
|
||||
* request. All request parameters must be made available through this
|
||||
* map, even if those parameters are no longer accessible within the
|
||||
* now-fully-consumed HTTP request.
|
||||
*
|
||||
* @return
|
||||
* An authentication response object containing the possible-new auth
|
||||
* token, as well as other related data.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error prevents successful authentication.
|
||||
*/
|
||||
@POST
|
||||
@AuthProviderRESTExposure
|
||||
public APIAuthenticationResult createToken(@FormParam("username") String username,
|
||||
@FormParam("password") String password,
|
||||
@FormParam("token") String token,
|
||||
@Context HttpServletRequest consumedRequest,
|
||||
MultivaluedMap<String, String> parameters)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Reconstitute the HTTP request with the map of parameters
|
||||
HttpServletRequest request = new APIRequest(consumedRequest, parameters);
|
||||
|
||||
// Pull existing session if token provided
|
||||
GuacamoleSession existingSession;
|
||||
if (token != null)
|
||||
existingSession = tokenSessionMap.get(token);
|
||||
else
|
||||
existingSession = null;
|
||||
|
||||
// Build credentials from request
|
||||
Credentials credentials = getCredentials(request, username, password);
|
||||
|
||||
// Get up-to-date AuthenticatedUser and associated UserContexts
|
||||
AuthenticatedUser authenticatedUser = getAuthenticatedUser(existingSession, credentials);
|
||||
List<UserContext> userContexts = getUserContexts(existingSession, authenticatedUser);
|
||||
|
||||
// Update existing session, if it exists
|
||||
String authToken;
|
||||
if (existingSession != null) {
|
||||
authToken = token;
|
||||
existingSession.setCredentials(credentials);
|
||||
existingSession.setUserContext(userContext);
|
||||
existingSession.setAuthenticatedUser(authenticatedUser);
|
||||
existingSession.setUserContexts(userContexts);
|
||||
}
|
||||
|
||||
// If no existing session, generate a new token/session pair
|
||||
else {
|
||||
authToken = authTokenGenerator.getToken();
|
||||
tokenSessionMap.put(authToken, new GuacamoleSession(environment, credentials, userContext));
|
||||
tokenSessionMap.put(authToken, new GuacamoleSession(environment, authenticatedUser, userContexts));
|
||||
logger.debug("Login was successful for user \"{}\".", authenticatedUser.getIdentifier());
|
||||
}
|
||||
|
||||
logger.debug("Login was successful for user \"{}\".", userContext.self().getIdentifier());
|
||||
return new APIAuthToken(authToken, userContext.self().getIdentifier());
|
||||
|
||||
// Build list of all available auth providers
|
||||
List<String> authProviderIdentifiers = new ArrayList<String>(userContexts.size());
|
||||
for (UserContext userContext : userContexts)
|
||||
authProviderIdentifiers.add(userContext.getAuthenticationProvider().getIdentifier());
|
||||
|
||||
// Return possibly-new auth token
|
||||
return new APIAuthenticationResult(
|
||||
authToken,
|
||||
authenticatedUser.getIdentifier(),
|
||||
authenticatedUser.getAuthenticationProvider().getIdentifier(),
|
||||
authProviderIdentifiers
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.rest.clipboard;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Response;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleUnsupportedException;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
import org.glyptodon.guacamole.net.basic.ClipboardState;
|
||||
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
import org.glyptodon.guacamole.properties.BooleanGuacamoleProperty;
|
||||
|
||||
/**
|
||||
* A REST service for reading the current contents of the clipboard.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
@Path("/clipboard")
|
||||
public class ClipboardRESTService {
|
||||
|
||||
/**
|
||||
* The Guacamole server environment.
|
||||
*/
|
||||
@Inject
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* A service for authenticating users from auth tokens.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationService authenticationService;
|
||||
|
||||
/**
|
||||
* The amount of time to wait for clipboard changes, in milliseconds.
|
||||
*/
|
||||
private static final int CLIPBOARD_TIMEOUT = 250;
|
||||
|
||||
/**
|
||||
* Whether clipboard integration is enabled.
|
||||
*/
|
||||
public static final BooleanGuacamoleProperty INTEGRATION_ENABLED = new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "enable-clipboard-integration"; }
|
||||
|
||||
};
|
||||
|
||||
@GET
|
||||
@AuthProviderRESTExposure
|
||||
public Response getClipboard(@QueryParam("token") String authToken)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Only bother if actually enabled
|
||||
if (environment.getProperty(INTEGRATION_ENABLED, false)) {
|
||||
|
||||
// Get clipboard
|
||||
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||
final ClipboardState clipboard = session.getClipboardState();
|
||||
|
||||
// Send clipboard contents
|
||||
synchronized (clipboard) {
|
||||
clipboard.waitForContents(CLIPBOARD_TIMEOUT);
|
||||
return Response.ok(clipboard.getContents(),
|
||||
clipboard.getMimetype()).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Otherwise, inform not supported
|
||||
else
|
||||
throw new GuacamoleUnsupportedException("Clipboard integration not supported");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -41,11 +41,11 @@ import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.net.auth.Directory;
|
||||
import org.glyptodon.guacamole.net.auth.User;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleCredentialsException;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
@@ -121,12 +121,6 @@ public class UserRESTService {
|
||||
@Inject
|
||||
private ObjectRetrievalService retrievalService;
|
||||
|
||||
/**
|
||||
* The authentication provider used to authenticating a user.
|
||||
*/
|
||||
@Inject
|
||||
private AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* Gets a list of users in the system, filtering the returned list by the
|
||||
* given permission, if specified.
|
||||
@@ -337,8 +331,16 @@ public class UserRESTService {
|
||||
credentials.setRequest(request);
|
||||
credentials.setSession(request.getSession(true));
|
||||
|
||||
// Verify that the old password was correct
|
||||
if (authProvider.getUserContext(credentials) == null) {
|
||||
// Verify that the old password was correct
|
||||
try {
|
||||
if (userContext.getAuthenticationProvider().authenticateUser(credentials) == null) {
|
||||
throw new APIException(APIError.Type.PERMISSION_DENIED,
|
||||
"Permission denied.");
|
||||
}
|
||||
}
|
||||
|
||||
// Pass through any credentials exceptions as simple permission denied
|
||||
catch (GuacamoleCredentialsException e) {
|
||||
throw new APIException(APIError.Type.PERMISSION_DENIED,
|
||||
"Permission denied.");
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.xml.user_mapping;
|
||||
package org.glyptodon.guacamole.net.basic.xml.usermapping;
|
||||
|
||||
import org.glyptodon.guacamole.net.basic.auth.Authorization;
|
||||
import org.glyptodon.guacamole.net.basic.auth.UserMapping;
|
@@ -20,7 +20,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.xml.user_mapping;
|
||||
package org.glyptodon.guacamole.net.basic.xml.usermapping;
|
||||
|
||||
import org.glyptodon.guacamole.net.basic.auth.Authorization;
|
||||
import org.glyptodon.guacamole.xml.TagHandler;
|
@@ -20,7 +20,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.xml.user_mapping;
|
||||
package org.glyptodon.guacamole.net.basic.xml.usermapping;
|
||||
|
||||
import org.glyptodon.guacamole.xml.TagHandler;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
@@ -20,7 +20,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.xml.user_mapping;
|
||||
package org.glyptodon.guacamole.net.basic.xml.usermapping;
|
||||
|
||||
import org.glyptodon.guacamole.xml.TagHandler;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
@@ -20,7 +20,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.xml.user_mapping;
|
||||
package org.glyptodon.guacamole.net.basic.xml.usermapping;
|
||||
|
||||
import org.glyptodon.guacamole.net.basic.auth.UserMapping;
|
||||
import org.glyptodon.guacamole.xml.TagHandler;
|
@@ -23,5 +23,5 @@
|
||||
/**
|
||||
* Classes related to parsing the user-mapping.xml file.
|
||||
*/
|
||||
package org.glyptodon.guacamole.net.basic.xml.user_mapping;
|
||||
package org.glyptodon.guacamole.net.basic.xml.usermapping;
|
||||
|
@@ -57,7 +57,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
||||
|
||||
/**
|
||||
* The unique identifier of the local cookie which stores the user's
|
||||
* current authentication token and user ID.
|
||||
* current authentication token and username.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
@@ -68,7 +68,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
||||
* and given arbitrary parameters, returning a promise that succeeds only
|
||||
* if the authentication operation was successful. The resulting
|
||||
* authentication data can be retrieved later via getCurrentToken() or
|
||||
* getCurrentUserID().
|
||||
* getCurrentUsername().
|
||||
*
|
||||
* The provided parameters can be virtually any object, as each property
|
||||
* will be sent as an HTTP parameter in the authentication request.
|
||||
@@ -99,8 +99,9 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
||||
|
||||
// Store auth data
|
||||
$cookieStore.put(AUTH_COOKIE_ID, {
|
||||
authToken : data.authToken,
|
||||
userID : data.userID
|
||||
authToken : data.authToken,
|
||||
username : data.username,
|
||||
dataSource : data.dataSource
|
||||
});
|
||||
|
||||
// Process is complete
|
||||
@@ -174,7 +175,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
||||
* its properties will be included as parameters in the update request.
|
||||
* This function returns a promise that succeeds only if the authentication
|
||||
* operation was successful. The resulting authentication data can be
|
||||
* retrieved later via getCurrentToken() or getCurrentUserID().
|
||||
* retrieved later via getCurrentToken() or getCurrentUsername().
|
||||
*
|
||||
* If there is no current auth token, this function behaves identically to
|
||||
* authenticate(), and makes a general authentication request.
|
||||
@@ -209,7 +210,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
||||
* with a username and password, ignoring any currently-stored token,
|
||||
* returning a promise that succeeds only if the login operation was
|
||||
* successful. The resulting authentication data can be retrieved later
|
||||
* via getCurrentToken() or getCurrentUserID().
|
||||
* via getCurrentToken() or getCurrentUsername().
|
||||
*
|
||||
* @param {String} username
|
||||
* The username to log in with.
|
||||
@@ -254,19 +255,19 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the user ID of the current user. If the current user is not
|
||||
* logged in, this ID may not be valid.
|
||||
* Returns the username of the current user. If the current user is not
|
||||
* logged in, this value may not be valid.
|
||||
*
|
||||
* @returns {String}
|
||||
* The user ID of the current user, or null if no authentication data
|
||||
* The username of the current user, or null if no authentication data
|
||||
* is present.
|
||||
*/
|
||||
service.getCurrentUserID = function getCurrentUserID() {
|
||||
service.getCurrentUsername = function getCurrentUsername() {
|
||||
|
||||
// Return user ID, if available
|
||||
// Return username, if available
|
||||
var authData = $cookieStore.get(AUTH_COOKIE_ID);
|
||||
if (authData)
|
||||
return authData.userID;
|
||||
return authData.username;
|
||||
|
||||
// No auth data present
|
||||
return null;
|
||||
@@ -293,5 +294,45 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the identifier of the data source that authenticated the current
|
||||
* user. If the current user is not logged in, this value may not be valid.
|
||||
*
|
||||
* @returns {String}
|
||||
* The identifier of the data source that authenticated the current
|
||||
* user, or null if no authentication data is present.
|
||||
*/
|
||||
service.getDataSource = function getDataSource() {
|
||||
|
||||
// Return data source, if available
|
||||
var authData = $cookieStore.get(AUTH_COOKIE_ID);
|
||||
if (authData)
|
||||
return authData.dataSource;
|
||||
|
||||
// No auth data present
|
||||
return null;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the identifiers of all data sources available to the current
|
||||
* user. If the current user is not logged in, this value may not be valid.
|
||||
*
|
||||
* @returns {String[]}
|
||||
* The identifiers of all data sources availble to the current user,
|
||||
* or null if no authentication data is present.
|
||||
*/
|
||||
service.getAvailableDataSources = function getAvailableDataSources() {
|
||||
|
||||
// Return data sources, if available
|
||||
var authData = $cookieStore.get(AUTH_COOKIE_ID);
|
||||
if (authData)
|
||||
return authData.availableDataSources;
|
||||
|
||||
// No auth data present
|
||||
return null;
|
||||
|
||||
};
|
||||
|
||||
return service;
|
||||
}]);
|
||||
|
@@ -190,7 +190,7 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
||||
});
|
||||
|
||||
// Query the user's permissions for the current connection
|
||||
permissionService.getPermissions(authenticationService.getCurrentUserID())
|
||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
||||
.success(function permissionsReceived(permissions) {
|
||||
|
||||
$scope.permissions = permissions;
|
||||
|
@@ -128,7 +128,7 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope'
|
||||
});
|
||||
|
||||
// Query the user's permissions for the current connection group
|
||||
permissionService.getPermissions(authenticationService.getCurrentUserID())
|
||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
||||
.success(function permissionsReceived(permissions) {
|
||||
|
||||
$scope.permissions = permissions;
|
||||
|
@@ -153,7 +153,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
|
||||
});
|
||||
|
||||
// Query the user's permissions for the current connection
|
||||
permissionService.getPermissions(authenticationService.getCurrentUserID())
|
||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
||||
.success(function permissionsReceived(permissions) {
|
||||
|
||||
$scope.permissions = permissions;
|
||||
|
@@ -78,7 +78,7 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu()
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
$scope.username = authenticationService.getCurrentUserID();
|
||||
$scope.username = authenticationService.getCurrentUsername();
|
||||
|
||||
/**
|
||||
* The available main pages for the current user.
|
||||
|
@@ -156,7 +156,7 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
||||
PermissionSet.removeConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, ConnectionGroup.ROOT_IDENTIFIER);
|
||||
|
||||
// Ignore permission to update self
|
||||
PermissionSet.removeUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, authenticationService.getCurrentUserID());
|
||||
PermissionSet.removeUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, authenticationService.getCurrentUsername());
|
||||
|
||||
// Determine whether the current user needs access to the user management UI
|
||||
var canManageUsers =
|
||||
@@ -247,7 +247,7 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
||||
|
||||
// Retrieve current permissions, resolving main pages if possible
|
||||
// Resolve promise using settings pages derived from permissions
|
||||
permissionService.getPermissions(authenticationService.getCurrentUserID())
|
||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
||||
.success(function permissionsRetrieved(permissions) {
|
||||
deferred.resolve(generateSettingsPages(permissions));
|
||||
});
|
||||
@@ -328,7 +328,7 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
||||
});
|
||||
|
||||
// Retrieve current permissions, resolving main pages if possible
|
||||
permissionService.getPermissions(authenticationService.getCurrentUserID())
|
||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
||||
.success(function permissionsRetrieved(retrievedPermissions) {
|
||||
permissions = retrievedPermissions;
|
||||
resolveMainPages();
|
||||
|
@@ -48,7 +48,7 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
|
||||
var permissionService = $injector.get('permissionService');
|
||||
|
||||
// Identifier of the current user
|
||||
var currentUserID = authenticationService.getCurrentUserID();
|
||||
var currentUsername = authenticationService.getCurrentUsername();
|
||||
|
||||
/**
|
||||
* An action to be provided along with the object sent to
|
||||
@@ -120,7 +120,7 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
|
||||
};
|
||||
|
||||
// Retrieve current permissions
|
||||
permissionService.getPermissions(currentUserID)
|
||||
permissionService.getPermissions(currentUsername)
|
||||
.success(function permissionsRetrieved(permissions) {
|
||||
|
||||
$scope.permissions = permissions;
|
||||
|
@@ -64,7 +64,7 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
var username = authenticationService.getCurrentUserID();
|
||||
var username = authenticationService.getCurrentUsername();
|
||||
|
||||
/**
|
||||
* All currently-set preferences, or their defaults if not yet set.
|
||||
|
@@ -187,7 +187,7 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
||||
};
|
||||
|
||||
// Query the user's permissions
|
||||
permissionService.getPermissions(authenticationService.getCurrentUserID())
|
||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
||||
.success(function permissionsReceived(retrievedPermissions) {
|
||||
$scope.permissions = retrievedPermissions;
|
||||
});
|
||||
|
@@ -48,7 +48,7 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
|
||||
var userService = $injector.get('userService');
|
||||
|
||||
// Identifier of the current user
|
||||
var currentUserID = authenticationService.getCurrentUserID();
|
||||
var currentUsername = authenticationService.getCurrentUsername();
|
||||
|
||||
/**
|
||||
* An action to be provided along with the object sent to
|
||||
@@ -118,7 +118,7 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
|
||||
};
|
||||
|
||||
// Retrieve current permissions
|
||||
permissionService.getPermissions(currentUserID)
|
||||
permissionService.getPermissions(currentUsername)
|
||||
.success(function permissionsRetrieved(permissions) {
|
||||
|
||||
$scope.permissions = permissions;
|
||||
@@ -147,7 +147,7 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
|
||||
|
||||
// Display only other users, not self
|
||||
$scope.users = users.filter(function isNotSelf(user) {
|
||||
return user.username !== currentUserID;
|
||||
return user.username !== currentUsername;
|
||||
});
|
||||
|
||||
});
|
||||
|
Reference in New Issue
Block a user