forked from shaba/openuds
Re-validate UDS data for each connection attempt.
This commit is contained in:
parent
4cc11d783a
commit
584dee9fcd
@ -32,7 +32,7 @@ import org.apache.guacamole.net.auth.AbstractAuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Credentials;
|
||||
import org.apache.guacamole.protocol.GuacamoleConfiguration;
|
||||
import org.openuds.guacamole.connection.UDSConnection;
|
||||
|
||||
/**
|
||||
* A Guacamole user that was authenticated by an external UDS service.
|
||||
@ -50,10 +50,9 @@ public class UDSAuthenticatedUser extends AbstractAuthenticatedUser {
|
||||
private final Credentials credentials;
|
||||
|
||||
/**
|
||||
* The GuacamoleConfiguration generated from the connection information
|
||||
* returned by the external UDS service when the user authenticated.
|
||||
* The single connection that this user should be authorized to access.
|
||||
*/
|
||||
private final GuacamoleConfiguration config;
|
||||
private final UDSConnection connection;
|
||||
|
||||
/**
|
||||
* Creates a new UDSAuthenticatedUser representing a Guacamole user that
|
||||
@ -65,15 +64,14 @@ public class UDSAuthenticatedUser extends AbstractAuthenticatedUser {
|
||||
* @param credentials
|
||||
* The credentials provided by the user when they authenticated.
|
||||
*
|
||||
* @param config
|
||||
* The GuacamoleConfiguration generated from the connection information
|
||||
* returned by the external UDS service when the user authenticated.
|
||||
* @param connection
|
||||
* The single connection that the user should be authorized to access.
|
||||
*/
|
||||
public UDSAuthenticatedUser(AuthenticationProvider authProvider,
|
||||
Credentials credentials, GuacamoleConfiguration config) {
|
||||
Credentials credentials, UDSConnection connection) {
|
||||
this.authProvider = authProvider;
|
||||
this.credentials = credentials;
|
||||
this.config = config;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -92,16 +90,14 @@ public class UDSAuthenticatedUser extends AbstractAuthenticatedUser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the GuacamoleConfiguration generated from the connection
|
||||
* information provided by the external UDS service when the user
|
||||
* authenticated.
|
||||
* Returns the single connection that this user should be authorized to
|
||||
* access.
|
||||
*
|
||||
* @return
|
||||
* The GuacamoleConfiguration generated from the connection information
|
||||
* provided by the external UDS service when the user authenticated.
|
||||
* The single connection that this user should be authorized to access.
|
||||
*/
|
||||
public GuacamoleConfiguration getGuacamoleConfiguration() {
|
||||
return config;
|
||||
public UDSConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ import com.google.inject.Injector;
|
||||
import java.util.Collections;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleServerException;
|
||||
import org.apache.guacamole.form.Field;
|
||||
import org.apache.guacamole.net.auth.AbstractAuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||
@ -41,9 +40,8 @@ import org.apache.guacamole.net.auth.Credentials;
|
||||
import org.apache.guacamole.net.auth.UserContext;
|
||||
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||
import org.apache.guacamole.net.auth.simple.SimpleUserContext;
|
||||
import org.apache.guacamole.protocol.GuacamoleConfiguration;
|
||||
import org.openuds.guacamole.connection.ConnectionService;
|
||||
import org.openuds.guacamole.connection.UDSConnection;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -53,18 +51,20 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class UDSAuthenticationProvider extends AbstractAuthenticationProvider {
|
||||
|
||||
/**
|
||||
* The name of the single connection that should be exposed to any user
|
||||
* that authenticates via UDS.
|
||||
*/
|
||||
private static final String CONNECTION_NAME = "UDS";
|
||||
|
||||
/**
|
||||
* The name of the query parameter that should contain the data sent to
|
||||
* the UDS service for authentication.
|
||||
*/
|
||||
private static final String DATA_PARAMETER_NAME = "data";
|
||||
|
||||
/**
|
||||
* The form of credentials accepted by this extension.
|
||||
*/
|
||||
private static final CredentialsInfo UDS_CREDENTIALS =
|
||||
new CredentialsInfo(Collections.<Field>singletonList(
|
||||
new Field(DATA_PARAMETER_NAME, Field.Type.QUERY_PARAMETER)
|
||||
));
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
@ -109,29 +109,26 @@ public class UDSAuthenticationProvider extends AbstractAuthenticationProvider {
|
||||
|
||||
// Pull OpenUDS-specific "data" parameter
|
||||
String data = request.getParameter(DATA_PARAMETER_NAME);
|
||||
if (data != null && !data.isEmpty()) {
|
||||
|
||||
logger.debug("Retrieving connection configuration using data from \"{}\"...", data);
|
||||
|
||||
// Retrieve connection information using provided data
|
||||
GuacamoleConfiguration config = connectionService.getConnectionConfiguration(data);
|
||||
if (config != null) {
|
||||
|
||||
// Report successful authentication as a temporary, anonymous user,
|
||||
// storing the retrieved connection configuration data for future use
|
||||
return new UDSAuthenticatedUser(this, credentials, config);
|
||||
|
||||
}
|
||||
|
||||
if (data == null || data.isEmpty()) {
|
||||
logger.debug("UDS connection data was not provided. No connection retrieval from UDS will be performed.");
|
||||
throw new GuacamoleInvalidCredentialsException("Connection data was not provided.", UDS_CREDENTIALS);
|
||||
}
|
||||
|
||||
// Required parameter was missing or was invalid
|
||||
throw new GuacamoleInvalidCredentialsException(
|
||||
"Connection data was not provided or was rejected by UDS.",
|
||||
new CredentialsInfo(Collections.<Field>singletonList(
|
||||
new Field(DATA_PARAMETER_NAME, Field.Type.QUERY_PARAMETER)
|
||||
))
|
||||
);
|
||||
try {
|
||||
|
||||
// Retrieve connection information using provided data
|
||||
UDSConnection connection = new UDSConnection(connectionService, data);
|
||||
|
||||
// Report successful authentication as a temporary, anonymous user,
|
||||
// storing the retrieved connection configuration data for future use
|
||||
return new UDSAuthenticatedUser(this, credentials, connection);
|
||||
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
logger.info("Provided connection data could not be validated with UDS: {}", e.getMessage());
|
||||
logger.debug("Validation of UDS connection data failed.", e);
|
||||
throw new GuacamoleInvalidCredentialsException("Connection data was rejected by UDS.", e, UDS_CREDENTIALS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -145,10 +142,7 @@ public class UDSAuthenticationProvider extends AbstractAuthenticationProvider {
|
||||
|
||||
// Expose a single connection (derived from the "data" parameter
|
||||
// provided during authentication)
|
||||
return new SimpleUserContext(this, Collections.singletonMap(
|
||||
CONNECTION_NAME,
|
||||
((UDSAuthenticatedUser) authenticatedUser).getGuacamoleConfiguration()
|
||||
));
|
||||
return new UDSUserContext(this, (UDSAuthenticatedUser) authenticatedUser);
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Virtual Cable S.L.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.openuds.guacamole;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.net.auth.AbstractUserContext;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Connection;
|
||||
import org.apache.guacamole.net.auth.Directory;
|
||||
import org.apache.guacamole.net.auth.User;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.apache.guacamole.net.auth.simple.SimpleDirectory;
|
||||
import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet;
|
||||
import org.apache.guacamole.net.auth.simple.SimpleUser;
|
||||
import org.openuds.guacamole.connection.UDSConnection;
|
||||
|
||||
/**
|
||||
* UserContext implementation which exposes access only to a single
|
||||
* UDSConnection. The details of the connection exposed are determined by the
|
||||
* UDS-specific data associated with the user.
|
||||
*/
|
||||
public class UDSUserContext extends AbstractUserContext {
|
||||
|
||||
/**
|
||||
* The unique identifier of the root connection group.
|
||||
*/
|
||||
public static final String ROOT_CONNECTION_GROUP = DEFAULT_ROOT_CONNECTION_GROUP;
|
||||
|
||||
/**
|
||||
* The AuthenticationProvider that produced this UserContext.
|
||||
*/
|
||||
private final AuthenticationProvider authProvider;
|
||||
|
||||
/**
|
||||
* The AuthenticatedUser for whom this UserContext was created.
|
||||
*/
|
||||
private final UDSAuthenticatedUser authenticatedUser;
|
||||
|
||||
/**
|
||||
* Creates a new UDSUserContext that is associated with the given
|
||||
* AuthenticationProvider and uses the UDS-specific data of the given
|
||||
* UDSAuthenticatedUser to determine the connection that user can access.
|
||||
*
|
||||
* @param authProvider
|
||||
* The AuthenticationProvider that is producing the UserContext.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* The AuthenticatedUser for whom this UserContext is being created.
|
||||
*/
|
||||
public UDSUserContext(AuthenticationProvider authProvider,
|
||||
UDSAuthenticatedUser authenticatedUser) {
|
||||
this.authProvider = authProvider;
|
||||
this.authenticatedUser = authenticatedUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User self() {
|
||||
return new SimpleUser() {
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException {
|
||||
return new SimpleObjectPermissionSet(Collections.singleton(DEFAULT_ROOT_CONNECTION_GROUP));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getConnectionPermissions() throws GuacamoleException {
|
||||
return new SimpleObjectPermissionSet(Collections.singleton(UDSConnection.IDENTIFIER));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationProvider getAuthenticationProvider() {
|
||||
return authProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directory<Connection> getConnectionDirectory() throws GuacamoleException {
|
||||
return new SimpleDirectory<>(authenticatedUser.getConnection());
|
||||
}
|
||||
|
||||
}
|
@ -174,6 +174,8 @@ public class ConnectionService {
|
||||
public GuacamoleConfiguration getConnectionConfiguration(String data)
|
||||
throws GuacamoleException {
|
||||
|
||||
logger.debug("Retrieving/validating connection configuration using data from \"{}\"...", data);
|
||||
|
||||
// Build URI of remote service from the base URI and given data
|
||||
URI serviceURI = UriBuilder.fromUri(configService.getUDSBaseURI())
|
||||
.path(configService.getUDSConnectionPath())
|
||||
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Virtual Cable S.L.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.openuds.guacamole.connection;
|
||||
|
||||
import java.util.Map;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.simple.SimpleConnection;
|
||||
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||
import org.openuds.guacamole.UDSUserContext;
|
||||
|
||||
/**
|
||||
* Connection implementation which uses provided data to communicate with a
|
||||
* remote UDS service to dynamically authorize access to a remote desktop. The
|
||||
* provided data is validated when the UDSConnection is created and upon each
|
||||
* connection attempt.
|
||||
*/
|
||||
public class UDSConnection extends SimpleConnection {
|
||||
|
||||
/**
|
||||
* The name of the single connection that should be exposed to any user
|
||||
* that authenticates via UDS.
|
||||
*/
|
||||
public static final String NAME = "UDS";
|
||||
|
||||
/**
|
||||
* The unique identifier of the single connection that should be exposed to
|
||||
* any user that authenticates via UDS.
|
||||
*/
|
||||
public static final String IDENTIFIER = NAME;
|
||||
|
||||
/**
|
||||
* Service for retrieving configuration information.
|
||||
*/
|
||||
private final ConnectionService connectionService;
|
||||
|
||||
/**
|
||||
* The UDS-specific data that should be provided to the remote UDS service
|
||||
* to re-authenticate the user and determine the details of the connection
|
||||
* they are authorized to access.
|
||||
*/
|
||||
private final String data;
|
||||
|
||||
/**
|
||||
* Creates a new UDSConnection which exposes access to a remote desktop
|
||||
* that is dynamically authorized by exchanging arbitrary UDS-specific data
|
||||
* with a remote service. If the data is accepted by the UDS service, the
|
||||
* data will also be re-validated upon each connection attempt.
|
||||
*
|
||||
* @param connectionService
|
||||
* The service that should be used to validate the provided UDS data
|
||||
* and retrieve corresponding connection configuration information.
|
||||
*
|
||||
* @param data
|
||||
* The UDS-specific data that should be provided to the remote UDS
|
||||
* service.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the provided data is no longer valid or the UDS service does not
|
||||
* respond successfully.
|
||||
*/
|
||||
public UDSConnection(ConnectionService connectionService, String data)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Validate provided data
|
||||
super.setConfiguration(connectionService.getConnectionConfiguration(data));
|
||||
|
||||
this.connectionService = connectionService;
|
||||
this.data = data;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentIdentifier() {
|
||||
return UDSUserContext.ROOT_CONNECTION_GROUP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParentIdentifier(String parentIdentifier) {
|
||||
throw new UnsupportedOperationException("UDSConnection is read-only.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
throw new UnsupportedOperationException("UDSConnection is read-only.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(String identifier) {
|
||||
throw new UnsupportedOperationException("UDSConnection is read-only.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleTunnel connect(GuacamoleClientInformation info,
|
||||
Map<String, String> tokens) throws GuacamoleException {
|
||||
|
||||
// Re-validate provided data (do not allow connections if data is no
|
||||
// longer valid)
|
||||
super.setConfiguration(connectionService.getConnectionConfiguration(data));
|
||||
|
||||
// Connect with configuration produced from data
|
||||
return super.connect(info, tokens);
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user