mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-5: Implement sharing-specific user context and in-memory storage. Add additional tracking of connections for sake of sharing.
This commit is contained in:
@@ -63,6 +63,7 @@ import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper;
|
|||||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper;
|
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper;
|
||||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
|
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
|
||||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionSet;
|
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionSet;
|
||||||
|
import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService;
|
||||||
import org.apache.guacamole.auth.jdbc.sharing.HashSharedConnectionMap;
|
import org.apache.guacamole.auth.jdbc.sharing.HashSharedConnectionMap;
|
||||||
import org.apache.guacamole.auth.jdbc.sharing.SecureRandomShareKeyGenerator;
|
import org.apache.guacamole.auth.jdbc.sharing.SecureRandomShareKeyGenerator;
|
||||||
import org.apache.guacamole.auth.jdbc.sharing.ShareKeyGenerator;
|
import org.apache.guacamole.auth.jdbc.sharing.ShareKeyGenerator;
|
||||||
@@ -168,6 +169,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
|
|||||||
bind(ConnectionGroupPermissionService.class);
|
bind(ConnectionGroupPermissionService.class);
|
||||||
bind(ConnectionGroupService.class);
|
bind(ConnectionGroupService.class);
|
||||||
bind(ConnectionPermissionService.class);
|
bind(ConnectionPermissionService.class);
|
||||||
|
bind(ConnectionSharingService.class);
|
||||||
bind(ConnectionService.class);
|
bind(ConnectionService.class);
|
||||||
bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class);
|
bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class);
|
||||||
bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
|
bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
|
||||||
|
@@ -19,10 +19,12 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.jdbc.activeconnection;
|
package org.apache.guacamole.auth.jdbc.activeconnection;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.GuacamoleSecurityException;
|
|
||||||
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
|
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
|
||||||
|
import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||||
|
import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService;
|
||||||
import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
|
import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
|
||||||
import org.apache.guacamole.auth.jdbc.user.AuthenticatedUser;
|
import org.apache.guacamole.auth.jdbc.user.AuthenticatedUser;
|
||||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||||
@@ -37,15 +39,21 @@ import org.apache.guacamole.net.auth.credentials.UserCredentials;
|
|||||||
*/
|
*/
|
||||||
public class TrackedActiveConnection extends RestrictedObject implements ActiveConnection {
|
public class TrackedActiveConnection extends RestrictedObject implements ActiveConnection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for managing shared connections.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private ConnectionSharingService sharingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of this active connection.
|
* The identifier of this active connection.
|
||||||
*/
|
*/
|
||||||
private String identifier;
|
private String identifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the associated connection.
|
* The connection being actively used or shared.
|
||||||
*/
|
*/
|
||||||
private String connectionIdentifier;
|
private ModeledConnection connection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the associated sharing profile.
|
* The identifier of the associated sharing profile.
|
||||||
@@ -98,7 +106,7 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
|
|||||||
super.init(currentUser);
|
super.init(currentUser);
|
||||||
|
|
||||||
// Copy all non-sensitive data from given record
|
// Copy all non-sensitive data from given record
|
||||||
this.connectionIdentifier = activeConnectionRecord.getConnectionIdentifier();
|
this.connection = activeConnectionRecord.getConnection();
|
||||||
this.sharingProfileIdentifier = activeConnectionRecord.getSharingProfileIdentifier();
|
this.sharingProfileIdentifier = activeConnectionRecord.getSharingProfileIdentifier();
|
||||||
this.identifier = activeConnectionRecord.getUUID().toString();
|
this.identifier = activeConnectionRecord.getUUID().toString();
|
||||||
this.startDate = activeConnectionRecord.getStartDate();
|
this.startDate = activeConnectionRecord.getStartDate();
|
||||||
@@ -121,15 +129,29 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
|
|||||||
public void setIdentifier(String identifier) {
|
public void setIdentifier(String identifier) {
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the connection being actively used. If this active connection is
|
||||||
|
* not the primary connection, this will be the connection being actively
|
||||||
|
* shared.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The connection being actively used.
|
||||||
|
*/
|
||||||
|
public ModeledConnection getConnection() {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getConnectionIdentifier() {
|
public String getConnectionIdentifier() {
|
||||||
return connectionIdentifier;
|
return connection.getIdentifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setConnectionIdentifier(String connnectionIdentifier) {
|
public void setConnectionIdentifier(String connnectionIdentifier) {
|
||||||
this.connectionIdentifier = connnectionIdentifier;
|
throw new UnsupportedOperationException("The connection identifier of "
|
||||||
|
+ "TrackedActiveConnection is inherited from the underlying "
|
||||||
|
+ "connection.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -145,7 +167,8 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
|
|||||||
@Override
|
@Override
|
||||||
public UserCredentials getSharingCredentials(String identifier)
|
public UserCredentials getSharingCredentials(String identifier)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
throw new GuacamoleSecurityException("Permission denied");
|
return sharingService.generateTemporaryCredentials(getCurrentUser(),
|
||||||
|
this, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.guacamole.auth.jdbc.sharing;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import java.util.Collections;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import org.apache.guacamole.auth.jdbc.user.AuthenticatedUser;
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection;
|
||||||
|
import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
|
||||||
|
import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileService;
|
||||||
|
import org.apache.guacamole.form.Field;
|
||||||
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
|
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||||
|
import org.apache.guacamole.net.auth.credentials.UserCredentials;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service which provides convenience methods for sharing active connections.
|
||||||
|
*
|
||||||
|
* @author Michael Jumper
|
||||||
|
*/
|
||||||
|
public class ConnectionSharingService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the query parameter that is used when authenticating obtain
|
||||||
|
* temporary access to a connection.
|
||||||
|
*/
|
||||||
|
public static final String SHARE_KEY_NAME = "key";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generator for sharing keys.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private ShareKeyGenerator keyGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of all currently-shared connections.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private SharedConnectionMap connectionMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for retrieving and manipulating sharing profile objects.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private SharingProfileService sharingProfileService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The credentials expected when a user is authenticating using temporary
|
||||||
|
* credentials in order to obtain access to a single connection.
|
||||||
|
*/
|
||||||
|
public static final CredentialsInfo SHARE_KEY =
|
||||||
|
new CredentialsInfo(Collections.<Field>singletonList(
|
||||||
|
new Field(SHARE_KEY_NAME, Field.Type.QUERY_PARAMETER)
|
||||||
|
));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a set of temporary credentials which can be used to connect to
|
||||||
|
* the given connection using the given sharing profile. If the user does
|
||||||
|
* not have permission to share the connection via the given sharing
|
||||||
|
* profile, permission will be denied.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user sharing the connection.
|
||||||
|
*
|
||||||
|
* @param activeConnection
|
||||||
|
* The active connection being shared.
|
||||||
|
*
|
||||||
|
* @param sharingProfileIdentifier
|
||||||
|
* The identifier of the sharing profile dictating the semantics or
|
||||||
|
* restrictions applying to the shared session.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A newly-generated set of temporary credentials which can be used to
|
||||||
|
* connect to the given connection.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If permission to share the given connection is denied.
|
||||||
|
*/
|
||||||
|
public UserCredentials generateTemporaryCredentials(AuthenticatedUser user,
|
||||||
|
TrackedActiveConnection activeConnection,
|
||||||
|
String sharingProfileIdentifier) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Pull sharing profile (verifying access)
|
||||||
|
ModeledSharingProfile sharingProfile =
|
||||||
|
sharingProfileService.retrieveObject(user,
|
||||||
|
sharingProfileIdentifier);
|
||||||
|
|
||||||
|
// Generate a share key for the requested connection
|
||||||
|
String key = keyGenerator.getShareKey();
|
||||||
|
connectionMap.put(key, new SharedConnectionDefinition(activeConnection,
|
||||||
|
sharingProfile));
|
||||||
|
|
||||||
|
// Return credentials defining a single expected parameter
|
||||||
|
return new UserCredentials(SHARE_KEY,
|
||||||
|
Collections.singletonMap(SHARE_KEY_NAME, key));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a SharedConnectionUser (an implementation of AuthenticatedUser)
|
||||||
|
* if the given credentials contain a valid share key. The returned user
|
||||||
|
* will be associated with the single shared connection to which they have
|
||||||
|
* been granted temporary access. If the share key is invalid, or no share
|
||||||
|
* key is contained within the given credentials, null is returned.
|
||||||
|
*
|
||||||
|
* @param authProvider
|
||||||
|
* The AuthenticationProvider on behalf of which the user is being
|
||||||
|
* retrieved.
|
||||||
|
*
|
||||||
|
* @param credentials
|
||||||
|
* The credentials which are expected to contain the share key.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A SharedConnectionUser with access to a single shared connection, if
|
||||||
|
* the share key within the given credentials is valid, or null if the
|
||||||
|
* share key is invalid or absent.
|
||||||
|
*/
|
||||||
|
public SharedConnectionUser retrieveSharedConnectionUser(
|
||||||
|
AuthenticationProvider authProvider, Credentials credentials) {
|
||||||
|
|
||||||
|
// Pull associated HTTP request
|
||||||
|
HttpServletRequest request = credentials.getRequest();
|
||||||
|
if (request == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Retrieve the share key from the request
|
||||||
|
String shareKey = request.getParameter(ConnectionSharingService.SHARE_KEY_NAME);
|
||||||
|
if (shareKey == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Pull the connection definition describing the connection these
|
||||||
|
// credentials provide access to (if any)
|
||||||
|
SharedConnectionDefinition definition = connectionMap.get(shareKey);
|
||||||
|
if (definition == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Return temporary in-memory user with access only to the shared connection
|
||||||
|
return new SharedConnectionUser(authProvider, definition, credentials);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.guacamole.auth.jdbc.sharing;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.GuacamoleUnsupportedException;
|
||||||
|
import org.apache.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection;
|
||||||
|
import org.apache.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup;
|
||||||
|
import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
|
||||||
|
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||||
|
import org.apache.guacamole.net.auth.Connection;
|
||||||
|
import org.apache.guacamole.net.auth.ConnectionRecord;
|
||||||
|
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||||
|
import org.apache.guacamole.protocol.GuacamoleConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Connection which joins an active connection, limited by restrictions
|
||||||
|
* defined by a sharing profile.
|
||||||
|
*
|
||||||
|
* @author Michael Jumper
|
||||||
|
*/
|
||||||
|
public class SharedConnection implements Connection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Randomly-generated unique identifier, guaranteeing this shared connection
|
||||||
|
* does not duplicate the identifying information of the underlying
|
||||||
|
* connection being shared.
|
||||||
|
*/
|
||||||
|
private final String identifier = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user that successfully authenticated to obtain access to this
|
||||||
|
* SharedConnection.
|
||||||
|
*/
|
||||||
|
private SharedConnectionUser user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The active connection being shared.
|
||||||
|
*/
|
||||||
|
private TrackedActiveConnection activeConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sharing profile which dictates the level of access provided to a user
|
||||||
|
* of the shared connection.
|
||||||
|
*/
|
||||||
|
private ModeledSharingProfile sharingProfile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new SharedConnection which can be used to join the connection
|
||||||
|
* described by the given SharedConnectionDefinition.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user that successfully authenticated to obtain access to this
|
||||||
|
* SharedConnection.
|
||||||
|
*
|
||||||
|
* @param definition
|
||||||
|
* The SharedConnectionDefinition dictating the connection being shared
|
||||||
|
* and any associated restrictions.
|
||||||
|
*/
|
||||||
|
public void init(SharedConnectionUser user, SharedConnectionDefinition definition) {
|
||||||
|
this.user = user;
|
||||||
|
this.activeConnection = definition.getActiveConnection();
|
||||||
|
this.sharingProfile = definition.getSharingProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIdentifier(String identifier) {
|
||||||
|
throw new UnsupportedOperationException("Shared connections are immutable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return sharingProfile.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setName(String name) {
|
||||||
|
throw new UnsupportedOperationException("Shared connections are immutable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getParentIdentifier() {
|
||||||
|
return RootConnectionGroup.IDENTIFIER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setParentIdentifier(String parentIdentifier) {
|
||||||
|
throw new UnsupportedOperationException("Shared connections are immutable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GuacamoleConfiguration getConfiguration() {
|
||||||
|
GuacamoleConfiguration config = new GuacamoleConfiguration();
|
||||||
|
config.setProtocol(activeConnection.getConnection().getConfiguration().getProtocol());
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setConfiguration(GuacamoleConfiguration config) {
|
||||||
|
throw new UnsupportedOperationException("Shared connections are immutable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GuacamoleTunnel connect(GuacamoleClientInformation info)
|
||||||
|
throws GuacamoleException {
|
||||||
|
// STUB
|
||||||
|
throw new GuacamoleUnsupportedException("Connecting to shared connections is not yet implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getAttributes() {
|
||||||
|
return Collections.<String, String>emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAttributes(Map<String, String> attributes) {
|
||||||
|
// Do nothing - no attributes supported
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends ConnectionRecord> getHistory()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return Collections.<ConnectionRecord>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getSharingProfileIdentifiers()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return Collections.<String>emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getActiveConnections() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.guacamole.auth.jdbc.sharing;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
|
||||||
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A temporary user who has authenticated using a share key and thus has
|
||||||
|
* restricted access to a single shared connection.
|
||||||
|
*
|
||||||
|
* @author Michael Jumper
|
||||||
|
*/
|
||||||
|
public class SharedConnectionUser extends RemoteAuthenticatedUser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The single shared connection to which this user has access.
|
||||||
|
*/
|
||||||
|
private final SharedConnectionDefinition definition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An arbitrary identifier guaranteed to be unique across users. Note that
|
||||||
|
* because Guacamole users the AuthenticatedUser's identifier as the means
|
||||||
|
* of determining overall user identity and aggregating data across
|
||||||
|
* multiple extensions, this identifier MUST NOT match the identifier of
|
||||||
|
* any possibly existing user (or else the user may unexpectedly gain
|
||||||
|
* access to another identically-named user's data).
|
||||||
|
*/
|
||||||
|
private final String identifier = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new SharedConnectionUser with access solely to connection
|
||||||
|
* described by the given SharedConnectionDefinition.
|
||||||
|
*
|
||||||
|
* @param authenticationProvider
|
||||||
|
* The AuthenticationProvider that has authenticated the given user.
|
||||||
|
*
|
||||||
|
* @param definition
|
||||||
|
* The SharedConnectionDefinition describing the connection that this
|
||||||
|
* user should have access to, along with any associated restrictions.
|
||||||
|
*
|
||||||
|
* @param credentials
|
||||||
|
* The credentials given by the user when they authenticated.
|
||||||
|
*/
|
||||||
|
public SharedConnectionUser(AuthenticationProvider authenticationProvider,
|
||||||
|
SharedConnectionDefinition definition, Credentials credentials) {
|
||||||
|
super(authenticationProvider, credentials);
|
||||||
|
this.definition = definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIdentifier(String identifier) {
|
||||||
|
throw new UnsupportedOperationException("Shared connection users are immutable");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the SharedConnectionDefinition which describes the connection
|
||||||
|
* that this user should have access to, along with any associated
|
||||||
|
* restrictions.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The SharedConnectionDefinition describing the connection that this
|
||||||
|
* user should have access to, along with any associated restrictions.
|
||||||
|
*/
|
||||||
|
public SharedConnectionDefinition getSharedConnectionDefinition() {
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.guacamole.auth.jdbc.sharing;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.form.Form;
|
||||||
|
import org.apache.guacamole.net.auth.ActiveConnection;
|
||||||
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
|
import org.apache.guacamole.net.auth.Connection;
|
||||||
|
import org.apache.guacamole.net.auth.ConnectionGroup;
|
||||||
|
import org.apache.guacamole.net.auth.ConnectionRecordSet;
|
||||||
|
import org.apache.guacamole.net.auth.Directory;
|
||||||
|
import org.apache.guacamole.net.auth.SharingProfile;
|
||||||
|
import org.apache.guacamole.net.auth.User;
|
||||||
|
import org.apache.guacamole.net.auth.UserContext;
|
||||||
|
import org.apache.guacamole.net.auth.simple.SimpleConnectionDirectory;
|
||||||
|
import org.apache.guacamole.net.auth.simple.SimpleConnectionGroup;
|
||||||
|
import org.apache.guacamole.net.auth.simple.SimpleConnectionGroupDirectory;
|
||||||
|
import org.apache.guacamole.net.auth.simple.SimpleConnectionRecordSet;
|
||||||
|
import org.apache.guacamole.net.auth.simple.SimpleDirectory;
|
||||||
|
import org.apache.guacamole.net.auth.simple.SimpleUser;
|
||||||
|
import org.apache.guacamole.net.auth.simple.SimpleUserDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user context of a SharedConnectionUser, providing access ONLY to the
|
||||||
|
* user themselves, the single SharedConnection associated with that user, and
|
||||||
|
* an internal root connection group containing only that single
|
||||||
|
* SharedConnection.
|
||||||
|
*
|
||||||
|
* @author Michael Jumper
|
||||||
|
*/
|
||||||
|
public class SharedConnectionUserContext implements UserContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for retrieving SharedConnection instances.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private Provider<SharedConnection> connectionProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AuthenticationProvider that created this SharedConnectionUserContext.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private AuthenticationProvider authProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user whose level of access is represented by this user context.
|
||||||
|
*/
|
||||||
|
private User self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A directory of all connections visible to the user for whom this user
|
||||||
|
* context was created.
|
||||||
|
*/
|
||||||
|
private Directory<Connection> connectionDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A directory of all connection groups visible to the user for whom this
|
||||||
|
* user context was created.
|
||||||
|
*/
|
||||||
|
private Directory<ConnectionGroup> connectionGroupDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A directory of all users visible to the user for whom this user context
|
||||||
|
* was created.
|
||||||
|
*/
|
||||||
|
private Directory<User> userDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The root connection group of the hierarchy containing all connections
|
||||||
|
* and connection groups visible to the user for whom this user context was
|
||||||
|
* created.
|
||||||
|
*/
|
||||||
|
private ConnectionGroup rootGroup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new SharedConnectionUserContext which provides access ONLY to
|
||||||
|
* the given user, the single SharedConnection associated with that user,
|
||||||
|
* and an internal root connection group containing only that single
|
||||||
|
* SharedConnection.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The SharedConnectionUser for whom this SharedConnectionUserContext
|
||||||
|
* is being created.
|
||||||
|
*/
|
||||||
|
public void init(SharedConnectionUser user) {
|
||||||
|
|
||||||
|
// Get the definition of the shared connection
|
||||||
|
SharedConnectionDefinition definition =
|
||||||
|
user.getSharedConnectionDefinition();
|
||||||
|
|
||||||
|
// Create a single shared connection accessible by the user
|
||||||
|
SharedConnection connection = connectionProvider.get();
|
||||||
|
connection.init(user, definition);
|
||||||
|
|
||||||
|
// Build list of all accessible connection identifiers
|
||||||
|
Collection<String> connectionIdentifiers =
|
||||||
|
Collections.singletonList(connection.getIdentifier());
|
||||||
|
|
||||||
|
// The connection directory should contain only the shared connection
|
||||||
|
this.connectionDirectory = new SimpleConnectionDirectory(
|
||||||
|
Collections.<Connection>singletonList(connection));
|
||||||
|
|
||||||
|
// The user should have access only to the shared connection and himself
|
||||||
|
this.self = new SimpleUser(user.getIdentifier(),
|
||||||
|
Collections.<String>singletonList(user.getIdentifier()),
|
||||||
|
connectionIdentifiers,
|
||||||
|
Collections.<String>emptyList());
|
||||||
|
|
||||||
|
// The root group contains only the shared connection
|
||||||
|
String rootIdentifier = connection.getParentIdentifier();
|
||||||
|
this.rootGroup = new SimpleConnectionGroup(rootIdentifier, rootIdentifier,
|
||||||
|
connectionIdentifiers, Collections.<String>emptyList());
|
||||||
|
|
||||||
|
// The connection group directory contains only the root group
|
||||||
|
this.connectionGroupDirectory = new SimpleConnectionGroupDirectory(
|
||||||
|
Collections.singletonList(this.rootGroup));
|
||||||
|
|
||||||
|
// The user directory contains only this user
|
||||||
|
this.userDirectory = new SimpleUserDirectory(this.self);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User self() {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticationProvider getAuthenticationProvider() {
|
||||||
|
return authProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Directory<User> getUserDirectory() {
|
||||||
|
return userDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Directory<Connection> getConnectionDirectory()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return connectionDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Directory<ConnectionGroup> getConnectionGroupDirectory() {
|
||||||
|
return connectionGroupDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Directory<ActiveConnection> getActiveConnectionDirectory()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return new SimpleDirectory<ActiveConnection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Directory<SharingProfile> getSharingProfileDirectory()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return new SimpleDirectory<SharingProfile>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConnectionRecordSet getConnectionHistory() {
|
||||||
|
return new SimpleConnectionRecordSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConnectionGroup getRootConnectionGroup() {
|
||||||
|
return rootGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Form> getUserAttributes() {
|
||||||
|
return Collections.<Form>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Form> getConnectionAttributes() {
|
||||||
|
return Collections.<Form>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Form> getConnectionGroupAttributes() {
|
||||||
|
return Collections.<Form>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Form> getSharingProfileAttributes() {
|
||||||
|
return Collections.<Form>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -22,6 +22,10 @@ package org.apache.guacamole.auth.jdbc.user;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService;
|
||||||
|
import org.apache.guacamole.auth.jdbc.sharing.SharedConnectionUser;
|
||||||
|
import org.apache.guacamole.auth.jdbc.sharing.SharedConnectionUserContext;
|
||||||
|
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
import org.apache.guacamole.net.auth.Credentials;
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||||
@@ -48,6 +52,18 @@ public class AuthenticationProviderService {
|
|||||||
@Inject
|
@Inject
|
||||||
private Provider<UserContext> userContextProvider;
|
private Provider<UserContext> userContextProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for retrieving SharedConnectionUserContext instances.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private Provider<SharedConnectionUserContext> sharedUserContextProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for sharing active connections.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private ConnectionSharingService sharingService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates the user having the given credentials, returning a new
|
* Authenticates the user having the given credentials, returning a new
|
||||||
* AuthenticatedUser instance only if the credentials are valid. If the
|
* AuthenticatedUser instance only if the credentials are valid. If the
|
||||||
@@ -72,8 +88,15 @@ public class AuthenticationProviderService {
|
|||||||
public AuthenticatedUser authenticateUser(AuthenticationProvider authenticationProvider,
|
public AuthenticatedUser authenticateUser(AuthenticationProvider authenticationProvider,
|
||||||
Credentials credentials) throws GuacamoleException {
|
Credentials credentials) throws GuacamoleException {
|
||||||
|
|
||||||
|
AuthenticatedUser user;
|
||||||
|
|
||||||
|
// Check whether user is authenticating with a valid sharing key
|
||||||
|
user = sharingService.retrieveSharedConnectionUser(authenticationProvider, credentials);
|
||||||
|
if (user != null)
|
||||||
|
return user;
|
||||||
|
|
||||||
// Authenticate user
|
// Authenticate user
|
||||||
AuthenticatedUser user = userService.retrieveAuthenticatedUser(authenticationProvider, credentials);
|
user = userService.retrieveAuthenticatedUser(authenticationProvider, credentials);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
return user;
|
return user;
|
||||||
|
|
||||||
@@ -98,8 +121,15 @@ public class AuthenticationProviderService {
|
|||||||
* If an error occurs during authentication, or if the given
|
* If an error occurs during authentication, or if the given
|
||||||
* credentials are invalid or expired.
|
* credentials are invalid or expired.
|
||||||
*/
|
*/
|
||||||
public UserContext getUserContext(org.apache.guacamole.net.auth.AuthenticatedUser authenticatedUser)
|
public org.apache.guacamole.net.auth.UserContext getUserContext(
|
||||||
throws GuacamoleException {
|
AuthenticatedUser authenticatedUser) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Produce sharing-specific user context if this is the user of a shared connection
|
||||||
|
if (authenticatedUser instanceof SharedConnectionUser) {
|
||||||
|
SharedConnectionUserContext context = sharedUserContextProvider.get();
|
||||||
|
context.init((SharedConnectionUser) authenticatedUser);
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve user account for already-authenticated user
|
// Retrieve user account for already-authenticated user
|
||||||
ModeledUser user = userService.retrieveUser(authenticatedUser);
|
ModeledUser user = userService.retrieveUser(authenticatedUser);
|
||||||
|
Reference in New Issue
Block a user