GUACAMOLE-5: Merge sharing profile API changes.

This commit is contained in:
James Muehlner
2016-07-17 15:27:00 -07:00
53 changed files with 2517 additions and 44 deletions

View File

@@ -20,11 +20,14 @@
package org.apache.guacamole.auth.jdbc.activeconnection; package org.apache.guacamole.auth.jdbc.activeconnection;
import java.util.Date; import java.util.Date;
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.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;
import org.apache.guacamole.net.auth.ActiveConnection; import org.apache.guacamole.net.auth.ActiveConnection;
import org.apache.guacamole.net.auth.credentials.UserCredentials;
/** /**
* An implementation of the ActiveConnection object which has an associated * An implementation of the ActiveConnection object which has an associated
@@ -44,6 +47,11 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
*/ */
private String connectionIdentifier; private String connectionIdentifier;
/**
* The identifier of the associated sharing profile.
*/
private String sharingProfileIdentifier;
/** /**
* The date and time this active connection began. * The date and time this active connection began.
*/ */
@@ -90,9 +98,10 @@ 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.getConnection().getIdentifier(); this.connectionIdentifier = activeConnectionRecord.getConnectionIdentifier();
this.identifier = activeConnectionRecord.getUUID().toString(); this.sharingProfileIdentifier = activeConnectionRecord.getSharingProfileIdentifier();
this.startDate = activeConnectionRecord.getStartDate(); this.identifier = activeConnectionRecord.getUUID().toString();
this.startDate = activeConnectionRecord.getStartDate();
// Include sensitive data, too, if requested // Include sensitive data, too, if requested
if (includeSensitiveInformation) { if (includeSensitiveInformation) {
@@ -123,6 +132,22 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
this.connectionIdentifier = connnectionIdentifier; this.connectionIdentifier = connnectionIdentifier;
} }
@Override
public String getSharingProfileIdentifier() {
return sharingProfileIdentifier;
}
@Override
public void setSharingProfileIdentifier(String sharingProfileIdentifier) {
this.sharingProfileIdentifier = sharingProfileIdentifier;
}
@Override
public UserCredentials getSharingCredentials(String identifier)
throws GuacamoleException {
throw new GuacamoleSecurityException("Permission denied");
}
@Override @Override
public Date getStartDate() { public Date getStartDate() {
return startDate; return startDate;

View File

@@ -27,6 +27,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment; import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
@@ -156,6 +157,12 @@ public class ModeledConnection extends ModeledGroupedDirectoryObject<ConnectionM
} }
@Override
public Set<String> getSharingProfileIdentifiers()
throws GuacamoleException {
return Collections.<String>emptySet();
}
@Override @Override
public List<? extends ConnectionRecord> getHistory() throws GuacamoleException { public List<? extends ConnectionRecord> getHistory() throws GuacamoleException {
return connectionService.retrieveHistory(getCurrentUser(), this); return connectionService.retrieveHistory(getCurrentUser(), this);

View File

@@ -58,6 +58,16 @@ public class ModeledConnectionRecord implements ConnectionRecord {
return model.getConnectionName(); return model.getConnectionName();
} }
@Override
public String getSharingProfileIdentifier() {
return null;
}
@Override
public String getSharingProfileName() {
return null;
}
@Override @Override
public Date getStartDate() { public Date getStartDate() {
return model.getStartDate(); return model.getStartDate();

View File

@@ -171,6 +171,16 @@ public class ActiveConnectionRecord implements ConnectionRecord {
return connection.getName(); return connection.getName();
} }
@Override
public String getSharingProfileIdentifier() {
return null;
}
@Override
public String getSharingProfileName() {
return null;
}
@Override @Override
public Date getStartDate() { public Date getStartDate() {
return startDate; return startDate;

View File

@@ -49,6 +49,7 @@ import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermission; import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet; import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -251,6 +252,12 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this); return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this);
} }
@Override
public ObjectPermissionSet getSharingProfilePermissions()
throws GuacamoleException {
return new SimpleObjectPermissionSet();
}
@Override @Override
public ObjectPermissionSet getActiveConnectionPermissions() public ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException { throws GuacamoleException {

View File

@@ -26,6 +26,7 @@ import org.apache.guacamole.auth.jdbc.connection.ConnectionDirectory;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.RestrictedObject; import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionDirectory; import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionDirectory;
@@ -38,7 +39,9 @@ import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.Directory; 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.User;
import org.apache.guacamole.net.auth.simple.SimpleDirectory;
/** /**
* UserContext implementation which is driven by an arbitrary, underlying * UserContext implementation which is driven by an arbitrary, underlying
@@ -134,6 +137,12 @@ public class UserContext extends RestrictedObject
return connectionGroupDirectory; return connectionGroupDirectory;
} }
@Override
public Directory<SharingProfile> getSharingProfileDirectory()
throws GuacamoleException {
return new SimpleDirectory<SharingProfile>();
}
@Override @Override
public Directory<ActiveConnection> getActiveConnectionDirectory() public Directory<ActiveConnection> getActiveConnectionDirectory()
throws GuacamoleException { throws GuacamoleException {
@@ -173,4 +182,9 @@ public class UserContext extends RestrictedObject
return ModeledConnectionGroup.ATTRIBUTES; return ModeledConnectionGroup.ATTRIBUTES;
} }
@Override
public Collection<Form> getSharingProfileAttributes() {
return Collections.<Form>emptyList();
}
} }

View File

@@ -34,6 +34,7 @@ import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.ConnectionRecordSet; import org.apache.guacamole.net.auth.ConnectionRecordSet;
import org.apache.guacamole.net.auth.Directory; 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.User;
import org.apache.guacamole.net.auth.simple.SimpleConnectionGroup; import org.apache.guacamole.net.auth.simple.SimpleConnectionGroup;
import org.apache.guacamole.net.auth.simple.SimpleConnectionGroupDirectory; import org.apache.guacamole.net.auth.simple.SimpleConnectionGroupDirectory;
@@ -193,6 +194,12 @@ public class UserContext implements org.apache.guacamole.net.auth.UserContext {
return new SimpleDirectory<ActiveConnection>(); return new SimpleDirectory<ActiveConnection>();
} }
@Override
public Directory<SharingProfile> getSharingProfileDirectory()
throws GuacamoleException {
return new SimpleDirectory<SharingProfile>();
}
@Override @Override
public ConnectionRecordSet getConnectionHistory() public ConnectionRecordSet getConnectionHistory()
throws GuacamoleException { throws GuacamoleException {
@@ -214,4 +221,9 @@ public class UserContext implements org.apache.guacamole.net.auth.UserContext {
return Collections.<Form>emptyList(); return Collections.<Form>emptyList();
} }
@Override
public Collection<Form> getSharingProfileAttributes() {
return Collections.<Form>emptyList();
}
} }

View File

@@ -99,6 +99,12 @@ public class Field {
*/ */
public static String TIME = "TIME"; public static String TIME = "TIME";
/**
* An HTTP query parameter which is expected to be embedded in the URL
* given to a user.
*/
public static String QUERY_PARAMETER = "QUERY_PARAMETER";
} }
/** /**

View File

@@ -36,6 +36,11 @@ public abstract class AbstractActiveConnection extends AbstractIdentifiable
*/ */
private String connectionIdentifier; private String connectionIdentifier;
/**
* The identifier of the associated sharing profile.
*/
private String sharingProfileIdentifier;
/** /**
* The date and time this active connection began. * The date and time this active connection began.
*/ */
@@ -66,6 +71,16 @@ public abstract class AbstractActiveConnection extends AbstractIdentifiable
this.connectionIdentifier = connnectionIdentifier; this.connectionIdentifier = connnectionIdentifier;
} }
@Override
public String getSharingProfileIdentifier() {
return sharingProfileIdentifier;
}
@Override
public void setSharingProfileIdentifier(String sharingProfileIdentifier) {
this.sharingProfileIdentifier = sharingProfileIdentifier;
}
@Override @Override
public Date getStartDate() { public Date getStartDate() {
return startDate; return startDate;

View File

@@ -19,6 +19,9 @@
package org.apache.guacamole.net.auth; package org.apache.guacamole.net.auth;
import java.util.Collections;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.protocol.GuacamoleConfiguration; import org.apache.guacamole.protocol.GuacamoleConfiguration;
/** /**
@@ -76,4 +79,10 @@ public abstract class AbstractConnection extends AbstractIdentifiable
this.configuration = configuration; this.configuration = configuration;
} }
@Override
public Set<String> getSharingProfileIdentifiers()
throws GuacamoleException {
return Collections.<String>emptySet();
}
} }

View File

@@ -0,0 +1,119 @@
/*
* 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.net.auth;
import java.util.HashMap;
import java.util.Map;
/**
* Base implementation of a sharing profile which can be used to share a
* Guacamole connection.
*
* @author Michael Jumper
*/
public abstract class AbstractSharingProfile implements SharingProfile {
/**
* The human-readable name of this sharing profile.
*/
private String name;
/**
* The unique identifier associated with this sharing profile.
*/
private String identifier;
/**
* The identifier of the primary connection that this sharing profile can
* be used to share.
*/
private String primaryConnectionIdentifier;
/**
* All connection parameters with this sharing profile.
*/
private final Map<String, String> parameters = new HashMap<String, String>();
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getIdentifier() {
return identifier;
}
@Override
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
@Override
public String getPrimaryConnectionIdentifier() {
return primaryConnectionIdentifier;
}
@Override
public void setPrimaryConnectionIdentifier(String primaryConnectionIdentifier) {
this.primaryConnectionIdentifier = primaryConnectionIdentifier;
}
@Override
public Map<String, String> getParameters() {
return parameters;
}
@Override
public void setParameters(Map<String, String> parameters) {
this.parameters.clear();
this.parameters.putAll(parameters);
}
@Override
public int hashCode() {
if (identifier == null) return 0;
return identifier.hashCode();
}
@Override
public boolean equals(Object obj) {
// Not equal if null or not an SharingProfile
if (obj == null) return false;
if (!(obj instanceof AbstractSharingProfile)) return false;
// Get identifier
String objIdentifier = ((AbstractSharingProfile) obj).identifier;
// If null, equal only if this identifier is null
if (objIdentifier == null) return identifier == null;
// Otherwise, equal only if strings are identical
return objIdentifier.equals(identifier);
}
}

View File

@@ -28,7 +28,7 @@ import org.apache.guacamole.net.GuacamoleTunnel;
* *
* @author Michael Jumper * @author Michael Jumper
*/ */
public interface ActiveConnection extends Identifiable { public interface ActiveConnection extends Identifiable, Shareable<SharingProfile> {
/** /**
* Returns the identifier of the connection being actively used. Unlike the * Returns the identifier of the connection being actively used. Unlike the
@@ -47,7 +47,24 @@ public interface ActiveConnection extends Identifiable {
* The identifier of the connection being actively used. * The identifier of the connection being actively used.
*/ */
void setConnectionIdentifier(String connnectionIdentifier); void setConnectionIdentifier(String connnectionIdentifier);
/**
* Returns the identifier of the sharing profile being actively used. If
* the connection is being accessed directly, this will be null.
*
* @return
* The identifier of the sharing profile being actively used.
*/
String getSharingProfileIdentifier();
/**
* Sets the identifier of the sharing profile being actively used.
*
* @param sharingProfileIdentifier
* The identifier of the sharing profile being actively used.
*/
void setSharingProfileIdentifier(String sharingProfileIdentifier);
/** /**
* Returns the date and time the connection began. * Returns the date and time the connection began.
* *

View File

@@ -21,6 +21,7 @@ package org.apache.guacamole.net.auth;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.protocol.GuacamoleConfiguration; import org.apache.guacamole.protocol.GuacamoleConfiguration;
@@ -119,4 +120,21 @@ public interface Connection extends Identifiable, Connectable {
*/ */
public List<? extends ConnectionRecord> getHistory() throws GuacamoleException; public List<? extends ConnectionRecord> getHistory() throws GuacamoleException;
/**
* Returns identifiers of all readable sharing profiles that can be used to
* join this connection when it is active. The level of access granted to a
* joining user is dictated by the connection parameters associated with
* the sharing profile, not necessarily the parameters of the primary
* connection being joined.
*
* @return
* A Set of identifiers representing the sharing profiles for this
* connection.
*
* @throws GuacamoleException
* If an error occurs while fetching the sharing profiles for this
* connection.
*/
public Set<String> getSharingProfileIdentifiers() throws GuacamoleException;
} }

View File

@@ -48,6 +48,32 @@ public interface ConnectionRecord {
*/ */
public String getConnectionName(); public String getConnectionName();
/**
* Returns the identifier of the sharing profile that was used to access the
* connection associated with this connection record. If the connection was
* accessed directly (without involving a sharing profile), this will be
* null.
*
* @return
* The identifier of the sharing profile used to access the connection
* associated with this connection record, or null if the connection
* was accessed directly.
*/
public String getSharingProfileIdentifier();
/**
* Returns the name of the sharing profile that was used to access the
* connection associated with this connection record. If the connection was
* accessed directly (without involving a sharing profile), this will be
* null.
*
* @return
* The name of the sharing profile used to access the connection
* associated with this connection record, or null if the connection
* was accessed directly.
*/
public String getSharingProfileName();
/** /**
* Returns the date and time the connection began. * Returns the date and time the connection began.
* *

View File

@@ -0,0 +1,63 @@
/*
* 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.net.auth;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.credentials.UserCredentials;
/**
* An object which can be shared with others via specially-generated sets of
* credentials. It is expected, but not required, that these credentials are
* temporary.
*
* @param <T>
* The type of object which dictates the semantics/restrictions of shared
* objects.
*
* @author Michael Jumper
*/
public interface Shareable<T> {
/**
* Returns a full set of credentials which can be used to authenticate as a
* user with access strictly to this object. The semantics and restrictions
* of the shared object (when accessed using the returned sharing
* credentials) are defined by the {@link T} associated with the given
* identifier and within the
* {@link Directory}&lt;{@link T}&gt; of the same {@link UserContext} that
* this Shareable was retrieved from.
*
* @param identifier
* The identifier of a {@link T} within the
* {@link Directory}&lt;{@link T}&gt; of the same {@link UserContext}
* that this Shareable was retrieved from.
*
* @return
* A full set of credentials which can be used to authenticate and
* obtain access to this object.
*
* @throws GuacamoleException
* If credentials could not be generated, or permission to share this
* object is denied.
*/
public UserCredentials getSharingCredentials(String identifier)
throws GuacamoleException;
}

View File

@@ -0,0 +1,119 @@
/*
* 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.net.auth;
import java.util.Map;
/**
* Represents the semantics which apply to an existing connection when shared,
* along with a human-readable name and unique identifier.
*
* @author Michael Jumper
*/
public interface SharingProfile extends Identifiable {
/**
* Returns the human-readable name assigned to this SharingProfile.
*
* @return
* The name assigned to this SharingProfile.
*/
public String getName();
/**
* Sets the human-readable name assigned to this SharingProfile.
*
* @param name
* The name to assign.
*/
public void setName(String name);
/**
* Returns the identifier of the primary connection associated with this
* connection. The primary connection is the connection that this sharing
* profile can be used to share.
*
* @return
* The identifier of the primary connection associated with this
* connection.
*/
public String getPrimaryConnectionIdentifier();
/**
* Sets the identifier of the primary connection associated with this
* connection. The primary connection is the connection that this sharing
* profile can be used to share.
*
* @param identifier
* The identifier of the primary connection associated with this
* connection.
*/
public void setPrimaryConnectionIdentifier(String identifier);
/**
* Returns a map which contains connection parameter name/value pairs as
* key/value pairs. Changes to this map will affect the parameters stored
* within this sharing profile. The differences in these parameters compared
* to those of the associated primary connection yield different levels of
* access to users joining the primary connection via this sharing profile.
* Note that because configurations may contain sensitive information, some
* data in this map may be omitted or tokenized.
*
* @return
* A map which contains all connection parameter name/value pairs as
* key/value pairs.
*/
public Map<String, String> getParameters();
/**
* Replaces all current parameters with the parameters defined within the
* given map. Key/value pairs within the map represent parameter name/value
* pairs. The differences in these parameters compared to those of the
* associated primary connection yield different levels of access to users
* joining the primary connection via this sharing profile.
*
* @param parameters
* A map which contains all connection parameter name/value pairs as
* key/value pairs.
*/
public void setParameters(Map<String, String> parameters);
/**
* Returns all attributes associated with this sharing profile. The returned
* map may not be modifiable.
*
* @return
* A map of all attribute identifiers to their corresponding values,
* for all attributes associated with this sharing profile, which may
* not be modifiable.
*/
Map<String, String> getAttributes();
/**
* Sets the given attributes. If an attribute within the map is not
* supported, it will simply be dropped. Any attributes not within the
* given map will be left untouched.
*
* @param attributes
* A map of all attribute identifiers to their corresponding values.
*/
void setAttributes(Map<String, String> attributes);
}

View File

@@ -111,6 +111,20 @@ public interface User extends Identifiable {
ObjectPermissionSet getConnectionGroupPermissions() ObjectPermissionSet getConnectionGroupPermissions()
throws GuacamoleException; throws GuacamoleException;
/**
* Returns all sharing profile permissions given to this user.
*
* @return
* An ObjectPermissionSet of all sharing profile permissions granted to
* this user.
*
* @throws GuacamoleException
* If an error occurs while retrieving permissions, or if reading all
* permissions is not allowed.
*/
ObjectPermissionSet getSharingProfilePermissions()
throws GuacamoleException;
/** /**
* Returns all permissions given to this user regarding currently-active * Returns all permissions given to this user regarding currently-active
* connections. * connections.

View File

@@ -106,6 +106,21 @@ public interface UserContext {
Directory<ActiveConnection> getActiveConnectionDirectory() Directory<ActiveConnection> getActiveConnectionDirectory()
throws GuacamoleException; throws GuacamoleException;
/**
* Retrieves a Directory which can be used to view and manipulate
* sharing profiles and their configurations, but only as allowed by the
* permissions given to the user.
*
* @return
* A Directory whose operations are bound by the permissions of the
* user.
*
* @throws GuacamoleException
* If an error occurs while creating the Directory.
*/
Directory<SharingProfile> getSharingProfileDirectory()
throws GuacamoleException;
/** /**
* Retrieves all connection records visible to current user. The resulting * Retrieves all connection records visible to current user. The resulting
* set of connection records can be further filtered and ordered using the * set of connection records can be further filtered and ordered using the
@@ -165,4 +180,15 @@ public interface UserContext {
*/ */
Collection<Form> getConnectionGroupAttributes(); Collection<Form> getConnectionGroupAttributes();
/**
* Retrieves a collection of all attributes applicable to sharing profiles.
* This collection will contain only those attributes which the current user
* has general permission to view or modify. If there are no such
* attributes, this collection will be empty.
*
* @return
* A collection of all attributes applicable to sharing profile.
*/
Collection<Form> getSharingProfileAttributes();
} }

View File

@@ -0,0 +1,220 @@
/*
* 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.net.auth.credentials;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.guacamole.form.Field;
/**
* A fully-valid set of credentials and associated values. Each instance of
* this object should describe a full set of parameter name/value pairs which
* can be used to authenticate successfully, even if that success depends on
* factors not described by this object.
*
* @author Michael Jumper
*/
public class UserCredentials extends CredentialsInfo {
/**
* All fields required for valid credentials.
*/
private Map<String, String> values;
/**
* Creates a new UserCredentials object which requires the given fields and
* values.
*
* @param fields
* The fields to require.
*
* @param values
* The values required for each field, as a map of field name to
* correct value.
*/
public UserCredentials(Collection<Field> fields, Map<String, String> values) {
super(fields);
this.values = values;
}
/**
* Creates a new UserCredentials object which requires fields described by
* the given CredentialsInfo. The value required for each field in the
* CredentialsInfo is defined in the given Map.
*
* @param info
* The CredentialsInfo object describing the fields to require.
*
* @param values
* The values required for each field, as a map of field name to
* correct value.
*/
public UserCredentials(CredentialsInfo info, Map<String, String> values) {
this(info.getFields(), values);
}
/**
* Creates a new UserCredentials object which requires fields described by
* the given CredentialsInfo but does not yet have any defined values.
*
* @param info
* The CredentialsInfo object describing the fields to require.
*/
public UserCredentials(CredentialsInfo info) {
this(info, new HashMap<String, String>());
}
/**
* Creates a new UserCredentials object which requires the given fields but
* does not yet have any defined values.
*
* @param fields
* The fields to require.
*/
public UserCredentials(Collection<Field> fields) {
this(fields, new HashMap<String, String>());
}
/**
* Returns a map of field names to values which backs this UserCredentials
* object. Modifications to the returned map will directly affect the
* associated name/value pairs.
*
* @return
* A map of field names to their corresponding values which backs this
* UserCredentials object.
*/
public Map<String, String> getValues() {
return values;
}
/**
* Replaces the map backing this UserCredentials object with the given map.
* All field name/value pairs described by the original map are replaced by
* the name/value pairs in the given map.
*
* @param values
* The map of field names to their corresponding values which should be
* used to back this UserCredentials object.
*/
public void setValues(Map<String, String> values) {
this.values = values;
}
/**
* Returns the value defined by this UserCrendentials object for the field
* having the given name.
*
* @param name
* The name of the field whose value should be returned.
*
* @return
* The value of the field having the given name, or null if no value is
* defined for that field.
*/
public String getValue(String name) {
return values.get(name);
}
/**
* Returns the value defined by this UserCrendentials object for the given
* field.
*
* @param field
* The field whose value should be returned.
*
* @return
* The value of the given field, or null if no value is defined for
* that field.
*/
public String getValue(Field field) {
return getValue(field.getName());
}
/**
* Sets the value of the field having the given name. Any existing value
* for that field is replaced.
*
* @param name
* The name of the field whose value should be assigned.
*
* @param value
* The value to assign to the field having the given name.
*
* @return
* The previous value of the field, or null if the value of the field
* was not previously defined.
*/
public String setValue(String name, String value) {
return values.put(name, value);
}
/**
* Sets the value of the given field. Any existing value for that field is
* replaced.
*
* @param field
* The field whose value should be assigned.
*
* @param value
* The value to assign to the given field.
*
* @return
* The previous value of the field, or null if the value of the field
* was not previously defined.
*/
public String setValue(Field field, String value) {
return setValue(field.getName(), value);
}
/**
* Removes (undefines) the value of the field having the given name,
* returning its previous value. If the field value was not defined, this
* function has no effect, and null is returned.
*
* @param name
* The name of the field whose value should be removed.
*
* @return
* The previous value of the field, or null if the value of the field
* was not previously defined.
*/
public String removeValue(String name) {
return values.remove(name);
}
/**
* Removes (undefines) the value of the given field returning its previous
* value. If the field value was not defined, this function has no effect,
* and null is returned.
*
* @param field
* The field whose value should be removed.
*
* @return
* The previous value of the field, or null if the value of the field
* was not previously defined.
*/
public String removeValue(Field field) {
return removeValue(field.getName());
}
}

View File

@@ -49,6 +49,11 @@ public class SystemPermission implements Permission<SystemPermission.Type> {
*/ */
CREATE_CONNECTION_GROUP, CREATE_CONNECTION_GROUP,
/**
* Create sharing profiles.
*/
CREATE_SHARING_PROFILE,
/** /**
* Administer the system in general, including adding permissions * Administer the system in general, including adding permissions
* which affect the system (like user creation, connection creation, * which affect the system (like user creation, connection creation,

View File

@@ -195,4 +195,9 @@ public class SimpleUser extends AbstractUser {
return new SimpleObjectPermissionSet(); return new SimpleObjectPermissionSet();
} }
@Override
public ObjectPermissionSet getSharingProfilePermissions() {
return new SimpleObjectPermissionSet();
}
} }

View File

@@ -32,6 +32,7 @@ import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.ConnectionRecordSet; import org.apache.guacamole.net.auth.ConnectionRecordSet;
import org.apache.guacamole.net.auth.Directory; 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.User;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.protocol.GuacamoleConfiguration; import org.apache.guacamole.protocol.GuacamoleConfiguration;
@@ -192,6 +193,12 @@ public class SimpleUserContext implements UserContext {
return rootGroup; return rootGroup;
} }
@Override
public Directory<SharingProfile> getSharingProfileDirectory()
throws GuacamoleException {
return new SimpleDirectory<SharingProfile>();
}
@Override @Override
public Directory<ActiveConnection> getActiveConnectionDirectory() public Directory<ActiveConnection> getActiveConnectionDirectory()
throws GuacamoleException { throws GuacamoleException {
@@ -219,4 +226,9 @@ public class SimpleUserContext implements UserContext {
return Collections.<Form>emptyList(); return Collections.<Form>emptyList();
} }
@Override
public Collection<Form> getSharingProfileAttributes() {
return Collections.<Form>emptyList();
}
} }

View File

@@ -28,7 +28,7 @@ import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.net.auth.AuthenticatedUser; 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.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.tunnel.StreamInterceptingTunnel; import org.apache.guacamole.tunnel.UserTunnel;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -59,8 +59,8 @@ public class GuacamoleSession {
/** /**
* All currently-active tunnels, indexed by tunnel UUID. * All currently-active tunnels, indexed by tunnel UUID.
*/ */
private final Map<String, StreamInterceptingTunnel> tunnels = private final Map<String, UserTunnel> tunnels =
new ConcurrentHashMap<String, StreamInterceptingTunnel>(); new ConcurrentHashMap<String, UserTunnel>();
/** /**
* The last time this session was accessed. * The last time this session was accessed.
@@ -196,7 +196,7 @@ public class GuacamoleSession {
* *
* @return A map of all active tunnels associated with this session. * @return A map of all active tunnels associated with this session.
*/ */
public Map<String, StreamInterceptingTunnel> getTunnels() { public Map<String, UserTunnel> getTunnels() {
return tunnels; return tunnels;
} }
@@ -206,7 +206,7 @@ public class GuacamoleSession {
* *
* @param tunnel The tunnel to associate with this session. * @param tunnel The tunnel to associate with this session.
*/ */
public void addTunnel(StreamInterceptingTunnel tunnel) { public void addTunnel(UserTunnel tunnel) {
tunnels.put(tunnel.getUUID().toString(), tunnel); tunnels.put(tunnel.getUUID().toString(), tunnel);
} }

View File

@@ -39,6 +39,9 @@ import org.apache.guacamole.rest.connectiongroup.ConnectionGroupModule;
import org.apache.guacamole.rest.language.LanguageRESTService; import org.apache.guacamole.rest.language.LanguageRESTService;
import org.apache.guacamole.rest.patch.PatchRESTService; import org.apache.guacamole.rest.patch.PatchRESTService;
import org.apache.guacamole.rest.session.SessionResourceFactory; import org.apache.guacamole.rest.session.SessionResourceFactory;
import org.apache.guacamole.rest.sharingprofile.SharingProfileModule;
import org.apache.guacamole.rest.tunnel.TunnelCollectionResourceFactory;
import org.apache.guacamole.rest.tunnel.TunnelResourceFactory;
import org.apache.guacamole.rest.user.UserModule; import org.apache.guacamole.rest.user.UserModule;
/** /**
@@ -90,12 +93,15 @@ public class RESTServiceModule extends ServletModule {
// Root-level resources // Root-level resources
bind(SessionRESTService.class); bind(SessionRESTService.class);
install(new FactoryModuleBuilder().build(SessionResourceFactory.class)); install(new FactoryModuleBuilder().build(SessionResourceFactory.class));
install(new FactoryModuleBuilder().build(TunnelCollectionResourceFactory.class));
install(new FactoryModuleBuilder().build(TunnelResourceFactory.class));
install(new FactoryModuleBuilder().build(UserContextResourceFactory.class)); install(new FactoryModuleBuilder().build(UserContextResourceFactory.class));
// Resources below root // Resources below root
install(new ActiveConnectionModule()); install(new ActiveConnectionModule());
install(new ConnectionModule()); install(new ConnectionModule());
install(new ConnectionGroupModule()); install(new ConnectionGroupModule());
install(new SharingProfileModule());
install(new UserModule()); install(new UserModule());
// Set up the servlet and JSON mappings // Set up the servlet and JSON mappings

View File

@@ -0,0 +1,82 @@
/*
* 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.rest.activeconnection;
import java.util.Collection;
import java.util.Map;
import org.apache.guacamole.form.Field;
import org.apache.guacamole.net.auth.credentials.UserCredentials;
/**
* The object returned by REST API calls to define a full set of valid
* credentials, including field definitions and corresponding expected
* values.
*
* @author Michael Jumper
*/
public class APIUserCredentials {
/**
* All expected request parameters, if any, as a collection of fields.
*/
private final Collection<Field> expected;
/**
* A map of all field values by field name.
*/
private final Map<String, String> values;
/**
* Creates a new APIUserCredentials object whose required parameters and
* corresponding values are defined by the given UserCredentials.
*
* @param userCredentials
* The UserCredentials which defines the parameters and corresponding
* values of this APIUserCredentials.
*/
public APIUserCredentials(UserCredentials userCredentials) {
this.expected = userCredentials.getFields();
this.values = userCredentials.getValues();
}
/**
* Returns a collection of all required parameters, where each parameter is
* represented by a field.
*
* @return
* A collection of all required parameters.
*/
public Collection<Field> getExpected() {
return expected;
}
/**
* Returns a map of all field values by field name. The fields having the
* names used within this map should be defined within the collection of
* required parameters returned by getExpected().
*
* @return
* A map of all field values by field name.
*/
public Map<String, String> getValues() {
return values;
}
}

View File

@@ -19,16 +19,24 @@
package org.apache.guacamole.rest.activeconnection; package org.apache.guacamole.rest.activeconnection;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.ActiveConnection; import org.apache.guacamole.net.auth.ActiveConnection;
import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.connection.APIConnection;
import org.apache.guacamole.rest.directory.DirectoryObjectResource; import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator; import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.directory.DirectoryResourceFactory;
/** /**
* A REST resource which abstracts the operations available on an existing * A REST resource which abstracts the operations available on an existing
@@ -41,6 +49,25 @@ import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
public class ActiveConnectionResource public class ActiveConnectionResource
extends DirectoryObjectResource<ActiveConnection, APIActiveConnection> { extends DirectoryObjectResource<ActiveConnection, APIActiveConnection> {
/**
* The UserContext associated with the Directory which contains the
* Connection exposed by this resource.
*/
private final UserContext userContext;
/**
* The ActiveConnection exposed by this ActiveConnectionResource.
*/
private final ActiveConnection activeConnection;
/**
* A factory which can be used to create instances of resources representing
* Connection.
*/
@Inject
private DirectoryResourceFactory<Connection, APIConnection>
connectionDirectoryResourceFactory;
/** /**
* Creates a new ActiveConnectionResource which exposes the operations and * Creates a new ActiveConnectionResource which exposes the operations and
* subresources available for the given ActiveConnection. * subresources available for the given ActiveConnection.
@@ -51,7 +78,7 @@ public class ActiveConnectionResource
* @param directory * @param directory
* The Directory which contains the given ActiveConnection. * The Directory which contains the given ActiveConnection.
* *
* @param connection * @param activeConnection
* The ActiveConnection that this ActiveConnectionResource should * The ActiveConnection that this ActiveConnectionResource should
* represent. * represent.
* *
@@ -62,9 +89,58 @@ public class ActiveConnectionResource
@AssistedInject @AssistedInject
public ActiveConnectionResource(@Assisted UserContext userContext, public ActiveConnectionResource(@Assisted UserContext userContext,
@Assisted Directory<ActiveConnection> directory, @Assisted Directory<ActiveConnection> directory,
@Assisted ActiveConnection connection, @Assisted ActiveConnection activeConnection,
DirectoryObjectTranslator<ActiveConnection, APIActiveConnection> translator) { DirectoryObjectTranslator<ActiveConnection, APIActiveConnection> translator) {
super(directory, connection, translator); super(directory, activeConnection, translator);
this.userContext = userContext;
this.activeConnection = activeConnection;
}
/**
* Retrieves a resource representing the Connection object that is being
* actively used.
*
* @return
* A resource representing the Connection object that is being actively
* used.
*
* @throws GuacamoleException
* If an error occurs while retrieving the Connection.
*/
@Path("connection")
public DirectoryObjectResource<Connection, APIConnection> getConnection()
throws GuacamoleException {
// Return the underlying connection as a resource
return connectionDirectoryResourceFactory
.create(userContext, userContext.getConnectionDirectory())
.getObjectResource(activeConnection.getConnectionIdentifier());
}
/**
* Retrieves a set of credentials which can be POSTed by another user to the
* "/api/tokens" endpoint to obtain access strictly to this connection. The
* retrieved credentials may be purpose-generated and temporary.
*
* @param sharingProfileIdentifier The identifier of the sharing connection
* defining the semantics of the shared session.
*
* @return The set of credentials which should be used to access strictly
* this connection.
*
* @throws GuacamoleException If an error occurs while retrieving the
* sharing credentials for this connection.
*/
@GET
@Path("sharingCredentials/{sharingProfile}")
public APIUserCredentials getSharingCredentials(
@PathParam("sharingProfile") String sharingProfileIdentifier)
throws GuacamoleException {
// Generate and return sharing credentials for the active connection
return new APIUserCredentials(activeConnection.getSharingCredentials(sharingProfileIdentifier));
} }
} }

View File

@@ -22,6 +22,7 @@ package org.apache.guacamole.rest.connection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
@@ -122,6 +123,11 @@ public class APIConnectionWrapper implements Connection {
apiConnection.setAttributes(attributes); apiConnection.setAttributes(attributes);
} }
@Override
public Set<String> getSharingProfileIdentifiers() {
throw new UnsupportedOperationException("Operation not supported.");
}
@Override @Override
public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported."); throw new UnsupportedOperationException("Operation not supported.");

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.rest.connection; package org.apache.guacamole.rest.connection;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
import java.util.ArrayList; import java.util.ArrayList;
@@ -34,6 +35,8 @@ import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionRecord; import org.apache.guacamole.net.auth.ConnectionRecord;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.rest.directory.DirectoryView;
import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
@@ -44,6 +47,9 @@ import org.apache.guacamole.rest.history.APIConnectionRecord;
import org.apache.guacamole.protocol.GuacamoleConfiguration; import org.apache.guacamole.protocol.GuacamoleConfiguration;
import org.apache.guacamole.rest.directory.DirectoryObjectResource; import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator; import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.directory.DirectoryResource;
import org.apache.guacamole.rest.directory.DirectoryResourceFactory;
import org.apache.guacamole.rest.sharingprofile.APISharingProfile;
/** /**
* A REST resource which abstracts the operations available on an existing * A REST resource which abstracts the operations available on an existing
@@ -66,6 +72,14 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
*/ */
private final Connection connection; private final Connection connection;
/**
* A factory which can be used to create instances of resources representing
* SharingProfiles.
*/
@Inject
private DirectoryResourceFactory<SharingProfile, APISharingProfile>
sharingProfileDirectoryResourceFactory;
/** /**
* Creates a new ConnectionResource which exposes the operations and * Creates a new ConnectionResource which exposes the operations and
* subresources available for the given Connection. * subresources available for the given Connection.
@@ -152,4 +166,33 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
} }
/**
* Returns a resource which provides read-only access to the subset of
* SharingProfiles that the current user can use to share this connection.
*
* @return
* A resource which provides read-only access to the subset of
* SharingProfiles that the current user can use to share this
* connection.
*
* @throws GuacamoleException
* If the SharingProfiles associated with this connection cannot be
* retrieved.
*/
@Path("sharingProfiles")
public DirectoryResource<SharingProfile, APISharingProfile>
getSharingProfileDirectoryResource() throws GuacamoleException {
// Produce subset of all SharingProfiles, containing only those which
// are associated with this connection
Directory<SharingProfile> sharingProfiles = new DirectoryView<SharingProfile>(
userContext.getSharingProfileDirectory(),
connection.getSharingProfileIdentifiers()
);
// Return a new resource which provides access to only those SharingProfiles
return sharingProfileDirectoryResourceFactory.create(userContext, sharingProfiles);
}
} }

View File

@@ -0,0 +1,120 @@
/*
* 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.rest.directory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.Identifiable;
/**
* Directory implementation which represents a read-only subset of another
* existing Directory. Access is provided only to a limited set of objects,
* determined by the set of identifiers provided when the DirectoryView is
* created.
*
* @author Michael Jumper
* @param <ObjectType>
* The type of objects accessible through this DirectoryView.
*/
public class DirectoryView<ObjectType extends Identifiable>
implements Directory<ObjectType> {
/**
* The Directory from which the given set of objects will be retrieved.
*/
private final Directory<ObjectType> directory;
/**
* The set of identifiers representing the restricted set of objects that
* this DirectoryView should provide access to.
*/
private final Set<String> identifiers;
/**
* Creates a new DirectoryView which provides access to a read-only subset
* of the objects in the given Directory. Only objects whose identifiers
* are within the provided set will be accessible.
*
* @param directory
* The Directory of which this DirectoryView represents a subset.
*
* @param identifiers
* The identifiers of all objects which should be accessible through
* this DirectoryView. Objects which do not have identifiers within
* the provided set will be inaccessible.
*/
public DirectoryView(Directory<ObjectType> directory,
Set<String> identifiers) {
this.directory = directory;
this.identifiers = identifiers;
}
@Override
public ObjectType get(String identifier) throws GuacamoleException {
// Attempt to retrieve the requested object ONLY if it's within the
// originally-specified subset
if (!identifiers.contains(identifier))
return null;
// Delegate to underlying directory
return directory.get(identifier);
}
@Override
public Collection<ObjectType> getAll(Collection<String> identifiers)
throws GuacamoleException {
// Reduce requested identifiers to only those which occur within the
// originally-specified subset
identifiers = new ArrayList<String>(identifiers);
identifiers.retainAll(this.identifiers);
// Delegate to underlying directory
return directory.getAll(identifiers);
}
@Override
public Set<String> getIdentifiers() throws GuacamoleException {
return identifiers;
}
@Override
public void add(ObjectType object) throws GuacamoleException {
throw new GuacamoleUnsupportedException("Directory view is read-only");
}
@Override
public void update(ObjectType object) throws GuacamoleException {
throw new GuacamoleUnsupportedException("Directory view is read-only");
}
@Override
public void remove(String identifier) throws GuacamoleException {
throw new GuacamoleUnsupportedException("Directory view is read-only");
}
}

View File

@@ -39,6 +39,16 @@ public class APIConnectionRecord {
*/ */
private final String connectionName; private final String connectionName;
/**
* The identifier of the sharing profile associated with this record.
*/
private final String sharingProfileIdentifier;
/**
* The identifier of the sharing profile associated with this record.
*/
private final String sharingProfileName;
/** /**
* The date and time the connection began. * The date and time the connection began.
*/ */
@@ -73,13 +83,15 @@ public class APIConnectionRecord {
* The record to copy data from. * The record to copy data from.
*/ */
public APIConnectionRecord(ConnectionRecord record) { public APIConnectionRecord(ConnectionRecord record) {
this.connectionIdentifier = record.getConnectionIdentifier(); this.connectionIdentifier = record.getConnectionIdentifier();
this.connectionName = record.getConnectionName(); this.connectionName = record.getConnectionName();
this.startDate = record.getStartDate(); this.sharingProfileIdentifier = record.getSharingProfileIdentifier();
this.endDate = record.getEndDate(); this.sharingProfileName = record.getSharingProfileName();
this.remoteHost = record.getRemoteHost(); this.startDate = record.getStartDate();
this.username = record.getUsername(); this.endDate = record.getEndDate();
this.active = record.isActive(); this.remoteHost = record.getRemoteHost();
this.username = record.getUsername();
this.active = record.isActive();
} }
/** /**
@@ -103,6 +115,32 @@ public class APIConnectionRecord {
return connectionName; return connectionName;
} }
/**
* Returns the identifier of the sharing profile associated with this
* record. If the connection was not being used via a sharing profile, this
* will be null.
*
* @return
* The identifier of the sharing profile associated with this record,
* or null if no sharing profile was used.
*/
public String getSharingProfileIdentifier() {
return sharingProfileIdentifier;
}
/**
* Returns the name of the sharing profile associated with this record. If
* the connection was not being used via a sharing profile, this will be
* null.
*
* @return
* The name of the sharing profile associated with this record, or null
* if no sharing profile was used.
*/
public String getSharingProfileName() {
return sharingProfileName;
}
/** /**
* Returns the date and time the connection began. * Returns the date and time the connection began.
* *

View File

@@ -53,6 +53,12 @@ public class APIPermissionSet {
private Map<String, Set<ObjectPermission.Type>> connectionGroupPermissions = private Map<String, Set<ObjectPermission.Type>> connectionGroupPermissions =
new HashMap<String, Set<ObjectPermission.Type>>(); new HashMap<String, Set<ObjectPermission.Type>>();
/**
* Map of sharing profile ID to the set of granted permissions.
*/
private Map<String, Set<ObjectPermission.Type>> sharingProfilePermissions =
new HashMap<String, Set<ObjectPermission.Type>>();
/** /**
* Map of active connection ID to the set of granted permissions. * Map of active connection ID to the set of granted permissions.
*/ */
@@ -155,6 +161,7 @@ public class APIPermissionSet {
addSystemPermissions(systemPermissions, user.getSystemPermissions()); addSystemPermissions(systemPermissions, user.getSystemPermissions());
addObjectPermissions(connectionPermissions, user.getConnectionPermissions()); addObjectPermissions(connectionPermissions, user.getConnectionPermissions());
addObjectPermissions(connectionGroupPermissions, user.getConnectionGroupPermissions()); addObjectPermissions(connectionGroupPermissions, user.getConnectionGroupPermissions());
addObjectPermissions(sharingProfilePermissions, user.getSharingProfilePermissions());
addObjectPermissions(activeConnectionPermissions, user.getActiveConnectionPermissions()); addObjectPermissions(activeConnectionPermissions, user.getActiveConnectionPermissions());
addObjectPermissions(userPermissions, user.getUserPermissions()); addObjectPermissions(userPermissions, user.getUserPermissions());
@@ -190,6 +197,21 @@ public class APIPermissionSet {
return connectionGroupPermissions; return connectionGroupPermissions;
} }
/**
* Returns a map of sharing profile identifiers to the set of permissions
* granted for that sharing profile. If no permissions are granted to a
* particular sharing profile, its identifier will not be present as a key
* in the map. This map is mutable, and changes to this map will affect the
* permission set directly.
*
* @return
* A map of sharing profile identifiers to the set of permissions
* granted for that sharing profile.
*/
public Map<String, Set<ObjectPermission.Type>> getSharingProfilePermissions() {
return sharingProfilePermissions;
}
/** /**
* Returns a map of active connection IDs to the set of permissions granted * Returns a map of active connection IDs to the set of permissions granted
* for that active connection. If no permissions are granted to a particular * for that active connection. If no permissions are granted to a particular
@@ -257,6 +279,19 @@ public class APIPermissionSet {
this.connectionGroupPermissions = connectionGroupPermissions; this.connectionGroupPermissions = connectionGroupPermissions;
} }
/**
* Replaces the current map of sharing profile permissions with the given
* map, which must map each sharing profile identifier to its corresponding
* set of granted permissions. If a sharing profile has no permissions, its
* identifier must not be present as a key in the map.
*
* @param sharingProfilePermissions
* The map which must replace the currently-stored map of permissions.
*/
public void setSharingProfilePermissions(Map<String, Set<ObjectPermission.Type>> sharingProfilePermissions) {
this.sharingProfilePermissions = sharingProfilePermissions;
}
/** /**
* Replaces the current map of active connection permissions with the give * Replaces the current map of active connection permissions with the give
* map, which must map active connection ID to its corresponding set of * map, which must map active connection ID to its corresponding set of

View File

@@ -55,6 +55,12 @@ public class PermissionSetResource {
*/ */
private static final String CONNECTION_GROUP_PERMISSION_PATCH_PATH_PREFIX = "/connectionGroupPermissions/"; private static final String CONNECTION_GROUP_PERMISSION_PATCH_PATH_PREFIX = "/connectionGroupPermissions/";
/**
* The prefix of any path within an operation of a JSON patch which
* modifies the permissions of a user regarding a specific sharing profile.
*/
private static final String SHARING_PROFILE_PERMISSION_PATCH_PATH_PREFIX = "/sharingProfilePermissions/";
/** /**
* The prefix of any path within an operation of a JSON patch which * The prefix of any path within an operation of a JSON patch which
* modifies the permissions of a user regarding a specific active connection. * modifies the permissions of a user regarding a specific active connection.
@@ -170,6 +176,7 @@ public class PermissionSetResource {
// Permission patches for all types of permissions // Permission patches for all types of permissions
PermissionSetPatch<ObjectPermission> connectionPermissionPatch = new PermissionSetPatch<ObjectPermission>(); PermissionSetPatch<ObjectPermission> connectionPermissionPatch = new PermissionSetPatch<ObjectPermission>();
PermissionSetPatch<ObjectPermission> connectionGroupPermissionPatch = new PermissionSetPatch<ObjectPermission>(); PermissionSetPatch<ObjectPermission> connectionGroupPermissionPatch = new PermissionSetPatch<ObjectPermission>();
PermissionSetPatch<ObjectPermission> sharingProfilePermissionPatch = new PermissionSetPatch<ObjectPermission>();
PermissionSetPatch<ObjectPermission> activeConnectionPermissionPatch = new PermissionSetPatch<ObjectPermission>(); PermissionSetPatch<ObjectPermission> activeConnectionPermissionPatch = new PermissionSetPatch<ObjectPermission>();
PermissionSetPatch<ObjectPermission> userPermissionPatch = new PermissionSetPatch<ObjectPermission>(); PermissionSetPatch<ObjectPermission> userPermissionPatch = new PermissionSetPatch<ObjectPermission>();
PermissionSetPatch<SystemPermission> systemPermissionPatch = new PermissionSetPatch<SystemPermission>(); PermissionSetPatch<SystemPermission> systemPermissionPatch = new PermissionSetPatch<SystemPermission>();
@@ -205,6 +212,19 @@ public class PermissionSetResource {
} }
// Create sharing profile permission if path has sharing profile prefix
else if (path.startsWith(SHARING_PROFILE_PERMISSION_PATCH_PATH_PREFIX)) {
// Get identifier and type from patch operation
String identifier = path.substring(SHARING_PROFILE_PERMISSION_PATCH_PATH_PREFIX.length());
ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue());
// Create and update corresponding permission
ObjectPermission permission = new ObjectPermission(type, identifier);
updatePermissionSet(patch.getOp(), sharingProfilePermissionPatch, permission);
}
// Create active connection permission if path has active connection prefix // Create active connection permission if path has active connection prefix
else if (path.startsWith(ACTIVE_CONNECTION_PERMISSION_PATCH_PATH_PREFIX)) { else if (path.startsWith(ACTIVE_CONNECTION_PERMISSION_PATCH_PATH_PREFIX)) {
@@ -252,6 +272,7 @@ public class PermissionSetResource {
// Save the permission changes // Save the permission changes
connectionPermissionPatch.apply(user.getConnectionPermissions()); connectionPermissionPatch.apply(user.getConnectionPermissions());
connectionGroupPermissionPatch.apply(user.getConnectionGroupPermissions()); connectionGroupPermissionPatch.apply(user.getConnectionGroupPermissions());
sharingProfilePermissionPatch.apply(user.getSharingProfilePermissions());
activeConnectionPermissionPatch.apply(user.getActiveConnectionPermissions()); activeConnectionPermissionPatch.apply(user.getActiveConnectionPermissions());
userPermissionPatch.apply(user.getUserPermissions()); userPermissionPatch.apply(user.getUserPermissions());
systemPermissionPatch.apply(user.getSystemPermissions()); systemPermissionPatch.apply(user.getSystemPermissions());

View File

@@ -31,6 +31,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSession; import org.apache.guacamole.GuacamoleSession;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.tunnel.TunnelCollectionResource; import org.apache.guacamole.rest.tunnel.TunnelCollectionResource;
import org.apache.guacamole.rest.tunnel.TunnelCollectionResourceFactory;
/** /**
* A REST resource which exposes all data associated with a Guacamole user's * A REST resource which exposes all data associated with a Guacamole user's
@@ -54,6 +55,13 @@ public class SessionResource {
@Inject @Inject
private UserContextResourceFactory userContextResourceFactory; private UserContextResourceFactory userContextResourceFactory;
/**
* Factory for creating instances of resources which represent the
* collection of tunnels within a GuacamoleSession.
*/
@Inject
private TunnelCollectionResourceFactory tunnelCollectionResourceFactory;
/** /**
* Creates a new SessionResource which exposes the data within the given * Creates a new SessionResource which exposes the data within the given
* GuacamoleSession. * GuacamoleSession.
@@ -105,7 +113,7 @@ public class SessionResource {
*/ */
@Path("tunnels") @Path("tunnels")
public TunnelCollectionResource getTunnelCollectionResource() { public TunnelCollectionResource getTunnelCollectionResource() {
return new TunnelCollectionResource(session); return tunnelCollectionResourceFactory.create(session);
} }
} }

View File

@@ -32,6 +32,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.ActiveConnection; import org.apache.guacamole.net.auth.ActiveConnection;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.activeconnection.APIActiveConnection; import org.apache.guacamole.rest.activeconnection.APIActiveConnection;
@@ -39,6 +40,7 @@ import org.apache.guacamole.rest.connection.APIConnection;
import org.apache.guacamole.rest.connectiongroup.APIConnectionGroup; import org.apache.guacamole.rest.connectiongroup.APIConnectionGroup;
import org.apache.guacamole.rest.history.HistoryResource; import org.apache.guacamole.rest.history.HistoryResource;
import org.apache.guacamole.rest.schema.SchemaResource; import org.apache.guacamole.rest.schema.SchemaResource;
import org.apache.guacamole.rest.sharingprofile.APISharingProfile;
import org.apache.guacamole.rest.user.APIUser; import org.apache.guacamole.rest.user.APIUser;
/** /**
@@ -79,6 +81,14 @@ public class UserContextResource {
private DirectoryResourceFactory<ConnectionGroup, APIConnectionGroup> private DirectoryResourceFactory<ConnectionGroup, APIConnectionGroup>
connectionGroupDirectoryResourceFactory; connectionGroupDirectoryResourceFactory;
/**
* Factory for creating DirectoryResources which expose a given
* SharingProfile Directory.
*/
@Inject
private DirectoryResourceFactory<SharingProfile, APISharingProfile>
sharingProfileDirectoryResourceFactory;
/** /**
* Factory for creating DirectoryResources which expose a given * Factory for creating DirectoryResources which expose a given
* User Directory. * User Directory.
@@ -153,6 +163,24 @@ public class UserContextResource {
userContext.getConnectionGroupDirectory()); userContext.getConnectionGroupDirectory());
} }
/**
* Returns a new resource which represents the SharingProfile Directory
* contained within the UserContext exposed by this UserContextResource.
*
* @return
* A new resource which represents the SharingProfile Directory
* contained within the UserContext exposed by this UserContextResource.
*
* @throws GuacamoleException
* If an error occurs while retrieving the SharingProfile Directory.
*/
@Path("sharingProfiles")
public DirectoryResource<SharingProfile, APISharingProfile>
getSharingProfileDirectoryResource() throws GuacamoleException {
return sharingProfileDirectoryResourceFactory.create(userContext,
userContext.getSharingProfileDirectory());
}
/** /**
* Returns a new resource which represents the User Directory contained * Returns a new resource which represents the User Directory contained
* within the UserContext exposed by this UserContextResource. * within the UserContext exposed by this UserContextResource.

View File

@@ -0,0 +1,207 @@
/*
* 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.rest.sharingprofile;
import java.util.Map;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.apache.guacamole.net.auth.SharingProfile;
/**
* The external representation used by the REST API for sharing profiles.
*
* @author Michael Jumper
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class APISharingProfile {
/**
* The human-readable name of this sharing profile.
*/
private String name;
/**
* The unique string which identifies this sharing profile within its
* containing directory.
*/
private String identifier;
/**
* The identifier of the primary connection that this sharing profile
* can be used to share.
*/
private String primaryConnectionIdentifier;
/**
* Map of all associated connection parameter values which apply when the
* sharing profile is used, indexed by parameter name.
*/
private Map<String, String> parameters;
/**
* Map of all associated attributes by attribute identifier.
*/
private Map<String, String> attributes;
/**
* Creates an empty, uninitialized APISharingProfile. The properties of the
* created APISharingProfile will need to be set individually as necessary
* via their corresponding setters.
*/
public APISharingProfile() {}
/**
* Creates a new APISharingProfile with its data populated from that of an
* existing SharingProfile. As the connection parameters of the
* SharingProfile are potentially sensitive, they will not be included in
* the new APISharingProfile.
*
* @param sharingProfile
* The sharing profile to use to populate the data of the new
* APISharingProfile.
*/
public APISharingProfile(SharingProfile sharingProfile) {
// Set main information
this.name = sharingProfile.getName();
this.identifier = sharingProfile.getIdentifier();
this.primaryConnectionIdentifier = sharingProfile.getPrimaryConnectionIdentifier();
// Associate any attributes
this.attributes = sharingProfile.getAttributes();
}
/**
* Returns the human-readable name of this sharing profile.
*
* @return
* The human-readable name of this sharing profile.
*/
public String getName() {
return name;
}
/**
* Set the human-readable name of this sharing profile.
*
* @param name
* The human-readable name of this sharing profile.
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the unique string which identifies this sharing profile within
* its containing directory.
*
* @return
* The unique string which identifies this sharing profile within its
* containing directory.
*/
public String getIdentifier() {
return identifier;
}
/**
* Sets the unique string which identifies this sharing profile within
* its containing directory.
*
* @param identifier
* The unique string which identifies this sharing profile within its
* containing directory.
*/
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
/**
* Returns the identifier of the primary connection that this sharing
* profile can be used to share.
*
* @return
* The identifier of the primary connection that this sharing profile
* can be used to share.
*/
public String getPrimaryConnectionIdentifier() {
return primaryConnectionIdentifier;
}
/**
* Sets the identifier of the primary connection that this sharing profile
* can be used to share.
*
* @param primaryConnectionIdentifier
* The identifier of the primary connection that this sharing profile
* can be used to share.
*/
public void setPrimaryConnectionIdentifier(String primaryConnectionIdentifier) {
this.primaryConnectionIdentifier = primaryConnectionIdentifier;
}
/**
* Returns a map of all associated connection parameter values which apply
* when the sharing profile is used, indexed by parameter name.
*
* @return
* A map of all associated connection parameter values which apply when
* the sharing profile is used, indexed by parameter name.
*/
public Map<String, String> getParameters() {
return parameters;
}
/**
* Sets the map of all associated connection parameter values which apply
* when the sharing profile is used, indexed by parameter name.
*
* @param parameters
* The map of all associated connection parameter values which apply
* when the sharing profile is used, indexed by parameter name.
*/
public void setParameters(Map<String, String> parameters) {
this.parameters = parameters;
}
/**
* Returns a map of all attributes associated with this sharing profile.
* Each entry key is the attribute identifier, while each value is the
* attribute value itself.
*
* @return
* The attribute map for this sharing profile.
*/
public Map<String, String> getAttributes() {
return attributes;
}
/**
* Sets the map of all attributes associated with this sharing profile. Each
* entry key is the attribute identifier, while each value is the attribute
* value itself.
*
* @param attributes
* The attribute map for this sharing profile.
*/
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.rest.sharingprofile;
import java.util.Map;
import org.apache.guacamole.net.auth.SharingProfile;
/**
* Wrapper for APISharingProfile which provides a SharingProfile interface.
* Changes to the underlying APISharingProfile are reflected immediately in the
* values exposed by the SharingProfile interface, and changes made through the
* SharingProfile interface immediately affect the underlying APISharingProfile.
*
* @author Michael Jumper
*/
public class APISharingProfileWrapper implements SharingProfile {
/**
* The wrapped APISharingProfile.
*/
private final APISharingProfile apiSharingProfile;
/**
* Creates a new APISharingProfileWrapper which is backed by the given
* APISharingProfile.
*
* @param apiSharingProfile
* The APISharingProfile to wrap.
*/
public APISharingProfileWrapper(APISharingProfile apiSharingProfile) {
this.apiSharingProfile = apiSharingProfile;
}
@Override
public String getName() {
return apiSharingProfile.getName();
}
@Override
public void setName(String name) {
apiSharingProfile.setName(name);
}
@Override
public String getIdentifier() {
return apiSharingProfile.getIdentifier();
}
@Override
public void setIdentifier(String identifier) {
apiSharingProfile.setIdentifier(identifier);
}
@Override
public String getPrimaryConnectionIdentifier() {
return apiSharingProfile.getPrimaryConnectionIdentifier();
}
@Override
public void setPrimaryConnectionIdentifier(String primaryConnectionIdentifier) {
apiSharingProfile.setPrimaryConnectionIdentifier(primaryConnectionIdentifier);
}
@Override
public Map<String, String> getParameters() {
return apiSharingProfile.getParameters();
}
@Override
public void setParameters(Map<String, String> parameters) {
apiSharingProfile.setParameters(parameters);
}
@Override
public Map<String, String> getAttributes() {
return apiSharingProfile.getAttributes();
}
@Override
public void setAttributes(Map<String, String> attributes) {
apiSharingProfile.setAttributes(attributes);
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.rest.sharingprofile;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.directory.DirectoryResource;
/**
* A REST resource which abstracts the operations available on a Directory of
* SharingProfiles.
*
* @author Michael Jumper
*/
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class SharingProfileDirectoryResource
extends DirectoryResource<SharingProfile, APISharingProfile> {
/**
* Creates a new SharingProfileDirectoryResource which exposes the
* operations and subresources available for the given SharingProfile
* Directory.
*
* @param userContext
* The UserContext associated with the given Directory.
*
* @param directory
* The Directory being exposed.
*
* @param translator
* A DirectoryObjectTranslator implementation which handles
* SharingProfiles.
*
* @param resourceFactory
* A factory which can be used to create instances of resources
* representing SharingProfiles.
*/
@AssistedInject
public SharingProfileDirectoryResource(@Assisted UserContext userContext,
@Assisted Directory<SharingProfile> directory,
DirectoryObjectTranslator<SharingProfile, APISharingProfile> translator,
DirectoryObjectResourceFactory<SharingProfile, APISharingProfile> resourceFactory) {
super(userContext, directory, translator, resourceFactory);
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.rest.sharingprofile;
import com.google.inject.AbstractModule;
import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory;
import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.directory.DirectoryResource;
import org.apache.guacamole.rest.directory.DirectoryResourceFactory;
/**
* Guice Module which configures injections required for handling SharingProfile
* resources via the REST API.
*
* @author Michael Jumper
*/
public class SharingProfileModule extends AbstractModule {
@Override
protected void configure() {
// Create the required DirectoryResourceFactory implementation
install(new FactoryModuleBuilder()
.implement(
new TypeLiteral<DirectoryResource<SharingProfile, APISharingProfile>>() {},
SharingProfileDirectoryResource.class
)
.build(new TypeLiteral<DirectoryResourceFactory<SharingProfile, APISharingProfile>>() {}));
// Create the required DirectoryObjectResourceFactory implementation
install(new FactoryModuleBuilder()
.implement(
new TypeLiteral<DirectoryObjectResource<SharingProfile, APISharingProfile>>() {},
SharingProfileResource.class
)
.build(new TypeLiteral<DirectoryObjectResourceFactory<SharingProfile, APISharingProfile>>() {}));
// Bind translator for converting between SharingProfile and APISharingProfile
bind(new TypeLiteral<DirectoryObjectTranslator<SharingProfile, APISharingProfile>>() {})
.to(SharingProfileObjectTranslator.class);
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.rest.sharingprofile;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
/**
* Translator which converts between SharingProfile objects and
* APISharingProfile objects.
*
* @author Michael Jumper
*/
public class SharingProfileObjectTranslator
implements DirectoryObjectTranslator<SharingProfile, APISharingProfile> {
@Override
public APISharingProfile toExternalObject(SharingProfile object)
throws GuacamoleException {
return new APISharingProfile(object);
}
@Override
public SharingProfile toInternalObject(APISharingProfile object) {
return new APISharingProfileWrapper(object);
}
@Override
public void applyExternalChanges(SharingProfile existingObject,
APISharingProfile object) {
// Update the sharing profile
existingObject.setPrimaryConnectionIdentifier(object.getPrimaryConnectionIdentifier());
existingObject.setName(object.getName());
existingObject.setParameters(object.getParameters());
existingObject.setAttributes(object.getAttributes());
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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.rest.sharingprofile;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException;
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.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
/**
* A REST resource which abstracts the operations available on an existing
* SharingProfile.
*
* @author Michael Jumper
*/
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class SharingProfileResource
extends DirectoryObjectResource<SharingProfile, APISharingProfile> {
/**
* The UserContext associated with the Directory which contains the
* SharingProfile exposed by this resource.
*/
private final UserContext userContext;
/**
* The SharingProfile object represented by this SharingProfileResource.
*/
private final SharingProfile sharingProfile;
/**
* Creates a new SharingProfileResource which exposes the operations and
* subresources available for the given SharingProfile.
*
* @param userContext
* The UserContext associated with the given Directory.
*
* @param directory
* The Directory which contains the given SharingProfile.
*
* @param sharingProfile
* The SharingProfile that this SharingProfileResource should represent.
*
* @param translator
* A DirectoryObjectTranslator implementation which handles the type of
* object given.
*/
@AssistedInject
public SharingProfileResource(@Assisted UserContext userContext,
@Assisted Directory<SharingProfile> directory,
@Assisted SharingProfile sharingProfile,
DirectoryObjectTranslator<SharingProfile, APISharingProfile> translator) {
super(directory, sharingProfile, translator);
this.userContext = userContext;
this.sharingProfile = sharingProfile;
}
/**
* Retrieves the connection parameters associated with the SharingProfile
* exposed by this SharingProfile resource.
*
* @return
* A map of parameter name/value pairs.
*
* @throws GuacamoleException
* If an error occurs while retrieving the connection parameters of the
* SharingProfile.
*/
@GET
@Path("parameters")
public Map<String, String> getParameters()
throws GuacamoleException {
User self = userContext.self();
// Retrieve permission sets
SystemPermissionSet systemPermissions = self.getSystemPermissions();
ObjectPermissionSet sharingProfilePermissions = self.getSharingProfilePermissions();
// Deny access if adminstrative or update permission is missing
String identifier = sharingProfile.getIdentifier();
if (!systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER)
&& !sharingProfilePermissions.hasPermission(ObjectPermission.Type.UPDATE, identifier))
throw new GuacamoleSecurityException("Permission to read sharing profile parameters denied.");
// Return parameter map
return sharingProfile.getParameters();
}
}

View File

@@ -0,0 +1,25 @@
/*
* 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.
*/
/**
* Classes related to retrieving or manipulating sharing profiles using the
* Guacamole REST API.
*/
package org.apache.guacamole.rest.sharingprofile;

View File

@@ -19,6 +19,9 @@
package org.apache.guacamole.rest.tunnel; package org.apache.guacamole.rest.tunnel;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@@ -30,7 +33,7 @@ import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.GuacamoleResourceNotFoundException;
import org.apache.guacamole.GuacamoleSession; import org.apache.guacamole.GuacamoleSession;
import org.apache.guacamole.tunnel.StreamInterceptingTunnel; import org.apache.guacamole.tunnel.UserTunnel;
/** /**
* A REST resource which exposes the active tunnels of a Guacamole session. * A REST resource which exposes the active tunnels of a Guacamole session.
@@ -46,6 +49,12 @@ public class TunnelCollectionResource {
*/ */
private final GuacamoleSession session; private final GuacamoleSession session;
/**
* Factory for creating instances of resources which represent tunnels.
*/
@Inject
private TunnelResourceFactory tunnelResourceFactory;
/** /**
* Creates a new TunnelCollectionResource which exposes the active tunnels * Creates a new TunnelCollectionResource which exposes the active tunnels
* of the given GuacamoleSession. * of the given GuacamoleSession.
@@ -54,7 +63,8 @@ public class TunnelCollectionResource {
* The GuacamoleSession whose tunnels should be exposed by this * The GuacamoleSession whose tunnels should be exposed by this
* resource. * resource.
*/ */
public TunnelCollectionResource(GuacamoleSession session) { @AssistedInject
public TunnelCollectionResource(@Assisted GuacamoleSession session) {
this.session = session; this.session = session;
} }
@@ -89,15 +99,15 @@ public class TunnelCollectionResource {
public TunnelResource getTunnel(@PathParam("tunnel") String tunnelUUID) public TunnelResource getTunnel(@PathParam("tunnel") String tunnelUUID)
throws GuacamoleException { throws GuacamoleException {
Map<String, StreamInterceptingTunnel> tunnels = session.getTunnels(); Map<String, UserTunnel> tunnels = session.getTunnels();
// Pull tunnel with given UUID // Pull tunnel with given UUID
final StreamInterceptingTunnel tunnel = tunnels.get(tunnelUUID); final UserTunnel tunnel = tunnels.get(tunnelUUID);
if (tunnel == null) if (tunnel == null)
throw new GuacamoleResourceNotFoundException("No such tunnel."); throw new GuacamoleResourceNotFoundException("No such tunnel.");
// Return corresponding tunnel resource // Return corresponding tunnel resource
return new TunnelResource(tunnel); return tunnelResourceFactory.create(tunnel);
} }

View File

@@ -0,0 +1,45 @@
/*
* 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.rest.tunnel;
import org.apache.guacamole.GuacamoleSession;
/**
* Factory which creates resources that expose the collection of tunnels
* contained within a given GuacamoleSession.
*
* @author Michael Jumper
*/
public interface TunnelCollectionResourceFactory {
/**
* Creates a new TunnelCollectionResource which exposes the collection of
* tunnels stored within the given GuacamoleSession.
*
* @param session
* The GuacamoleSession whose collection of tunnels should be exposed.
*
* @return
* A new TunnelCollectionResource which exposes the collection of
* tunnels stored within the given GuacamoleSession.
*/
TunnelCollectionResource create(GuacamoleSession session);
}

View File

@@ -19,6 +19,9 @@
package org.apache.guacamole.rest.tunnel; package org.apache.guacamole.rest.tunnel;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue; import javax.ws.rs.DefaultValue;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@@ -27,7 +30,12 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.tunnel.StreamInterceptingTunnel; import org.apache.guacamole.net.auth.ActiveConnection;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.activeconnection.APIActiveConnection;
import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory;
import org.apache.guacamole.tunnel.UserTunnel;
/** /**
* A REST resource which abstracts the operations available for an individual * A REST resource which abstracts the operations available for an individual
@@ -48,7 +56,15 @@ public class TunnelResource {
/** /**
* The tunnel that this TunnelResource represents. * The tunnel that this TunnelResource represents.
*/ */
private final StreamInterceptingTunnel tunnel; private final UserTunnel tunnel;
/**
* A factory which can be used to create instances of resources representing
* ActiveConnections.
*/
@Inject
private DirectoryObjectResourceFactory<ActiveConnection, APIActiveConnection>
activeConnectionResourceFactory;
/** /**
* Creates a new TunnelResource which exposes the operations and * Creates a new TunnelResource which exposes the operations and
@@ -57,10 +73,36 @@ public class TunnelResource {
* @param tunnel * @param tunnel
* The tunnel that this TunnelResource should represent. * The tunnel that this TunnelResource should represent.
*/ */
public TunnelResource(StreamInterceptingTunnel tunnel) { @AssistedInject
public TunnelResource(@Assisted UserTunnel tunnel) {
this.tunnel = tunnel; this.tunnel = tunnel;
} }
/**
* Retrieves a resource representing the ActiveConnection object associated
* with this tunnel.
*
* @return
* A resource representing the ActiveConnection object associated with
* this tunnel.
*
* @throws GuacamoleException
* If an error occurs while retrieving the ActiveConnection.
*/
@Path("activeConnection")
public DirectoryObjectResource<ActiveConnection, APIActiveConnection>
getActiveConnection() throws GuacamoleException {
// Pull the UserContext from the tunnel
UserContext userContext = tunnel.getUserContext();
// Return the associated ActiveConnection as a resource
return activeConnectionResourceFactory.create(userContext,
userContext.getActiveConnectionDirectory(),
tunnel.getActiveConnection());
}
/** /**
* Intercepts and returns the entire contents of a specific stream. * Intercepts and returns the entire contents of a specific stream.
* *

View File

@@ -0,0 +1,44 @@
/*
* 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.rest.tunnel;
import org.apache.guacamole.tunnel.UserTunnel;
/**
* Factory which creates resources that expose the contents of a given
* tunnel.
*
* @author Michael Jumper
*/
public interface TunnelResourceFactory {
/**
* Creates a new TunnelResource which exposes the contents of the
* given tunnel.
*
* @param tunnel
* The tunnel whose contents should be exposed.
*
* @return
* A new TunnelResource which exposes the contents of the given tunnel.
*/
TunnelResource create(UserTunnel tunnel);
}

View File

@@ -97,6 +97,11 @@ public class APIUserWrapper implements User {
throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access.");
} }
@Override
public ObjectPermissionSet getSharingProfilePermissions() throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access.");
}
@Override @Override
public ObjectPermissionSet getUserPermissions() public ObjectPermissionSet getUserPermissions()
throws GuacamoleException { throws GuacamoleException {

View File

@@ -211,6 +211,10 @@ public class TunnelRequestService {
* @param session * @param session
* The Guacamole session to associate the tunnel with. * The Guacamole session to associate the tunnel with.
* *
* @param context
* The UserContext associated with the user for whom the tunnel is
* being created.
*
* @param type * @param type
* The type of object being connected to (connection or group). * The type of object being connected to (connection or group).
* *
@@ -226,12 +230,12 @@ public class TunnelRequestService {
* If an error occurs while obtaining the tunnel. * If an error occurs while obtaining the tunnel.
*/ */
protected GuacamoleTunnel createAssociatedTunnel(GuacamoleTunnel tunnel, protected GuacamoleTunnel createAssociatedTunnel(GuacamoleTunnel tunnel,
final String authToken, final GuacamoleSession session, final String authToken, final GuacamoleSession session,
final TunnelRequest.Type type, final String id) final UserContext context, final TunnelRequest.Type type,
throws GuacamoleException { final String id) throws GuacamoleException {
// Monitor tunnel closure and data // Monitor tunnel closure and data
StreamInterceptingTunnel monitoredTunnel = new StreamInterceptingTunnel(tunnel) { UserTunnel monitoredTunnel = new UserTunnel(context, tunnel) {
/** /**
* The time the connection began, measured in milliseconds since * The time the connection began, measured in milliseconds since
@@ -328,7 +332,7 @@ public class TunnelRequestService {
GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, id, info); GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, id, info);
// Associate tunnel with session // Associate tunnel with session
return createAssociatedTunnel(tunnel, authToken, session, type, id); return createAssociatedTunnel(tunnel, authToken, session, userContext, type, id);
} }

View File

@@ -0,0 +1,120 @@
/*
* 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.tunnel;
import java.util.Collection;
import java.util.UUID;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.net.auth.ActiveConnection;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext;
/**
* Tunnel implementation which associates a given tunnel with the UserContext of
* the user that created it.
*
* @author Michael Jumper
*/
public class UserTunnel extends StreamInterceptingTunnel {
/**
* The UserContext associated with the user for whom this tunnel was
* created. This UserContext MUST be from the AuthenticationProvider that
* created this tunnel.
*/
private final UserContext userContext;
/**
* Creates a new UserTunnel which wraps the given tunnel, associating it
* with the given UserContext. The UserContext MUST be from the
* AuthenticationProvider that created this tunnel, and MUST be associated
* with the user for whom this tunnel was created.
*
* @param userContext
* The UserContext associated with the user for whom this tunnel was
* created. This UserContext MUST be from the AuthenticationProvider
* that created this tunnel.
*
* @param tunnel
* The tunnel whose stream-related instruction should be intercepted if
* interceptStream() is invoked.
*/
public UserTunnel(UserContext userContext, GuacamoleTunnel tunnel) {
super(tunnel);
this.userContext = userContext;
}
/**
* Returns the UserContext of the user for whom this tunnel was created.
* This UserContext will be the UserContext from the AuthenticationProvider
* that created this tunnel.
*
* @return
* The UserContext of the user for whom this tunnel was created.
*/
public UserContext getUserContext() {
return userContext;
}
/**
* Returns the ActiveConnection object associated with this tunnel within
* the AuthenticationProvider and UserContext which created the tunnel. If
* the AuthenticationProvider is not tracking active connections, or this
* tunnel is no longer active, this will be null.
*
* @return
* The ActiveConnection object associated with this tunnel, or null if
* this tunnel is no longer active or the AuthenticationProvider which
* created the tunnel is not tracking active connections.
*
* @throws GuacamoleException
* If an error occurs which prevents retrieval of the user's current
* active connections.
*/
public ActiveConnection getActiveConnection() throws GuacamoleException {
// Pull the UUID of the current tunnel
UUID uuid = getUUID();
// Get the directory of active connections
Directory<ActiveConnection> activeConnectionDirectory = userContext.getActiveConnectionDirectory();
Collection<String> activeConnectionIdentifiers = activeConnectionDirectory.getIdentifiers();
// Search all connections for a tunnel which matches this tunnel
for (ActiveConnection activeConnection : activeConnectionDirectory.getAll(activeConnectionIdentifiers)) {
// If we lack access, continue with next tunnel
GuacamoleTunnel tunnel = activeConnection.getTunnel();
if (tunnel == null)
continue;
// Tunnels are equivalent if they have the same UUID
if (uuid.equals(tunnel.getUUID()))
return activeConnection;
}
// No active connection associated with this tunnel
return null;
}
}

View File

@@ -166,6 +166,41 @@ angular.module('rest').factory('activeConnectionService', ['$injector',
}; };
/**
* Makes a request to the REST API to generate credentials which have
* access strictly to the given active connection, using the restrictions
* defined by the given sharing profile, returning a promise that provides
* the resulting @link{UserCredentials} object if successful.
*
* @param {String} id
* The identifier of the active connection being shared.
*
* @param {String} sharingProfile
* The identifier of the sharing profile dictating the
* semantics/restrictions which apply to the shared session.
*
* @returns {Promise.<UserCredentials>}
* A promise which will resolve with a @link{UserCredentials} object
* upon success.
*/
service.getSharingCredentials = function getSharingCredentials(dataSource, id, sharingProfile) {
// Build HTTP parameters set
var httpParameters = {
token : authenticationService.getCurrentToken()
};
// Generate sharing credentials
return $http({
method : 'GET',
url : 'api/session/data/' + encodeURIComponent(dataSource)
+ '/activeConnections/' + encodeURIComponent(id)
+ '/sharingCredentials/' + encodeURIComponent(sharingProfile),
params : httpParameters
});
};
return service; return service;
}]); }]);

View File

@@ -68,6 +68,73 @@ angular.module('rest').factory('tunnelService', ['$injector',
}; };
/**
* Retrieves the set of sharing profiles that the current user can use to
* share the active connection of the given tunnel.
*
* @param {String} tunnel
* The UUID of the tunnel associated with the Guacamole connection
* whose sharing profiles are being retrieved.
*
* @returns {Promise.<Object.<String, SharingProfile>>}
* A promise which will resolve with a map of @link{SharingProfile}
* objects where each key is the identifier of the corresponding
* sharing profile.
*/
service.getSharingProfiles = function getSharingProfiles(tunnel) {
// Build HTTP parameters set
var httpParameters = {
token : authenticationService.getCurrentToken()
};
// Retrieve all associated sharing profiles
return $http({
method : 'GET',
url : 'api/session/tunnels/' + encodeURIComponent(tunnel)
+ '/activeConnection/connection/sharingProfiles',
params : httpParameters
});
};
/**
* Makes a request to the REST API to generate credentials which have
* access strictly to the active connection associated with the given
* tunnel, using the restrictions defined by the given sharing profile,
* returning a promise that provides the resulting @link{UserCredentials}
* object if successful.
*
* @param {String} tunnel
* The UUID of the tunnel associated with the Guacamole connection
* being shared.
*
* @param {String} sharingProfile
* The identifier of the connection object dictating the
* semantics/restrictions which apply to the shared session.
*
* @returns {Promise.<UserCredentials>}
* A promise which will resolve with a @link{UserCredentials} object
* upon success.
*/
service.getSharingCredentials = function getSharingCredentials(tunnel, sharingProfile) {
// Build HTTP parameters set
var httpParameters = {
token : authenticationService.getCurrentToken()
};
// Generate sharing credentials
return $http({
method : 'GET',
url : 'api/session/tunnels/' + encodeURIComponent(tunnel)
+ '/activeConnection/sharingCredentials/'
+ encodeURIComponent(sharingProfile),
params : httpParameters
});
};
/** /**
* Makes a request to the REST API to retrieve the contents of a stream * Makes a request to the REST API to retrieve the contents of a stream
* which has been created within the active Guacamole connection associated * which has been created within the active Guacamole connection associated

View File

@@ -73,7 +73,7 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
TEXT : "TEXT", TEXT : 'TEXT',
/** /**
* The type string associated with parameters that may contain an * The type string associated with parameters that may contain an
@@ -82,7 +82,7 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
USERNAME : "USERNAME", USERNAME : 'USERNAME',
/** /**
* The type string associated with parameters that may contain an * The type string associated with parameters that may contain an
@@ -91,7 +91,7 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
PASSWORD : "PASSWORD", PASSWORD : 'PASSWORD',
/** /**
* The type string associated with parameters that may contain only * The type string associated with parameters that may contain only
@@ -99,7 +99,7 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
NUMERIC : "NUMERIC", NUMERIC : 'NUMERIC',
/** /**
* The type string associated with parameters that may contain only a * The type string associated with parameters that may contain only a
@@ -110,7 +110,7 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
BOOLEAN : "BOOLEAN", BOOLEAN : 'BOOLEAN',
/** /**
* The type string associated with parameters that may contain a * The type string associated with parameters that may contain a
@@ -118,7 +118,7 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
ENUM : "ENUM", ENUM : 'ENUM',
/** /**
* The type string associated with parameters that may contain any * The type string associated with parameters that may contain any
@@ -126,7 +126,7 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
MULTILINE : "MULTILINE", MULTILINE : 'MULTILINE',
/** /**
* The type string associated with parameters that may contain timezone * The type string associated with parameters that may contain timezone
@@ -135,7 +135,7 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
TIMEZONE : "TIMEZONE", TIMEZONE : 'TIMEZONE',
/** /**
* The type string associated with parameters that may contain dates. * The type string associated with parameters that may contain dates.
@@ -143,7 +143,7 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
DATE : "DATE", DATE : 'DATE',
/** /**
* The type string associated with parameters that may contain times. * The type string associated with parameters that may contain times.
@@ -152,7 +152,15 @@ angular.module('rest').factory('Field', [function defineField() {
* *
* @type String * @type String
*/ */
TIME : "TIME" TIME : 'TIME',
/**
* An HTTP query parameter which is expected to be embedded in the URL
* given to a user.
*
* @type String
*/
QUERY_PARAMETER : 'QUERY_PARAMETER'
}; };

View File

@@ -0,0 +1,85 @@
/*
* 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.
*/
/**
* Service which defines the SharingProfile class.
*/
angular.module('rest').factory('SharingProfile', [function defineSharingProfile() {
/**
* The object returned by REST API calls when representing the data
* associated with a sharing profile.
*
* @constructor
* @param {SharingProfile|Object} [template={}]
* The object whose properties should be copied within the new
* SharingProfile.
*/
var SharingProfile = function SharingProfile(template) {
// Use empty object by default
template = template || {};
/**
* The unique identifier associated with this sharing profile.
*
* @type String
*/
this.identifier = template.identifier;
/**
* The unique identifier of the connection that this sharing profile
* can be used to share.
*
* @type String
*/
this.primaryConnectionIdentifier = template.primaryConnectionIdentifier;
/**
* The human-readable name of this sharing profile, which is not
* necessarily unique.
*
* @type String
*/
this.name = template.name;
/**
* Connection configuration parameters, as dictated by the protocol in
* use by the primary connection, arranged as name/value pairs. This
* information may not be available until directly queried. If this
* information is unavailable, this property will be null or undefined.
*
* @type Object.<String, String>
*/
this.parameters = template.parameters;
/**
* Arbitrary name/value pairs which further describe this sharing
* profile. The semantics and validity of these attributes are dictated
* by the extension which defines them.
*
* @type Object.<String, String>
*/
this.attributes = {};
};
return SharingProfile;
}]);

View File

@@ -0,0 +1,133 @@
/*
* 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.
*/
/**
* Service which defines the UserCredentials class.
*/
angular.module('rest').factory('UserCredentials', ['$injector', function defineUserCredentials($injector) {
// Required services
var $window = $injector.get('$window');
// Required types
var Field = $injector.get('Field');
/**
* The object returned by REST API calls to define a full set of valid
* credentials, including field definitions and corresponding expected
* values.
*
* @constructor
* @param {UserCredentials|Object} [template={}]
* The object whose properties should be copied within the new
* UserCredentials.
*/
var UserCredentials = function UserCredentials(template) {
// Use empty object by default
template = template || {};
/**
* Any parameters which should be provided when these credentials are
* submitted. If no such information is available, this will be null.
*
* @type Field[]
*/
this.expected = template.expected;
/**
* A map of all field values by field name. The fields having the names
* used within this map should be defined within the @link{Field} array
* stored under the @link{expected} property.
*
* @type Object.<String, String>
*/
this.values = template.values;
};
/**
* Generates a query string containing all QUERY_PARAMETER fields from the
* given UserCredentials object, along with their corresponding values. The
* parameter names and values will be appropriately URL-encoded and
* separated by ampersands.
*
* @param {UserCredentials} userCredentials
* The UserCredentials to retrieve all query parameters from.
*
* @returns {String}
* A string containing all QUERY_PARAMETER fields as name/value pairs
* separated by ampersands, where each name is separated by the value
* by an equals sign.
*/
UserCredentials.getQueryParameters = function getQueryParameters(userCredentials) {
// Build list of parameter name/value pairs
var parameters = [];
angular.forEach(userCredentials.expected, function addQueryParameter(field) {
// Only add query parameters
if (field.type !== Field.Type.QUERY_PARAMETER)
return;
// Pull parameter name and value
var name = field.name;
var value = userCredentials.values[name];
// Properly encode name/value pair
parameters.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
});
// Separate each name/value pair by an ampersand
return parameters.join('&');
};
/**
* Returns a fully-qualified, absolute URL to Guacamole prepopulated with
* any query parameters dictated by the QUERY_PARAMETER fields defined in
* the given UserCredentials.
*
* @param {UserCredentials} userCredentials
* The UserCredentials to retrieve all query parameters from.
*
* @returns {String}
* A fully-qualified, absolute URL to Guacamole prepopulated with the
* query parameters dictated by the given UserCredentials.
*/
UserCredentials.getLink = function getLink(userCredentials) {
// Build base link
var link = $window.location.origin
+ $window.location.pathname
+ '#/';
// Add any required parameters
var params = UserCredentials.getQueryParameters(userCredentials);
if (params)
link += '?' + params;
return link;
};
return UserCredentials;
}]);