mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
Merge pull request #252 from glyptodon/decouple-auth
GUAC-586: Support multiple auth providers within web UI
This commit is contained in:
@@ -123,6 +123,7 @@ public class ConnectionService extends ModeledGroupedDirectoryObjectService<Mode
|
|||||||
connection.setParentIdentifier(object.getParentIdentifier());
|
connection.setParentIdentifier(object.getParentIdentifier());
|
||||||
connection.setName(object.getName());
|
connection.setName(object.getName());
|
||||||
connection.setConfiguration(object.getConfiguration());
|
connection.setConfiguration(object.getConfiguration());
|
||||||
|
connection.setAttributes(object.getAttributes());
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
||||||
|
@@ -106,6 +106,7 @@ public class ConnectionGroupService extends ModeledGroupedDirectoryObjectService
|
|||||||
connectionGroup.setParentIdentifier(object.getParentIdentifier());
|
connectionGroup.setParentIdentifier(object.getParentIdentifier());
|
||||||
connectionGroup.setName(object.getName());
|
connectionGroup.setName(object.getName());
|
||||||
connectionGroup.setType(object.getType());
|
connectionGroup.setType(object.getType());
|
||||||
|
connectionGroup.setAttributes(object.getAttributes());
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
||||||
|
@@ -162,6 +162,7 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
|||||||
// Set model contents through ModeledUser, copying the provided user
|
// Set model contents through ModeledUser, copying the provided user
|
||||||
user.setIdentifier(object.getIdentifier());
|
user.setIdentifier(object.getIdentifier());
|
||||||
user.setPassword(object.getPassword());
|
user.setPassword(object.getPassword());
|
||||||
|
user.setAttributes(object.getAttributes());
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
||||||
|
@@ -33,6 +33,14 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"DATA_SOURCE_MYSQL" : {
|
||||||
|
"NAME" : "MySQL"
|
||||||
|
},
|
||||||
|
|
||||||
|
"DATA_SOURCE_POSTGRESQL" : {
|
||||||
|
"NAME" : "PostgreSQL"
|
||||||
|
},
|
||||||
|
|
||||||
"USER_ATTRIBUTES" : {
|
"USER_ATTRIBUTES" : {
|
||||||
|
|
||||||
"FIELD_HEADER_DISABLED" : "Login disabled:",
|
"FIELD_HEADER_DISABLED" : "Login disabled:",
|
||||||
|
@@ -7,6 +7,10 @@
|
|||||||
|
|
||||||
"authProviders" : [
|
"authProviders" : [
|
||||||
"net.sourceforge.guacamole.net.auth.ldap.LDAPAuthenticationProvider"
|
"net.sourceforge.guacamole.net.auth.ldap.LDAPAuthenticationProvider"
|
||||||
|
],
|
||||||
|
|
||||||
|
"translations" : [
|
||||||
|
"translations/en.json"
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
"DATA_SOURCE_LDAP" : {
|
||||||
|
"NAME" : "LDAP"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -7,6 +7,10 @@
|
|||||||
|
|
||||||
"authProviders" : [
|
"authProviders" : [
|
||||||
"net.sourceforge.guacamole.net.auth.noauth.NoAuthenticationProvider"
|
"net.sourceforge.guacamole.net.auth.noauth.NoAuthenticationProvider"
|
||||||
|
],
|
||||||
|
|
||||||
|
"translations" : [
|
||||||
|
"translations/en.json"
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
"DATA_SOURCE_NOAUTH" : {
|
||||||
|
"NAME" : "NoAuth"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -202,7 +202,7 @@ public abstract class SimpleAuthenticationProvider
|
|||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Pull cached configurations, if any
|
// Pull cached configurations, if any
|
||||||
if (authenticatedUser instanceof SimpleAuthenticatedUser)
|
if (authenticatedUser instanceof SimpleAuthenticatedUser && authenticatedUser.getAuthenticationProvider() == this)
|
||||||
return ((SimpleAuthenticatedUser) authenticatedUser).getAuthorizedConfigurations();
|
return ((SimpleAuthenticatedUser) authenticatedUser).getAuthorizedConfigurations();
|
||||||
|
|
||||||
// Otherwise, pull using credentials
|
// Otherwise, pull using credentials
|
||||||
|
@@ -115,40 +115,6 @@ public class GuacamoleSession {
|
|||||||
this.authenticatedUser = authenticatedUser;
|
this.authenticatedUser = authenticatedUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the UserContext associated with this session.
|
|
||||||
*
|
|
||||||
* @return The UserContext associated with this session.
|
|
||||||
*/
|
|
||||||
public UserContext getUserContext() {
|
|
||||||
|
|
||||||
// Warn of deprecation
|
|
||||||
logger.debug(
|
|
||||||
"\n****************************************************************"
|
|
||||||
+ "\n"
|
|
||||||
+ "\n !!!! PLEASE DO NOT USE getUserContext() !!!!"
|
|
||||||
+ "\n"
|
|
||||||
+ "\n getUserContext() has been replaced by getUserContexts(), which"
|
|
||||||
+ "\n properly handles multiple authentication providers. All use of"
|
|
||||||
+ "\n the old getUserContext() must be removed before GUAC-586 can"
|
|
||||||
+ "\n be considered complete."
|
|
||||||
+ "\n"
|
|
||||||
+ "\n****************************************************************"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Return the UserContext associated with the AuthenticationProvider
|
|
||||||
// that authenticated the current user.
|
|
||||||
String authProviderIdentifier = authenticatedUser.getAuthenticationProvider().getIdentifier();
|
|
||||||
for (UserContext userContext : userContexts) {
|
|
||||||
if (userContext.getAuthenticationProvider().getIdentifier().equals(authProviderIdentifier))
|
|
||||||
return userContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not found, return null
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of all UserContexts associated with this session. Each
|
* Returns a list of all UserContexts associated with this session. Each
|
||||||
* AuthenticationProvider currently loaded by Guacamole may provide its own
|
* AuthenticationProvider currently loaded by Guacamole may provide its own
|
||||||
|
@@ -31,7 +31,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
public class HTTPTunnelRequest implements TunnelRequest {
|
public class HTTPTunnelRequest extends TunnelRequest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The wrapped HttpServletRequest.
|
* The wrapped HttpServletRequest.
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -23,88 +23,331 @@
|
|||||||
package org.glyptodon.guacamole.net.basic;
|
package org.glyptodon.guacamole.net.basic;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||||
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request interface which provides only the functions absolutely required
|
* A request object which provides only the functions absolutely required to
|
||||||
* to retrieve and connect to a tunnel.
|
* retrieve and connect to a tunnel.
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
public interface TunnelRequest {
|
public abstract class TunnelRequest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All supported identifier types.
|
* The name of the request parameter containing the user's authentication
|
||||||
|
* token.
|
||||||
*/
|
*/
|
||||||
public static enum IdentifierType {
|
public static final String AUTH_TOKEN_PARAMETER = "token";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter containing the identifier of the
|
||||||
|
* AuthenticationProvider associated with the UserContext containing the
|
||||||
|
* object to which a tunnel is being requested.
|
||||||
|
*/
|
||||||
|
public static final String AUTH_PROVIDER_IDENTIFIER_PARAMETER = "GUAC_DATA_SOURCE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter specifying the type of object to which a
|
||||||
|
* tunnel is being requested. Currently, this may be "c" for a Guacamole
|
||||||
|
* connection, or "g" for a Guacamole connection group.
|
||||||
|
*/
|
||||||
|
public static final String TYPE_PARAMETER = "GUAC_TYPE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter containing the unique identifier of the object
|
||||||
|
* to which a tunnel is being requested.
|
||||||
|
*/
|
||||||
|
public static final String IDENTIFIER_PARAMETER = "GUAC_ID";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter containing the desired display width, in
|
||||||
|
* pixels.
|
||||||
|
*/
|
||||||
|
public static final String WIDTH_PARAMETER = "GUAC_WIDTH";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter containing the desired display height, in
|
||||||
|
* pixels.
|
||||||
|
*/
|
||||||
|
public static final String HEIGHT_PARAMETER = "GUAC_HEIGHT";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter containing the desired display resolution, in
|
||||||
|
* DPI.
|
||||||
|
*/
|
||||||
|
public static final String DPI_PARAMETER = "GUAC_DPI";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter specifying one supported audio mimetype. This
|
||||||
|
* will normally appear multiple times within a single tunnel request -
|
||||||
|
* once for each mimetype.
|
||||||
|
*/
|
||||||
|
public static final String AUDIO_PARAMETER = "GUAC_AUDIO";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter specifying one supported video mimetype. This
|
||||||
|
* will normally appear multiple times within a single tunnel request -
|
||||||
|
* once for each mimetype.
|
||||||
|
*/
|
||||||
|
public static final String VIDEO_PARAMETER = "GUAC_VIDEO";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All supported object types that can be used as the destination of a
|
||||||
|
* tunnel.
|
||||||
|
*/
|
||||||
|
public static enum Type {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unique identifier of a connection.
|
* A Guacamole connection.
|
||||||
*/
|
*/
|
||||||
CONNECTION("c/"),
|
CONNECTION("c"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unique identifier of a connection group.
|
* A Guacamole connection group.
|
||||||
*/
|
*/
|
||||||
CONNECTION_GROUP("g/");
|
CONNECTION_GROUP("g");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parameter value which denotes a destination object of this type.
|
||||||
|
*/
|
||||||
|
final String PARAMETER_VALUE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The prefix which precedes an identifier of this type.
|
* Defines a Type having the given corresponding parameter value.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The parameter value which denotes a destination object of this
|
||||||
|
* type.
|
||||||
*/
|
*/
|
||||||
final String PREFIX;
|
Type(String value) {
|
||||||
|
PARAMETER_VALUE = value;
|
||||||
/**
|
|
||||||
* Defines an IdentifierType having the given prefix.
|
|
||||||
* @param prefix The prefix which will precede any identifier of this
|
|
||||||
* type, thus differentiating it from other identifier
|
|
||||||
* types.
|
|
||||||
*/
|
|
||||||
IdentifierType(String prefix) {
|
|
||||||
PREFIX = prefix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an identifier, determines the corresponding identifier type.
|
|
||||||
*
|
|
||||||
* @param identifier The identifier whose type should be identified.
|
|
||||||
* @return The identified identifier type.
|
|
||||||
*/
|
|
||||||
static IdentifierType getType(String identifier) {
|
|
||||||
|
|
||||||
// If null, no known identifier
|
|
||||||
if (identifier == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Connection identifiers
|
|
||||||
if (identifier.startsWith(CONNECTION.PREFIX))
|
|
||||||
return CONNECTION;
|
|
||||||
|
|
||||||
// Connection group identifiers
|
|
||||||
if (identifier.startsWith(CONNECTION_GROUP.PREFIX))
|
|
||||||
return CONNECTION_GROUP;
|
|
||||||
|
|
||||||
// Otherwise, unknown
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value of the parameter having the given name.
|
* Returns the value of the parameter having the given name.
|
||||||
*
|
*
|
||||||
* @param name The name of the parameter to return.
|
* @param name
|
||||||
* @return The value of the parameter having the given name, or null
|
* The name of the parameter to return.
|
||||||
* if no such parameter was specified.
|
*
|
||||||
|
* @return
|
||||||
|
* The value of the parameter having the given name, or null if no such
|
||||||
|
* parameter was specified.
|
||||||
*/
|
*/
|
||||||
public String getParameter(String name);
|
public abstract String getParameter(String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of all values specified for the given parameter.
|
* Returns a list of all values specified for the given parameter.
|
||||||
*
|
*
|
||||||
* @param name The name of the parameter to return.
|
* @param name
|
||||||
* @return All values of the parameter having the given name , or null
|
* The name of the parameter to return.
|
||||||
* if no such parameter was specified.
|
*
|
||||||
|
* @return
|
||||||
|
* All values of the parameter having the given name , or null if no
|
||||||
|
* such parameter was specified.
|
||||||
*/
|
*/
|
||||||
public List<String> getParameterValues(String name);
|
public abstract List<String> getParameterValues(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the parameter having the given name, throwing an
|
||||||
|
* exception if the parameter is missing.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the parameter to return.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The value of the parameter having the given name.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the parameter is not present in the request.
|
||||||
|
*/
|
||||||
|
public String getRequiredParameter(String name) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Pull requested parameter, aborting if absent
|
||||||
|
String value = getParameter(name);
|
||||||
|
if (value == null)
|
||||||
|
throw new GuacamoleClientException("Parameter \"" + name + "\" is required.");
|
||||||
|
|
||||||
|
return value;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the integer value of the parameter having the given name,
|
||||||
|
* throwing an exception if the parameter cannot be parsed.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the parameter to return.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The integer value of the parameter having the given name, or null if
|
||||||
|
* the parameter is missing.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the parameter is not a valid integer.
|
||||||
|
*/
|
||||||
|
public Integer getIntegerParameter(String name) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Pull requested parameter
|
||||||
|
String value = getParameter(name);
|
||||||
|
if (value == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Attempt to parse as an integer
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rethrow any parsing error as a GuacamoleClientException
|
||||||
|
catch (NumberFormatException e) {
|
||||||
|
throw new GuacamoleClientException("Parameter \"" + name + "\" must be a valid integer.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the authentication token associated with this tunnel request.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The authentication token associated with this tunnel request, or
|
||||||
|
* null if no authentication token is present.
|
||||||
|
*/
|
||||||
|
public String getAuthenticationToken() {
|
||||||
|
return getParameter(AUTH_TOKEN_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the identifier of the AuthenticationProvider associated with the
|
||||||
|
* UserContext from which the connection or connection group is to be
|
||||||
|
* retrieved when the tunnel is created. In the context of the REST API and
|
||||||
|
* the JavaScript side of the web application, this is referred to as the
|
||||||
|
* data source identifier.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The identifier of the AuthenticationProvider associated with the
|
||||||
|
* UserContext from which the connection or connection group is to be
|
||||||
|
* retrieved when the tunnel is created.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the identifier was not present in the request.
|
||||||
|
*/
|
||||||
|
public String getAuthenticationProviderIdentifier()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return getRequiredParameter(AUTH_PROVIDER_IDENTIFIER_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of object for which the tunnel is being requested.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The type of object for which the tunnel is being requested.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the type was not present in the request, or if the type requested
|
||||||
|
* is in the wrong format.
|
||||||
|
*/
|
||||||
|
public Type getType() throws GuacamoleException {
|
||||||
|
|
||||||
|
String type = getRequiredParameter(TYPE_PARAMETER);
|
||||||
|
|
||||||
|
// For each possible object type
|
||||||
|
for (Type possibleType : Type.values()) {
|
||||||
|
|
||||||
|
// Match against defined parameter value
|
||||||
|
if (type.equals(possibleType.PARAMETER_VALUE))
|
||||||
|
return possibleType;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new GuacamoleClientException("Illegal identifier - unknown type.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the identifier of the destination of the tunnel being requested.
|
||||||
|
* As there are multiple types of destination objects available, and within
|
||||||
|
* multiple data sources, the associated object type and data source are
|
||||||
|
* also necessary to determine what this identifier refers to.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The identifier of the destination of the tunnel being requested.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the identifier was not present in the request.
|
||||||
|
*/
|
||||||
|
public String getIdentifier() throws GuacamoleException {
|
||||||
|
return getRequiredParameter(IDENTIFIER_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the display width desired for the Guacamole session over the
|
||||||
|
* tunnel being requested.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The display width desired for the Guacamole session over the tunnel
|
||||||
|
* being requested, or null if no width was given.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the width specified was not a valid integer.
|
||||||
|
*/
|
||||||
|
public Integer getWidth() throws GuacamoleException {
|
||||||
|
return getIntegerParameter(WIDTH_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the display height desired for the Guacamole session over the
|
||||||
|
* tunnel being requested.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The display height desired for the Guacamole session over the tunnel
|
||||||
|
* being requested, or null if no width was given.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the height specified was not a valid integer.
|
||||||
|
*/
|
||||||
|
public Integer getHeight() throws GuacamoleException {
|
||||||
|
return getIntegerParameter(HEIGHT_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the display resolution desired for the Guacamole session over
|
||||||
|
* the tunnel being requested, in DPI.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The display resolution desired for the Guacamole session over the
|
||||||
|
* tunnel being requested, or null if no resolution was given.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the resolution specified was not a valid integer.
|
||||||
|
*/
|
||||||
|
public Integer getDPI() throws GuacamoleException {
|
||||||
|
return getIntegerParameter(DPI_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all audio mimetypes declared as supported within the
|
||||||
|
* tunnel request.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A list of all audio mimetypes declared as supported within the
|
||||||
|
* tunnel request, or null if no mimetypes were specified.
|
||||||
|
*/
|
||||||
|
public List<String> getAudioMimetypes() {
|
||||||
|
return getParameterValues(AUDIO_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all video mimetypes declared as supported within the
|
||||||
|
* tunnel request.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A list of all video mimetypes declared as supported within the
|
||||||
|
* tunnel request, or null if no mimetypes were specified.
|
||||||
|
*/
|
||||||
|
public List<String> getVideoMimetypes() {
|
||||||
|
return getParameterValues(VIDEO_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -25,16 +25,15 @@ package org.glyptodon.guacamole.net.basic;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||||
import org.glyptodon.guacamole.environment.Environment;
|
|
||||||
import org.glyptodon.guacamole.net.DelegatingGuacamoleTunnel;
|
import org.glyptodon.guacamole.net.DelegatingGuacamoleTunnel;
|
||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||||
import org.glyptodon.guacamole.net.auth.Connection;
|
import org.glyptodon.guacamole.net.auth.Connection;
|
||||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||||
import org.glyptodon.guacamole.net.auth.Directory;
|
import org.glyptodon.guacamole.net.auth.Directory;
|
||||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
|
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||||
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -53,12 +52,6 @@ import org.slf4j.LoggerFactory;
|
|||||||
@Singleton
|
@Singleton
|
||||||
public class TunnelRequestService {
|
public class TunnelRequestService {
|
||||||
|
|
||||||
/**
|
|
||||||
* The Guacamole server environment.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private Environment environment;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger for this class.
|
* Logger for this class.
|
||||||
*/
|
*/
|
||||||
@@ -70,6 +63,12 @@ public class TunnelRequestService {
|
|||||||
@Inject
|
@Inject
|
||||||
private AuthenticationService authenticationService;
|
private AuthenticationService authenticationService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for convenient retrieval of objects.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private ObjectRetrievalService retrievalService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads and returns the client information provided within the given
|
* Reads and returns the client information provided within the given
|
||||||
* request.
|
* request.
|
||||||
@@ -80,35 +79,40 @@ public class TunnelRequestService {
|
|||||||
* @return GuacamoleClientInformation
|
* @return GuacamoleClientInformation
|
||||||
* An object containing information about the client sending the tunnel
|
* An object containing information about the client sending the tunnel
|
||||||
* request.
|
* request.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the parameters of the tunnel request are invalid.
|
||||||
*/
|
*/
|
||||||
protected GuacamoleClientInformation getClientInformation(TunnelRequest request) {
|
protected GuacamoleClientInformation getClientInformation(TunnelRequest request)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Get client information
|
// Get client information
|
||||||
GuacamoleClientInformation info = new GuacamoleClientInformation();
|
GuacamoleClientInformation info = new GuacamoleClientInformation();
|
||||||
|
|
||||||
// Set width if provided
|
// Set width if provided
|
||||||
String width = request.getParameter("width");
|
Integer width = request.getWidth();
|
||||||
if (width != null)
|
if (width != null)
|
||||||
info.setOptimalScreenWidth(Integer.parseInt(width));
|
info.setOptimalScreenWidth(width);
|
||||||
|
|
||||||
// Set height if provided
|
// Set height if provided
|
||||||
String height = request.getParameter("height");
|
Integer height = request.getHeight();
|
||||||
if (height != null)
|
if (height != null)
|
||||||
info.setOptimalScreenHeight(Integer.parseInt(height));
|
info.setOptimalScreenHeight(height);
|
||||||
|
|
||||||
// Set resolution if provided
|
// Set resolution if provided
|
||||||
String dpi = request.getParameter("dpi");
|
Integer dpi = request.getDPI();
|
||||||
if (dpi != null)
|
if (dpi != null)
|
||||||
info.setOptimalResolution(Integer.parseInt(dpi));
|
info.setOptimalResolution(dpi);
|
||||||
|
|
||||||
// Add audio mimetypes
|
// Add audio mimetypes
|
||||||
List<String> audio_mimetypes = request.getParameterValues("audio");
|
List<String> audioMimetypes = request.getAudioMimetypes();
|
||||||
if (audio_mimetypes != null)
|
if (audioMimetypes != null)
|
||||||
info.getAudioMimetypes().addAll(audio_mimetypes);
|
info.getAudioMimetypes().addAll(audioMimetypes);
|
||||||
|
|
||||||
// Add video mimetypes
|
// Add video mimetypes
|
||||||
List<String> video_mimetypes = request.getParameterValues("video");
|
List<String> videoMimetypes = request.getVideoMimetypes();
|
||||||
if (video_mimetypes != null)
|
if (videoMimetypes != null)
|
||||||
info.getVideoMimetypes().addAll(video_mimetypes);
|
info.getVideoMimetypes().addAll(videoMimetypes);
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@@ -122,7 +126,7 @@ public class TunnelRequestService {
|
|||||||
* The UserContext associated with the user for whom the tunnel is
|
* The UserContext associated with the user for whom the tunnel is
|
||||||
* being created.
|
* being created.
|
||||||
*
|
*
|
||||||
* @param idType
|
* @param type
|
||||||
* The type of object being connected to (connection or group).
|
* The type of object being connected to (connection or group).
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id
|
||||||
@@ -138,13 +142,13 @@ public class TunnelRequestService {
|
|||||||
* If an error occurs while creating the tunnel.
|
* If an error occurs while creating the tunnel.
|
||||||
*/
|
*/
|
||||||
protected GuacamoleTunnel createConnectedTunnel(UserContext context,
|
protected GuacamoleTunnel createConnectedTunnel(UserContext context,
|
||||||
final TunnelRequest.IdentifierType idType, String id,
|
final TunnelRequest.Type type, String id,
|
||||||
GuacamoleClientInformation info)
|
GuacamoleClientInformation info)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Create connected tunnel from identifier
|
// Create connected tunnel from identifier
|
||||||
GuacamoleTunnel tunnel = null;
|
GuacamoleTunnel tunnel = null;
|
||||||
switch (idType) {
|
switch (type) {
|
||||||
|
|
||||||
// Connection identifiers
|
// Connection identifiers
|
||||||
case CONNECTION: {
|
case CONNECTION: {
|
||||||
@@ -205,7 +209,7 @@ public class TunnelRequestService {
|
|||||||
* @param session
|
* @param session
|
||||||
* The Guacamole session to associate the tunnel with.
|
* The Guacamole session to associate the tunnel with.
|
||||||
*
|
*
|
||||||
* @param idType
|
* @param type
|
||||||
* The type of object being connected to (connection or group).
|
* The type of object being connected to (connection or group).
|
||||||
*
|
*
|
||||||
* @param id
|
* @param id
|
||||||
@@ -220,7 +224,7 @@ public class TunnelRequestService {
|
|||||||
* If an error occurs while obtaining the tunnel.
|
* If an error occurs while obtaining the tunnel.
|
||||||
*/
|
*/
|
||||||
protected GuacamoleTunnel createAssociatedTunnel(final GuacamoleSession session,
|
protected GuacamoleTunnel createAssociatedTunnel(final GuacamoleSession session,
|
||||||
GuacamoleTunnel tunnel, final TunnelRequest.IdentifierType idType,
|
GuacamoleTunnel tunnel, final TunnelRequest.Type type,
|
||||||
final String id) throws GuacamoleException {
|
final String id) throws GuacamoleException {
|
||||||
|
|
||||||
// Monitor tunnel closure and data
|
// Monitor tunnel closure and data
|
||||||
@@ -239,7 +243,7 @@ public class TunnelRequestService {
|
|||||||
long duration = connectionEndTime - connectionStartTime;
|
long duration = connectionEndTime - connectionStartTime;
|
||||||
|
|
||||||
// Log closure
|
// Log closure
|
||||||
switch (idType) {
|
switch (type) {
|
||||||
|
|
||||||
// Connection identifiers
|
// Connection identifiers
|
||||||
case CONNECTION:
|
case CONNECTION:
|
||||||
@@ -289,27 +293,20 @@ public class TunnelRequestService {
|
|||||||
public GuacamoleTunnel createTunnel(TunnelRequest request)
|
public GuacamoleTunnel createTunnel(TunnelRequest request)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Get auth token and session
|
// Parse request parameters
|
||||||
final String authToken = request.getParameter("authToken");
|
String authToken = request.getAuthenticationToken();
|
||||||
final GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
String id = request.getIdentifier();
|
||||||
|
TunnelRequest.Type type = request.getType();
|
||||||
// Get client information and connection ID from request
|
String authProviderIdentifier = request.getAuthenticationProviderIdentifier();
|
||||||
String id = request.getParameter("id");
|
GuacamoleClientInformation info = getClientInformation(request);
|
||||||
final GuacamoleClientInformation info = getClientInformation(request);
|
|
||||||
|
|
||||||
// Determine ID type
|
|
||||||
TunnelRequest.IdentifierType idType = TunnelRequest.IdentifierType.getType(id);
|
|
||||||
if (idType == null)
|
|
||||||
throw new GuacamoleClientException("Illegal identifier - unknown type.");
|
|
||||||
|
|
||||||
// Remove prefix
|
|
||||||
id = id.substring(idType.PREFIX.length());
|
|
||||||
|
|
||||||
// Create connected tunnel using provided connection ID and client information
|
// Create connected tunnel using provided connection ID and client information
|
||||||
final GuacamoleTunnel tunnel = createConnectedTunnel(session.getUserContext(), idType, id, info);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
GuacamoleTunnel tunnel = createConnectedTunnel(userContext, type, id, info);
|
||||||
|
|
||||||
// Associate tunnel with session
|
// Associate tunnel with session
|
||||||
return createAssociatedTunnel(session, tunnel, idType, id);
|
return createAssociatedTunnel(session, tunnel, type, id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -333,7 +333,10 @@ public class ExtensionModule extends ServletModule {
|
|||||||
logger.warn("Although GUACAMOLE_HOME/" + EXTENSIONS_DIRECTORY + " exists, its contents cannot be read.");
|
logger.warn("Although GUACAMOLE_HOME/" + EXTENSIONS_DIRECTORY + " exists, its contents cannot be read.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort files lexicographically
|
||||||
|
Arrays.sort(extensionFiles);
|
||||||
|
|
||||||
// Load each extension within the extension directory
|
// Load each extension within the extension directory
|
||||||
for (File extensionFile : extensionFiles) {
|
for (File extensionFile : extensionFiles) {
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@ package org.glyptodon.guacamole.net.basic.rest;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
|
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
|
||||||
|
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||||
import org.glyptodon.guacamole.net.auth.Connection;
|
import org.glyptodon.guacamole.net.auth.Connection;
|
||||||
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
||||||
import org.glyptodon.guacamole.net.auth.Directory;
|
import org.glyptodon.guacamole.net.auth.Directory;
|
||||||
@@ -48,9 +49,9 @@ public class ObjectRetrievalService {
|
|||||||
* @param session
|
* @param session
|
||||||
* The GuacamoleSession to retrieve the UserContext from.
|
* The GuacamoleSession to retrieve the UserContext from.
|
||||||
*
|
*
|
||||||
* @param identifier
|
* @param authProviderIdentifier
|
||||||
* The unique identifier of the AuthenticationProvider that created the
|
* The unique identifier of the AuthenticationProvider that created the
|
||||||
* UserContext being retrieved. Only one UserContext per
|
* UserContext being retrieved. Only one UserContext per User per
|
||||||
* AuthenticationProvider can exist.
|
* AuthenticationProvider can exist.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
@@ -62,7 +63,7 @@ public class ObjectRetrievalService {
|
|||||||
* UserContext does not exist.
|
* UserContext does not exist.
|
||||||
*/
|
*/
|
||||||
public UserContext retrieveUserContext(GuacamoleSession session,
|
public UserContext retrieveUserContext(GuacamoleSession session,
|
||||||
String identifier) throws GuacamoleException {
|
String authProviderIdentifier) throws GuacamoleException {
|
||||||
|
|
||||||
// Get list of UserContexts
|
// Get list of UserContexts
|
||||||
List<UserContext> userContexts = session.getUserContexts();
|
List<UserContext> userContexts = session.getUserContexts();
|
||||||
@@ -70,11 +71,17 @@ public class ObjectRetrievalService {
|
|||||||
// Locate and return the UserContext associated with the
|
// Locate and return the UserContext associated with the
|
||||||
// AuthenticationProvider having the given identifier, if any
|
// AuthenticationProvider having the given identifier, if any
|
||||||
for (UserContext userContext : userContexts) {
|
for (UserContext userContext : userContexts) {
|
||||||
if (userContext.getAuthenticationProvider().getIdentifier().equals(identifier))
|
|
||||||
|
// Get AuthenticationProvider associated with current UserContext
|
||||||
|
AuthenticationProvider authProvider = userContext.getAuthenticationProvider();
|
||||||
|
|
||||||
|
// If AuthenticationProvider identifier matches, done
|
||||||
|
if (authProvider.getIdentifier().equals(authProviderIdentifier))
|
||||||
return userContext;
|
return userContext;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new GuacamoleResourceNotFoundException("Session not associated with authentication provider \"" + identifier + "\".");
|
throw new GuacamoleResourceNotFoundException("Session not associated with authentication provider \"" + authProviderIdentifier + "\".");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +116,35 @@ public class ObjectRetrievalService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a single user from the given GuacamoleSession.
|
||||||
|
*
|
||||||
|
* @param session
|
||||||
|
* The GuacamoleSession to retrieve the user from.
|
||||||
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider that created the
|
||||||
|
* UserContext from which the user should be retrieved. Only one
|
||||||
|
* UserContext per User per AuthenticationProvider can exist.
|
||||||
|
*
|
||||||
|
* @param identifier
|
||||||
|
* The identifier of the user to retrieve.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The user having the given identifier.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while retrieving the user, or if the
|
||||||
|
* user does not exist.
|
||||||
|
*/
|
||||||
|
public User retrieveUser(GuacamoleSession session, String authProviderIdentifier,
|
||||||
|
String identifier) throws GuacamoleException {
|
||||||
|
|
||||||
|
UserContext userContext = retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
return retrieveUser(userContext, identifier);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a single connection from the given user context.
|
* Retrieves a single connection from the given user context.
|
||||||
*
|
*
|
||||||
@@ -140,6 +176,36 @@ public class ObjectRetrievalService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a single connection from the given GuacamoleSession.
|
||||||
|
*
|
||||||
|
* @param session
|
||||||
|
* The GuacamoleSession to retrieve the connection from.
|
||||||
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider that created the
|
||||||
|
* UserContext from which the connection should be retrieved. Only one
|
||||||
|
* UserContext per User per AuthenticationProvider can exist.
|
||||||
|
*
|
||||||
|
* @param identifier
|
||||||
|
* The identifier of the connection to retrieve.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The connection having the given identifier.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while retrieving the connection, or if the
|
||||||
|
* connection does not exist.
|
||||||
|
*/
|
||||||
|
public Connection retrieveConnection(GuacamoleSession session,
|
||||||
|
String authProviderIdentifier, String identifier)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
UserContext userContext = retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
return retrieveConnection(userContext, identifier);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a single connection group from the given user context. If
|
* Retrieves a single connection group from the given user context. If
|
||||||
* the given identifier the REST API root identifier, the root connection
|
* the given identifier the REST API root identifier, the root connection
|
||||||
@@ -178,4 +244,37 @@ public class ObjectRetrievalService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a single connection group from the given GuacamoleSession. If
|
||||||
|
* the given identifier is the REST API root identifier, the root
|
||||||
|
* connection group will be returned. The underlying authentication
|
||||||
|
* provider may additionally use a different identifier for root.
|
||||||
|
*
|
||||||
|
* @param session
|
||||||
|
* The GuacamoleSession to retrieve the connection group from.
|
||||||
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider that created the
|
||||||
|
* UserContext from which the connection group should be retrieved.
|
||||||
|
* Only one UserContext per User per AuthenticationProvider can exist.
|
||||||
|
*
|
||||||
|
* @param identifier
|
||||||
|
* The identifier of the connection group to retrieve.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The connection group having the given identifier, or the root
|
||||||
|
* connection group if the identifier is the root identifier.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while retrieving the connection group, or if the
|
||||||
|
* connection group does not exist.
|
||||||
|
*/
|
||||||
|
public ConnectionGroup retrieveConnectionGroup(GuacamoleSession session,
|
||||||
|
String authProviderIdentifier, String identifier) throws GuacamoleException {
|
||||||
|
|
||||||
|
UserContext userContext = retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
return retrieveConnectionGroup(userContext, identifier);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -30,6 +30,7 @@ import java.util.Map;
|
|||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
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;
|
||||||
@@ -44,8 +45,10 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
|||||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
||||||
|
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.APIPatch;
|
import org.glyptodon.guacamole.net.basic.rest.APIPatch;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||||
|
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.PATCH;
|
import org.glyptodon.guacamole.net.basic.rest.PATCH;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -56,7 +59,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
@Path("/activeConnections")
|
@Path("/data/{dataSource}/activeConnections")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public class ActiveConnectionRESTService {
|
public class ActiveConnectionRESTService {
|
||||||
@@ -72,6 +75,12 @@ public class ActiveConnectionRESTService {
|
|||||||
@Inject
|
@Inject
|
||||||
private AuthenticationService authenticationService;
|
private AuthenticationService authenticationService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for convenient retrieval of objects.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private ObjectRetrievalService retrievalService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of active connections in the system, filtering the returned
|
* Gets a list of active connections in the system, filtering the returned
|
||||||
* list by the given permissions, if specified.
|
* list by the given permissions, if specified.
|
||||||
@@ -80,6 +89,10 @@ public class ActiveConnectionRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the active connections to be retrieved.
|
||||||
|
*
|
||||||
* @param permissions
|
* @param permissions
|
||||||
* The set of permissions to filter with. A user must have one or more
|
* The set of permissions to filter with. A user must have one or more
|
||||||
* of these permissions for a user to appear in the result.
|
* of these permissions for a user to appear in the result.
|
||||||
@@ -96,10 +109,12 @@ public class ActiveConnectionRESTService {
|
|||||||
@GET
|
@GET
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public Map<String, APIActiveConnection> getActiveConnections(@QueryParam("token") String authToken,
|
public Map<String, APIActiveConnection> getActiveConnections(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
@QueryParam("permission") List<ObjectPermission.Type> permissions)
|
@QueryParam("permission") List<ObjectPermission.Type> permissions)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
User self = userContext.self();
|
User self = userContext.self();
|
||||||
|
|
||||||
// Do not filter on permissions if no permissions are specified
|
// Do not filter on permissions if no permissions are specified
|
||||||
@@ -140,6 +155,10 @@ public class ActiveConnectionRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the active connections to be deleted.
|
||||||
|
*
|
||||||
* @param patches
|
* @param patches
|
||||||
* The active connection patches to apply for this request.
|
* The active connection patches to apply for this request.
|
||||||
*
|
*
|
||||||
@@ -149,9 +168,11 @@ public class ActiveConnectionRESTService {
|
|||||||
@PATCH
|
@PATCH
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public void patchTunnels(@QueryParam("token") String authToken,
|
public void patchTunnels(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
List<APIPatch<String>> patches) throws GuacamoleException {
|
List<APIPatch<String>> patches) throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Get the directory
|
// Get the directory
|
||||||
Directory<ActiveConnection> activeConnectionDirectory = userContext.getActiveConnectionDirectory();
|
Directory<ActiveConnection> activeConnectionDirectory = userContext.getActiveConnectionDirectory();
|
||||||
|
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.glyptodon.guacamole.net.basic.rest.auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple object to represent an auth token/username pair in the API.
|
||||||
|
*
|
||||||
|
* @author James Muehlner
|
||||||
|
*/
|
||||||
|
public class APIAuthenticationResponse {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The auth token.
|
||||||
|
*/
|
||||||
|
private final String authToken;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username of the user that authenticated.
|
||||||
|
*/
|
||||||
|
private final String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of the data source from which this user account
|
||||||
|
* came. Although this user account may exist across several data sources
|
||||||
|
* (AuthenticationProviders), this will be the unique identifier of the
|
||||||
|
* AuthenticationProvider that authenticated this user for the current
|
||||||
|
* session.
|
||||||
|
*/
|
||||||
|
private final String dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unique authentication token which identifies the current
|
||||||
|
* session.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The user's authentication token.
|
||||||
|
*/
|
||||||
|
public String getAuthToken() {
|
||||||
|
return authToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the user identified by the authentication token associated with
|
||||||
|
* the current session.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The user identified by this authentication token.
|
||||||
|
*/
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unique identifier of the data source associated with the user
|
||||||
|
* account associated with this auth token.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The unique identifier of the data source associated with the user
|
||||||
|
* account associated with this auth token.
|
||||||
|
*/
|
||||||
|
public String getDataSource() {
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new APIAuthToken Object with the given auth token.
|
||||||
|
*
|
||||||
|
* @param dataSource
|
||||||
|
* The unique identifier of the AuthenticationProvider which
|
||||||
|
* authenticated the user.
|
||||||
|
*
|
||||||
|
* @param authToken
|
||||||
|
* The auth token to create the new APIAuthToken with.
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* The username of the user owning the given token.
|
||||||
|
*/
|
||||||
|
public APIAuthenticationResponse(String dataSource, String authToken, String username) {
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
this.authToken = authToken;
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -66,19 +66,6 @@ public class AuthenticationService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the UserContext for a given auth token, if the auth token represents
|
|
||||||
* a currently logged in user. Throws an unauthorized error otherwise.
|
|
||||||
*
|
|
||||||
* @param authToken The auth token to check against the map of logged in users.
|
|
||||||
* @return The user context that corresponds to the provided auth token.
|
|
||||||
* @throws GuacamoleException If the auth token does not correspond to any
|
|
||||||
* logged in user.
|
|
||||||
*/
|
|
||||||
public UserContext getUserContext(String authToken) throws GuacamoleException {
|
|
||||||
return getGuacamoleSession(authToken).getUserContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all UserContexts associated with a given auth token, if the auth
|
* Returns all UserContexts associated with a given auth token, if the auth
|
||||||
* token represents a currently logged in user. Throws an unauthorized
|
* token represents a currently logged in user. Throws an unauthorized
|
||||||
|
@@ -48,6 +48,7 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
|||||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
||||||
|
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
|
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||||
@@ -60,7 +61,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author James Muehlner
|
* @author James Muehlner
|
||||||
*/
|
*/
|
||||||
@Path("/connections")
|
@Path("/data/{dataSource}/connections")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public class ConnectionRESTService {
|
public class ConnectionRESTService {
|
||||||
@@ -89,6 +90,10 @@ public class ConnectionRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the connection to be retrieved.
|
||||||
|
*
|
||||||
* @param connectionID
|
* @param connectionID
|
||||||
* The identifier of the connection to retrieve.
|
* The identifier of the connection to retrieve.
|
||||||
*
|
*
|
||||||
@@ -102,12 +107,14 @@ public class ConnectionRESTService {
|
|||||||
@Path("/{connectionID}")
|
@Path("/{connectionID}")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public APIConnection getConnection(@QueryParam("token") String authToken,
|
public APIConnection getConnection(@QueryParam("token") String authToken,
|
||||||
@PathParam("connectionID") String connectionID) throws GuacamoleException {
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("connectionID") String connectionID)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
|
||||||
// Retrieve the requested connection
|
// Retrieve the requested connection
|
||||||
return new APIConnection(retrievalService.retrieveConnection(userContext, connectionID));
|
return new APIConnection(retrievalService.retrieveConnection(session, authProviderIdentifier, connectionID));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +125,11 @@ public class ConnectionRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the connection whose parameters are to be
|
||||||
|
* retrieved.
|
||||||
|
*
|
||||||
* @param connectionID
|
* @param connectionID
|
||||||
* The identifier of the connection.
|
* The identifier of the connection.
|
||||||
*
|
*
|
||||||
@@ -131,9 +143,12 @@ public class ConnectionRESTService {
|
|||||||
@Path("/{connectionID}/parameters")
|
@Path("/{connectionID}/parameters")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public Map<String, String> getConnectionParameters(@QueryParam("token") String authToken,
|
public Map<String, String> getConnectionParameters(@QueryParam("token") String authToken,
|
||||||
@PathParam("connectionID") String connectionID) throws GuacamoleException {
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("connectionID") String connectionID)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
User self = userContext.self();
|
User self = userContext.self();
|
||||||
|
|
||||||
// Retrieve permission sets
|
// Retrieve permission sets
|
||||||
@@ -163,6 +178,11 @@ public class ConnectionRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the connection whose history is to be
|
||||||
|
* retrieved.
|
||||||
|
*
|
||||||
* @param connectionID
|
* @param connectionID
|
||||||
* The identifier of the connection.
|
* The identifier of the connection.
|
||||||
*
|
*
|
||||||
@@ -177,12 +197,14 @@ public class ConnectionRESTService {
|
|||||||
@Path("/{connectionID}/history")
|
@Path("/{connectionID}/history")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public List<APIConnectionRecord> getConnectionHistory(@QueryParam("token") String authToken,
|
public List<APIConnectionRecord> getConnectionHistory(@QueryParam("token") String authToken,
|
||||||
@PathParam("connectionID") String connectionID) throws GuacamoleException {
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("connectionID") String connectionID)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
|
||||||
|
|
||||||
// Retrieve the requested connection
|
// Retrieve the requested connection
|
||||||
Connection connection = retrievalService.retrieveConnection(userContext, connectionID);
|
Connection connection = retrievalService.retrieveConnection(session, authProviderIdentifier, connectionID);
|
||||||
|
|
||||||
// Retrieve the requested connection's history
|
// Retrieve the requested connection's history
|
||||||
List<APIConnectionRecord> apiRecords = new ArrayList<APIConnectionRecord>();
|
List<APIConnectionRecord> apiRecords = new ArrayList<APIConnectionRecord>();
|
||||||
@@ -201,6 +223,10 @@ public class ConnectionRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the connection to be deleted.
|
||||||
|
*
|
||||||
* @param connectionID
|
* @param connectionID
|
||||||
* The identifier of the connection to delete.
|
* The identifier of the connection to delete.
|
||||||
*
|
*
|
||||||
@@ -210,10 +236,13 @@ public class ConnectionRESTService {
|
|||||||
@DELETE
|
@DELETE
|
||||||
@Path("/{connectionID}")
|
@Path("/{connectionID}")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public void deleteConnection(@QueryParam("token") String authToken, @PathParam("connectionID") String connectionID)
|
public void deleteConnection(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("connectionID") String connectionID)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Get the connection directory
|
// Get the connection directory
|
||||||
Directory<Connection> connectionDirectory = userContext.getConnectionDirectory();
|
Directory<Connection> connectionDirectory = userContext.getConnectionDirectory();
|
||||||
@@ -231,6 +260,10 @@ public class ConnectionRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext in which the connection is to be created.
|
||||||
|
*
|
||||||
* @param connection
|
* @param connection
|
||||||
* The connection to create.
|
* The connection to create.
|
||||||
*
|
*
|
||||||
@@ -244,9 +277,11 @@ public class ConnectionRESTService {
|
|||||||
@Produces(MediaType.TEXT_PLAIN)
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public String createConnection(@QueryParam("token") String authToken,
|
public String createConnection(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
APIConnection connection) throws GuacamoleException {
|
APIConnection connection) throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Validate that connection data was provided
|
// Validate that connection data was provided
|
||||||
if (connection == null)
|
if (connection == null)
|
||||||
@@ -270,6 +305,10 @@ public class ConnectionRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the connection to be updated.
|
||||||
|
*
|
||||||
* @param connectionID
|
* @param connectionID
|
||||||
* The identifier of the connection to update.
|
* The identifier of the connection to update.
|
||||||
*
|
*
|
||||||
@@ -283,9 +322,12 @@ public class ConnectionRESTService {
|
|||||||
@Path("/{connectionID}")
|
@Path("/{connectionID}")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public void updateConnection(@QueryParam("token") String authToken,
|
public void updateConnection(@QueryParam("token") String authToken,
|
||||||
@PathParam("connectionID") String connectionID, APIConnection connection) throws GuacamoleException {
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("connectionID") String connectionID,
|
||||||
|
APIConnection connection) throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Validate that connection data was provided
|
// Validate that connection data was provided
|
||||||
if (connection == null)
|
if (connection == null)
|
||||||
|
@@ -40,6 +40,7 @@ import org.glyptodon.guacamole.net.auth.ConnectionGroup;
|
|||||||
import org.glyptodon.guacamole.net.auth.Directory;
|
import org.glyptodon.guacamole.net.auth.Directory;
|
||||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||||
|
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
|
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||||
@@ -51,7 +52,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author James Muehlner
|
* @author James Muehlner
|
||||||
*/
|
*/
|
||||||
@Path("/connectionGroups")
|
@Path("/data/{dataSource}/connectionGroups")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public class ConnectionGroupRESTService {
|
public class ConnectionGroupRESTService {
|
||||||
@@ -80,6 +81,10 @@ public class ConnectionGroupRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the connection group to be retrieved.
|
||||||
|
*
|
||||||
* @param connectionGroupID
|
* @param connectionGroupID
|
||||||
* The ID of the connection group to retrieve.
|
* The ID of the connection group to retrieve.
|
||||||
*
|
*
|
||||||
@@ -92,13 +97,15 @@ public class ConnectionGroupRESTService {
|
|||||||
@GET
|
@GET
|
||||||
@Path("/{connectionGroupID}")
|
@Path("/{connectionGroupID}")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public APIConnectionGroup getConnectionGroup(@QueryParam("token") String authToken,
|
public APIConnectionGroup getConnectionGroup(@QueryParam("token") String authToken,
|
||||||
@PathParam("connectionGroupID") String connectionGroupID) throws GuacamoleException {
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("connectionGroupID") String connectionGroupID)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
|
||||||
// Retrieve the requested connection group
|
// Retrieve the requested connection group
|
||||||
return new APIConnectionGroup(retrievalService.retrieveConnectionGroup(userContext, connectionGroupID));
|
return new APIConnectionGroup(retrievalService.retrieveConnectionGroup(session, authProviderIdentifier, connectionGroupID));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +116,10 @@ public class ConnectionGroupRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the connection group to be retrieved.
|
||||||
|
*
|
||||||
* @param connectionGroupID
|
* @param connectionGroupID
|
||||||
* The ID of the connection group to retrieve.
|
* The ID of the connection group to retrieve.
|
||||||
*
|
*
|
||||||
@@ -129,11 +140,13 @@ public class ConnectionGroupRESTService {
|
|||||||
@Path("/{connectionGroupID}/tree")
|
@Path("/{connectionGroupID}/tree")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public APIConnectionGroup getConnectionGroupTree(@QueryParam("token") String authToken,
|
public APIConnectionGroup getConnectionGroupTree(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
@PathParam("connectionGroupID") String connectionGroupID,
|
@PathParam("connectionGroupID") String connectionGroupID,
|
||||||
@QueryParam("permission") List<ObjectPermission.Type> permissions)
|
@QueryParam("permission") List<ObjectPermission.Type> permissions)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Retrieve the requested tree, filtering by the given permissions
|
// Retrieve the requested tree, filtering by the given permissions
|
||||||
ConnectionGroup treeRoot = retrievalService.retrieveConnectionGroup(userContext, connectionGroupID);
|
ConnectionGroup treeRoot = retrievalService.retrieveConnectionGroup(userContext, connectionGroupID);
|
||||||
@@ -151,6 +164,10 @@ public class ConnectionGroupRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the connection group to be deleted.
|
||||||
|
*
|
||||||
* @param connectionGroupID
|
* @param connectionGroupID
|
||||||
* The identifier of the connection group to delete.
|
* The identifier of the connection group to delete.
|
||||||
*
|
*
|
||||||
@@ -161,9 +178,12 @@ public class ConnectionGroupRESTService {
|
|||||||
@Path("/{connectionGroupID}")
|
@Path("/{connectionGroupID}")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public void deleteConnectionGroup(@QueryParam("token") String authToken,
|
public void deleteConnectionGroup(@QueryParam("token") String authToken,
|
||||||
@PathParam("connectionGroupID") String connectionGroupID) throws GuacamoleException {
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("connectionGroupID") String connectionGroupID)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Get the connection group directory
|
// Get the connection group directory
|
||||||
Directory<ConnectionGroup> connectionGroupDirectory = userContext.getConnectionGroupDirectory();
|
Directory<ConnectionGroup> connectionGroupDirectory = userContext.getConnectionGroupDirectory();
|
||||||
@@ -183,6 +203,10 @@ public class ConnectionGroupRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext in which the connection group is to be created.
|
||||||
|
*
|
||||||
* @param connectionGroup
|
* @param connectionGroup
|
||||||
* The connection group to create.
|
* The connection group to create.
|
||||||
*
|
*
|
||||||
@@ -196,9 +220,11 @@ public class ConnectionGroupRESTService {
|
|||||||
@Produces(MediaType.TEXT_PLAIN)
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public String createConnectionGroup(@QueryParam("token") String authToken,
|
public String createConnectionGroup(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
APIConnectionGroup connectionGroup) throws GuacamoleException {
|
APIConnectionGroup connectionGroup) throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Validate that connection group data was provided
|
// Validate that connection group data was provided
|
||||||
if (connectionGroup == null)
|
if (connectionGroup == null)
|
||||||
@@ -222,6 +248,10 @@ public class ConnectionGroupRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext containing the connection group to be updated.
|
||||||
|
*
|
||||||
* @param connectionGroupID
|
* @param connectionGroupID
|
||||||
* The identifier of the existing connection group to update.
|
* The identifier of the existing connection group to update.
|
||||||
*
|
*
|
||||||
@@ -235,10 +265,13 @@ public class ConnectionGroupRESTService {
|
|||||||
@Path("/{connectionGroupID}")
|
@Path("/{connectionGroupID}")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public void updateConnectionGroup(@QueryParam("token") String authToken,
|
public void updateConnectionGroup(@QueryParam("token") String authToken,
|
||||||
@PathParam("connectionGroupID") String connectionGroupID, APIConnectionGroup connectionGroup)
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("connectionGroupID") String connectionGroupID,
|
||||||
|
APIConnectionGroup connectionGroup)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Validate that connection group data was provided
|
// Validate that connection group data was provided
|
||||||
if (connectionGroup == null)
|
if (connectionGroup == null)
|
||||||
|
@@ -28,6 +28,7 @@ import java.util.Map;
|
|||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
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;
|
||||||
@@ -36,7 +37,9 @@ import org.glyptodon.guacamole.environment.Environment;
|
|||||||
import org.glyptodon.guacamole.environment.LocalEnvironment;
|
import org.glyptodon.guacamole.environment.LocalEnvironment;
|
||||||
import org.glyptodon.guacamole.form.Form;
|
import org.glyptodon.guacamole.form.Form;
|
||||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
|
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||||
|
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||||
import org.glyptodon.guacamole.protocols.ProtocolInfo;
|
import org.glyptodon.guacamole.protocols.ProtocolInfo;
|
||||||
|
|
||||||
@@ -46,7 +49,7 @@ import org.glyptodon.guacamole.protocols.ProtocolInfo;
|
|||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
@Path("/schema")
|
@Path("/schema/{dataSource}")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public class SchemaRESTService {
|
public class SchemaRESTService {
|
||||||
@@ -57,6 +60,12 @@ public class SchemaRESTService {
|
|||||||
@Inject
|
@Inject
|
||||||
private AuthenticationService authenticationService;
|
private AuthenticationService authenticationService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for convenient retrieval of objects.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private ObjectRetrievalService retrievalService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the possible attributes of a user object.
|
* Retrieves the possible attributes of a user object.
|
||||||
*
|
*
|
||||||
@@ -64,6 +73,10 @@ public class SchemaRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext dictating the available user attributes.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* A collection of forms which describe the possible attributes of a
|
* A collection of forms which describe the possible attributes of a
|
||||||
* user object.
|
* user object.
|
||||||
@@ -74,10 +87,13 @@ public class SchemaRESTService {
|
|||||||
@GET
|
@GET
|
||||||
@Path("/users/attributes")
|
@Path("/users/attributes")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public Collection<Form> getUserAttributes(@QueryParam("token") String authToken) throws GuacamoleException {
|
public Collection<Form> getUserAttributes(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Retrieve all possible user attributes
|
// Retrieve all possible user attributes
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
return userContext.getUserAttributes();
|
return userContext.getUserAttributes();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -89,6 +105,10 @@ public class SchemaRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext dictating the available connection attributes.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* A collection of forms which describe the possible attributes of a
|
* A collection of forms which describe the possible attributes of a
|
||||||
* connection object.
|
* connection object.
|
||||||
@@ -99,10 +119,13 @@ public class SchemaRESTService {
|
|||||||
@GET
|
@GET
|
||||||
@Path("/connections/attributes")
|
@Path("/connections/attributes")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public Collection<Form> getConnectionAttributes(@QueryParam("token") String authToken) throws GuacamoleException {
|
public Collection<Form> getConnectionAttributes(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Retrieve all possible connection attributes
|
// Retrieve all possible connection attributes
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
return userContext.getConnectionAttributes();
|
return userContext.getConnectionAttributes();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -114,6 +137,11 @@ public class SchemaRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext dictating the available connection group
|
||||||
|
* attributes.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* A collection of forms which describe the possible attributes of a
|
* A collection of forms which describe the possible attributes of a
|
||||||
* connection group object.
|
* connection group object.
|
||||||
@@ -124,10 +152,13 @@ public class SchemaRESTService {
|
|||||||
@GET
|
@GET
|
||||||
@Path("/connectionGroups/attributes")
|
@Path("/connectionGroups/attributes")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public Collection<Form> getConnectionGroupAttributes(@QueryParam("token") String authToken) throws GuacamoleException {
|
public Collection<Form> getConnectionGroupAttributes(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Retrieve all possible connection group attributes
|
// Retrieve all possible connection group attributes
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
return userContext.getConnectionGroupAttributes();
|
return userContext.getConnectionGroupAttributes();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -139,6 +170,13 @@ public class SchemaRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext dictating the protocols available. Currently, the
|
||||||
|
* UserContext actually does not dictate this, the the same set of
|
||||||
|
* protocols will be retrieved for all users, though the identifier
|
||||||
|
* given here will be validated.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* A map of protocol information, where each key is the unique name
|
* A map of protocol information, where each key is the unique name
|
||||||
* associated with that protocol.
|
* associated with that protocol.
|
||||||
@@ -149,10 +187,13 @@ public class SchemaRESTService {
|
|||||||
@GET
|
@GET
|
||||||
@Path("/protocols")
|
@Path("/protocols")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public Map<String, ProtocolInfo> getProtocols(@QueryParam("token") String authToken) throws GuacamoleException {
|
public Map<String, ProtocolInfo> getProtocols(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Verify the given auth token is valid
|
// Verify the given auth token and auth provider identifier are valid
|
||||||
authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Get and return a map of all protocols.
|
// Get and return a map of all protocols.
|
||||||
Environment env = new LocalEnvironment();
|
Environment env = new LocalEnvironment();
|
||||||
|
@@ -41,6 +41,7 @@ import javax.ws.rs.core.Context;
|
|||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
|
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
|
||||||
|
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||||
import org.glyptodon.guacamole.net.auth.Directory;
|
import org.glyptodon.guacamole.net.auth.Directory;
|
||||||
import org.glyptodon.guacamole.net.auth.User;
|
import org.glyptodon.guacamole.net.auth.User;
|
||||||
@@ -51,6 +52,7 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
|||||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
||||||
|
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.APIError;
|
import org.glyptodon.guacamole.net.basic.rest.APIError;
|
||||||
import org.glyptodon.guacamole.net.basic.rest.APIPatch;
|
import org.glyptodon.guacamole.net.basic.rest.APIPatch;
|
||||||
import static org.glyptodon.guacamole.net.basic.rest.APIPatch.Operation.add;
|
import static org.glyptodon.guacamole.net.basic.rest.APIPatch.Operation.add;
|
||||||
@@ -68,8 +70,9 @@ import org.slf4j.LoggerFactory;
|
|||||||
* A REST Service for handling user CRUD operations.
|
* A REST Service for handling user CRUD operations.
|
||||||
*
|
*
|
||||||
* @author James Muehlner
|
* @author James Muehlner
|
||||||
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
@Path("/users")
|
@Path("/data/{dataSource}/users")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
public class UserRESTService {
|
public class UserRESTService {
|
||||||
@@ -120,42 +123,44 @@ public class UserRESTService {
|
|||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
private ObjectRetrievalService retrievalService;
|
private ObjectRetrievalService retrievalService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of users in the system, filtering the returned list by the
|
* Gets a list of users in the given data source (UserContext), filtering
|
||||||
* given permission, if specified.
|
* the returned list by the given permission, if specified.
|
||||||
*
|
*
|
||||||
* @param authToken
|
* @param authToken
|
||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext from which the users are to be retrieved.
|
||||||
|
*
|
||||||
* @param permissions
|
* @param permissions
|
||||||
* The set of permissions to filter with. A user must have one or more
|
* The set of permissions to filter with. A user must have one or more
|
||||||
* of these permissions for a user to appear in the result.
|
* of these permissions for a user to appear in the result.
|
||||||
* If null, no filtering will be performed.
|
* If null, no filtering will be performed.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* A list of all visible users. If a permission was specified, this
|
* A list of all visible users. If a permission was specified, this
|
||||||
* list will contain only those users for whom the current user has
|
* list will contain only those users for whom the current user has
|
||||||
* that permission.
|
* that permission.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error is encountered while retrieving users.
|
* If an error is encountered while retrieving users.
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public List<APIUser> getUsers(@QueryParam("token") String authToken,
|
public List<APIUser> getUsers(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
@QueryParam("permission") List<ObjectPermission.Type> permissions)
|
@QueryParam("permission") List<ObjectPermission.Type> permissions)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
User self = userContext.self();
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Do not filter on permissions if no permissions are specified
|
|
||||||
if (permissions != null && permissions.isEmpty())
|
|
||||||
permissions = null;
|
|
||||||
|
|
||||||
// An admin user has access to any user
|
// An admin user has access to any user
|
||||||
|
User self = userContext.self();
|
||||||
SystemPermissionSet systemPermissions = self.getSystemPermissions();
|
SystemPermissionSet systemPermissions = self.getSystemPermissions();
|
||||||
boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER);
|
boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER);
|
||||||
|
|
||||||
@@ -164,7 +169,7 @@ public class UserRESTService {
|
|||||||
|
|
||||||
// Filter users, if requested
|
// Filter users, if requested
|
||||||
Collection<String> userIdentifiers = userDirectory.getIdentifiers();
|
Collection<String> userIdentifiers = userDirectory.getIdentifiers();
|
||||||
if (!isAdmin && permissions != null) {
|
if (!isAdmin && permissions != null && !permissions.isEmpty()) {
|
||||||
ObjectPermissionSet userPermissions = self.getUserPermissions();
|
ObjectPermissionSet userPermissions = self.getUserPermissions();
|
||||||
userIdentifiers = userPermissions.getAccessibleObjects(permissions, userIdentifiers);
|
userIdentifiers = userPermissions.getAccessibleObjects(permissions, userIdentifiers);
|
||||||
}
|
}
|
||||||
@@ -174,7 +179,6 @@ public class UserRESTService {
|
|||||||
for (User user : userDirectory.getAll(userIdentifiers))
|
for (User user : userDirectory.getAll(userIdentifiers))
|
||||||
apiUsers.add(new APIUser(user));
|
apiUsers.add(new APIUser(user));
|
||||||
|
|
||||||
// Return the converted user list
|
|
||||||
return apiUsers;
|
return apiUsers;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -186,6 +190,10 @@ public class UserRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext from which the requested user is to be retrieved.
|
||||||
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* The username of the user to retrieve.
|
* The username of the user to retrieve.
|
||||||
*
|
*
|
||||||
@@ -198,34 +206,49 @@ public class UserRESTService {
|
|||||||
@GET
|
@GET
|
||||||
@Path("/{username}")
|
@Path("/{username}")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public APIUser getUser(@QueryParam("token") String authToken, @PathParam("username") String username)
|
public APIUser getUser(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("username") String username)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
|
||||||
// Retrieve the requested user
|
// Retrieve the requested user
|
||||||
User user = retrievalService.retrieveUser(userContext, username);
|
User user = retrievalService.retrieveUser(session, authProviderIdentifier, username);
|
||||||
return new APIUser(user);
|
return new APIUser(user);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new user and returns the username.
|
* Creates a new user and returns the username.
|
||||||
* @param authToken The authentication token that is used to authenticate
|
*
|
||||||
* the user performing the operation.
|
* @param authToken
|
||||||
* @param user The new user to create.
|
* The authentication token that is used to authenticate the user
|
||||||
* @throws GuacamoleException If a problem is encountered while creating the user.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
* @return The username of the newly created user.
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext in which the requested user is to be created.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The new user to create.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If a problem is encountered while creating the user.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The username of the newly created user.
|
||||||
*/
|
*/
|
||||||
@POST
|
@POST
|
||||||
@Produces(MediaType.TEXT_PLAIN)
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public String createUser(@QueryParam("token") String authToken, APIUser user)
|
public String createUser(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier, APIUser user)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Get the directory
|
// Get the directory
|
||||||
Directory<User> userDirectory = userContext.getUserDirectory();
|
Directory<User> userDirectory = userContext.getUserDirectory();
|
||||||
|
|
||||||
@@ -247,6 +270,10 @@ public class UserRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext in which the requested user is to be updated.
|
||||||
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* The username of the user to update.
|
* The username of the user to update.
|
||||||
*
|
*
|
||||||
@@ -260,11 +287,13 @@ public class UserRESTService {
|
|||||||
@Path("/{username}")
|
@Path("/{username}")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public void updateUser(@QueryParam("token") String authToken,
|
public void updateUser(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
@PathParam("username") String username, APIUser user)
|
@PathParam("username") String username, APIUser user)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Get the directory
|
// Get the directory
|
||||||
Directory<User> userDirectory = userContext.getUserDirectory();
|
Directory<User> userDirectory = userContext.getUserDirectory();
|
||||||
|
|
||||||
@@ -301,6 +330,10 @@ public class UserRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext in which the requested user is to be updated.
|
||||||
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* The username of the user to update.
|
* The username of the user to update.
|
||||||
*
|
*
|
||||||
@@ -318,12 +351,14 @@ public class UserRESTService {
|
|||||||
@Path("/{username}/password")
|
@Path("/{username}/password")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public void updatePassword(@QueryParam("token") String authToken,
|
public void updatePassword(@QueryParam("token") String authToken,
|
||||||
@PathParam("username") String username,
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
|
@PathParam("username") String username,
|
||||||
APIUserPasswordUpdate userPasswordUpdate,
|
APIUserPasswordUpdate userPasswordUpdate,
|
||||||
@Context HttpServletRequest request) throws GuacamoleException {
|
@Context HttpServletRequest request) throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Build credentials
|
// Build credentials
|
||||||
Credentials credentials = new Credentials();
|
Credentials credentials = new Credentials();
|
||||||
credentials.setUsername(username);
|
credentials.setUsername(username);
|
||||||
@@ -333,7 +368,8 @@ public class UserRESTService {
|
|||||||
|
|
||||||
// Verify that the old password was correct
|
// Verify that the old password was correct
|
||||||
try {
|
try {
|
||||||
if (userContext.getAuthenticationProvider().authenticateUser(credentials) == null) {
|
AuthenticationProvider authProvider = userContext.getAuthenticationProvider();
|
||||||
|
if (authProvider.authenticateUser(credentials) == null) {
|
||||||
throw new APIException(APIError.Type.PERMISSION_DENIED,
|
throw new APIException(APIError.Type.PERMISSION_DENIED,
|
||||||
"Permission denied.");
|
"Permission denied.");
|
||||||
}
|
}
|
||||||
@@ -366,6 +402,10 @@ public class UserRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext from which the requested user is to be deleted.
|
||||||
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* The username of the user to delete.
|
* The username of the user to delete.
|
||||||
*
|
*
|
||||||
@@ -376,11 +416,13 @@ public class UserRESTService {
|
|||||||
@Path("/{username}")
|
@Path("/{username}")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public void deleteUser(@QueryParam("token") String authToken,
|
public void deleteUser(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
@PathParam("username") String username)
|
@PathParam("username") String username)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Get the directory
|
// Get the directory
|
||||||
Directory<User> userDirectory = userContext.getUserDirectory();
|
Directory<User> userDirectory = userContext.getUserDirectory();
|
||||||
|
|
||||||
@@ -401,6 +443,10 @@ public class UserRESTService {
|
|||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext in which the requested user is to be found.
|
||||||
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* The username of the user to retrieve permissions for.
|
* The username of the user to retrieve permissions for.
|
||||||
*
|
*
|
||||||
@@ -414,10 +460,12 @@ public class UserRESTService {
|
|||||||
@Path("/{username}/permissions")
|
@Path("/{username}/permissions")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public APIPermissionSet getPermissions(@QueryParam("token") String authToken,
|
public APIPermissionSet getPermissions(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
@PathParam("username") String username)
|
@PathParam("username") String username)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
User user;
|
User user;
|
||||||
|
|
||||||
@@ -489,7 +537,11 @@ public class UserRESTService {
|
|||||||
* @param authToken
|
* @param authToken
|
||||||
* The authentication token that is used to authenticate the user
|
* The authentication token that is used to authenticate the user
|
||||||
* performing the operation.
|
* performing the operation.
|
||||||
*
|
*
|
||||||
|
* @param authProviderIdentifier
|
||||||
|
* The unique identifier of the AuthenticationProvider associated with
|
||||||
|
* the UserContext in which the requested user is to be found.
|
||||||
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* The username of the user to modify the permissions of.
|
* The username of the user to modify the permissions of.
|
||||||
*
|
*
|
||||||
@@ -503,11 +555,13 @@ public class UserRESTService {
|
|||||||
@Path("/{username}/permissions")
|
@Path("/{username}/permissions")
|
||||||
@AuthProviderRESTExposure
|
@AuthProviderRESTExposure
|
||||||
public void patchPermissions(@QueryParam("token") String authToken,
|
public void patchPermissions(@QueryParam("token") String authToken,
|
||||||
|
@PathParam("dataSource") String authProviderIdentifier,
|
||||||
@PathParam("username") String username,
|
@PathParam("username") String username,
|
||||||
List<APIPatch<String>> patches) throws GuacamoleException {
|
List<APIPatch<String>> patches) throws GuacamoleException {
|
||||||
|
|
||||||
UserContext userContext = authenticationService.getUserContext(authToken);
|
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
|
||||||
|
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
|
||||||
|
|
||||||
// Get the user
|
// Get the user
|
||||||
User user = userContext.getUserDirectory().get(username);
|
User user = userContext.getUserDirectory().get(username);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@@ -32,7 +32,7 @@ import org.glyptodon.guacamole.net.basic.TunnelRequest;
|
|||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
public class WebSocketTunnelRequest implements TunnelRequest {
|
public class WebSocketTunnelRequest extends TunnelRequest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All parameters passed via HTTP to the WebSocket handshake.
|
* All parameters passed via HTTP to the WebSocket handshake.
|
||||||
|
@@ -33,7 +33,7 @@ import org.glyptodon.guacamole.net.basic.TunnelRequest;
|
|||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
*/
|
*/
|
||||||
public class WebSocketTunnelRequest implements TunnelRequest {
|
public class WebSocketTunnelRequest extends TunnelRequest {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All parameters passed via HTTP to the WebSocket handshake.
|
* All parameters passed via HTTP to the WebSocket handshake.
|
||||||
|
@@ -99,9 +99,10 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
|
|
||||||
// Store auth data
|
// Store auth data
|
||||||
$cookieStore.put(AUTH_COOKIE_ID, {
|
$cookieStore.put(AUTH_COOKIE_ID, {
|
||||||
authToken : data.authToken,
|
'authToken' : data.authToken,
|
||||||
username : data.username,
|
'username' : data.username,
|
||||||
dataSource : data.dataSource
|
'dataSource' : data.dataSource,
|
||||||
|
'availableDataSources' : data.availableDataSources
|
||||||
});
|
});
|
||||||
|
|
||||||
// Process is complete
|
// Process is complete
|
||||||
@@ -320,7 +321,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
*
|
*
|
||||||
* @returns {String[]}
|
* @returns {String[]}
|
||||||
* The identifiers of all data sources availble to the current user,
|
* The identifiers of all data sources availble to the current user,
|
||||||
* or null if no authentication data is present.
|
* or an empty array if no authentication data is present.
|
||||||
*/
|
*/
|
||||||
service.getAvailableDataSources = function getAvailableDataSources() {
|
service.getAvailableDataSources = function getAvailableDataSources() {
|
||||||
|
|
||||||
@@ -330,7 +331,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
return authData.availableDataSources;
|
return authData.availableDataSources;
|
||||||
|
|
||||||
// No auth data present
|
// No auth data present
|
||||||
return null;
|
return [];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -158,7 +158,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
|
|||||||
var RECONNECT_ACTION = {
|
var RECONNECT_ACTION = {
|
||||||
name : "CLIENT.ACTION_RECONNECT",
|
name : "CLIENT.ACTION_RECONNECT",
|
||||||
callback : function reconnectCallback() {
|
callback : function reconnectCallback() {
|
||||||
$scope.client = guacClientManager.replaceManagedClient(uniqueId, $routeParams.params);
|
$scope.client = guacClientManager.replaceManagedClient($routeParams.id, $routeParams.params);
|
||||||
guacNotification.showStatus(false);
|
guacNotification.showStatus(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -219,13 +219,13 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
|
|||||||
$scope.$on('guacClientClipboard', function clientClipboardListener(event, client, mimetype, clipboardData) {
|
$scope.$on('guacClientClipboard', function clientClipboardListener(event, client, mimetype, clipboardData) {
|
||||||
$scope.clipboardData = clipboardData;
|
$scope.clipboardData = clipboardData;
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Parse the type, name, and id out of the url paramteres,
|
* The client which should be attached to the client UI.
|
||||||
* as well as any extra parameters if set.
|
*
|
||||||
|
* @type ManagedClient
|
||||||
*/
|
*/
|
||||||
var uniqueId = $routeParams.type + '/' + $routeParams.id;
|
$scope.client = guacClientManager.getManagedClient($routeParams.id, $routeParams.params);
|
||||||
$scope.client = guacClientManager.getManagedClient(uniqueId, $routeParams.params);
|
|
||||||
|
|
||||||
var keysCurrentlyPressed = {};
|
var keysCurrentlyPressed = {};
|
||||||
|
|
||||||
|
@@ -28,6 +28,7 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
|
|
||||||
// Required types
|
// Required types
|
||||||
var ClientProperties = $injector.get('ClientProperties');
|
var ClientProperties = $injector.get('ClientProperties');
|
||||||
|
var ClientIdentifier = $injector.get('ClientIdentifier');
|
||||||
var ManagedClientState = $injector.get('ManagedClientState');
|
var ManagedClientState = $injector.get('ManagedClientState');
|
||||||
var ManagedDisplay = $injector.get('ManagedDisplay');
|
var ManagedDisplay = $injector.get('ManagedDisplay');
|
||||||
var ManagedFileDownload = $injector.get('ManagedFileDownload');
|
var ManagedFileDownload = $injector.get('ManagedFileDownload');
|
||||||
@@ -153,8 +154,8 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
* desired connection ID, display resolution, and supported audio/video
|
* desired connection ID, display resolution, and supported audio/video
|
||||||
* codecs.
|
* codecs.
|
||||||
*
|
*
|
||||||
* @param {String} id
|
* @param {ClientIdentifier} identifier
|
||||||
* The ID of the connection or group to connect to.
|
* The identifier representing the connection or group to connect to.
|
||||||
*
|
*
|
||||||
* @param {String} [connectionParameters]
|
* @param {String} [connectionParameters]
|
||||||
* Any additional HTTP parameters to pass while connecting.
|
* Any additional HTTP parameters to pass while connecting.
|
||||||
@@ -163,7 +164,7 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
* The string of connection parameters to be passed to the Guacamole
|
* The string of connection parameters to be passed to the Guacamole
|
||||||
* client.
|
* client.
|
||||||
*/
|
*/
|
||||||
var getConnectString = function getConnectString(id, connectionParameters) {
|
var getConnectString = function getConnectString(identifier, connectionParameters) {
|
||||||
|
|
||||||
// Calculate optimal width/height for display
|
// Calculate optimal width/height for display
|
||||||
var pixel_density = $window.devicePixelRatio || 1;
|
var pixel_density = $window.devicePixelRatio || 1;
|
||||||
@@ -173,21 +174,23 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
|
|
||||||
// Build base connect string
|
// Build base connect string
|
||||||
var connectString =
|
var connectString =
|
||||||
"id=" + encodeURIComponent(id)
|
"token=" + encodeURIComponent(authenticationService.getCurrentToken())
|
||||||
+ "&authToken=" + encodeURIComponent(authenticationService.getCurrentToken())
|
+ "&GUAC_DATA_SOURCE=" + encodeURIComponent(identifier.dataSource)
|
||||||
+ "&width=" + Math.floor(optimal_width)
|
+ "&GUAC_ID=" + encodeURIComponent(identifier.id)
|
||||||
+ "&height=" + Math.floor(optimal_height)
|
+ "&GUAC_TYPE=" + encodeURIComponent(identifier.type)
|
||||||
+ "&dpi=" + Math.floor(optimal_dpi)
|
+ "&GUAC_WIDTH=" + Math.floor(optimal_width)
|
||||||
|
+ "&GUAC_HEIGHT=" + Math.floor(optimal_height)
|
||||||
|
+ "&GUAC_DPI=" + Math.floor(optimal_dpi)
|
||||||
+ (connectionParameters ? '&' + connectionParameters : '');
|
+ (connectionParameters ? '&' + connectionParameters : '');
|
||||||
|
|
||||||
// Add audio mimetypes to connect_string
|
// Add audio mimetypes to connect_string
|
||||||
guacAudio.supported.forEach(function(mimetype) {
|
guacAudio.supported.forEach(function(mimetype) {
|
||||||
connectString += "&audio=" + encodeURIComponent(mimetype);
|
connectString += "&GUAC_AUDIO=" + encodeURIComponent(mimetype);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add video mimetypes to connect_string
|
// Add video mimetypes to connect_string
|
||||||
guacVideo.supported.forEach(function(mimetype) {
|
guacVideo.supported.forEach(function(mimetype) {
|
||||||
connectString += "&video=" + encodeURIComponent(mimetype);
|
connectString += "&GUAC_VIDEO=" + encodeURIComponent(mimetype);
|
||||||
});
|
});
|
||||||
|
|
||||||
return connectString;
|
return connectString;
|
||||||
@@ -238,7 +241,9 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
* or group.
|
* or group.
|
||||||
*
|
*
|
||||||
* @param {String} id
|
* @param {String} id
|
||||||
* The ID of the connection or group to connect to.
|
* The ID of the connection or group to connect to. This String must be
|
||||||
|
* a valid ClientIdentifier string, as would be generated by
|
||||||
|
* ClientIdentifier.toString().
|
||||||
*
|
*
|
||||||
* @param {String} [connectionParameters]
|
* @param {String} [connectionParameters]
|
||||||
* Any additional HTTP parameters to pass while connecting.
|
* Any additional HTTP parameters to pass while connecting.
|
||||||
@@ -402,23 +407,23 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
|
|||||||
// Manage the client display
|
// Manage the client display
|
||||||
managedClient.managedDisplay = ManagedDisplay.getInstance(client.getDisplay());
|
managedClient.managedDisplay = ManagedDisplay.getInstance(client.getDisplay());
|
||||||
|
|
||||||
// Connect the Guacamole client
|
// Parse connection details from ID
|
||||||
client.connect(getConnectString(id, connectionParameters));
|
var clientIdentifier = ClientIdentifier.fromString(id);
|
||||||
|
|
||||||
// Determine type of connection
|
// Connect the Guacamole client
|
||||||
var typePrefix = id.substring(0, 2);
|
client.connect(getConnectString(clientIdentifier, connectionParameters));
|
||||||
|
|
||||||
// If using a connection, pull connection name
|
// If using a connection, pull connection name
|
||||||
if (typePrefix === 'c/') {
|
if (clientIdentifier.type === ClientIdentifier.Types.CONNECTION) {
|
||||||
connectionService.getConnection(id.substring(2))
|
connectionService.getConnection(clientIdentifier.dataSource, clientIdentifier.id)
|
||||||
.success(function connectionRetrieved(connection) {
|
.success(function connectionRetrieved(connection) {
|
||||||
managedClient.name = connection.name;
|
managedClient.name = connection.name;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// If using a connection group, pull connection name
|
// If using a connection group, pull connection name
|
||||||
else if (typePrefix === 'g/') {
|
else if (clientIdentifier.type === ClientIdentifier.Types.CONNECTION_GROUP) {
|
||||||
connectionGroupService.getConnectionGroup(id.substring(2))
|
connectionGroupService.getConnectionGroup(clientIdentifier.dataSource, clientIdentifier.id)
|
||||||
.success(function connectionGroupRetrieved(group) {
|
.success(function connectionGroupRetrieved(group) {
|
||||||
managedClient.name = group.name;
|
managedClient.name = group.name;
|
||||||
});
|
});
|
||||||
|
@@ -697,15 +697,15 @@ angular.module('form').controller('timeZoneFieldController', ['$scope', '$inject
|
|||||||
*/
|
*/
|
||||||
$scope.region = '';
|
$scope.region = '';
|
||||||
|
|
||||||
// Restore time zone selection when region changes
|
|
||||||
$scope.$watch('region', function restoreSelection(region) {
|
|
||||||
$scope.model = selectedTimeZone[region] || null;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure corresponding region is selected
|
// Ensure corresponding region is selected
|
||||||
$scope.$watch('model', function setModel(model) {
|
$scope.$watch('model', function setModel(model) {
|
||||||
$scope.region = timeZoneRegions[model] || '';
|
$scope.region = timeZoneRegions[model] || '';
|
||||||
selectedTimeZone[$scope.region] = model;
|
selectedTimeZone[$scope.region] = model;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Restore time zone selection when region changes
|
||||||
|
$scope.$watch('region', function restoreSelection(region) {
|
||||||
|
$scope.model = selectedTimeZone[region] || null;
|
||||||
|
});
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
@@ -32,11 +32,12 @@ angular.module('groupList').directive('guacGroupList', [function guacGroupList()
|
|||||||
scope: {
|
scope: {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The connection group to display.
|
* The connection groups to display as a map of data source
|
||||||
|
* identifier to corresponding root group.
|
||||||
*
|
*
|
||||||
* @type ConnectionGroup|Object
|
* @type Object.<String, ConnectionGroup>
|
||||||
*/
|
*/
|
||||||
connectionGroup : '=',
|
connectionGroups : '=',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arbitrary object which shall be made available to the connection
|
* Arbitrary object which shall be made available to the connection
|
||||||
@@ -92,43 +93,38 @@ angular.module('groupList').directive('guacGroupList', [function guacGroupList()
|
|||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var activeConnectionService = $injector.get('activeConnectionService');
|
var activeConnectionService = $injector.get('activeConnectionService');
|
||||||
|
var dataSourceService = $injector.get('dataSourceService');
|
||||||
|
|
||||||
// Required types
|
// Required types
|
||||||
var GroupListItem = $injector.get('GroupListItem');
|
var GroupListItem = $injector.get('GroupListItem');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of active connections associated with a given
|
* Map of data source identifier to the number of active
|
||||||
* connection identifier. If this information is unknown, or there
|
* connections associated with a given connection identifier.
|
||||||
* are no active connections for a given identifier, no number will
|
* If this information is unknown, or there are no active
|
||||||
* be stored.
|
* connections for a given identifier, no number will be stored.
|
||||||
*
|
*
|
||||||
* @type Object.<String, Number>
|
* @type Object.<String, Object.<String, Number>>
|
||||||
*/
|
*/
|
||||||
var connectionCount = {};
|
var connectionCount = {};
|
||||||
|
|
||||||
// Count active connections by connection identifier
|
/**
|
||||||
activeConnectionService.getActiveConnections()
|
* A list of all items which should appear at the root level. As
|
||||||
.success(function activeConnectionsRetrieved(activeConnections) {
|
* connections and connection groups from multiple data sources may
|
||||||
|
* be included in a guacGroupList, there may be multiple root
|
||||||
// Count each active connection by identifier
|
* items, even if the root connection group is shown.
|
||||||
angular.forEach(activeConnections, function addActiveConnection(activeConnection) {
|
*
|
||||||
|
* @type GroupListItem[]
|
||||||
// If counter already exists, increment
|
*/
|
||||||
var identifier = activeConnection.connectionIdentifier;
|
$scope.rootItems = [];
|
||||||
if (connectionCount[identifier])
|
|
||||||
connectionCount[identifier]++;
|
|
||||||
|
|
||||||
// Otherwise, initialize counter to 1
|
|
||||||
else
|
|
||||||
connectionCount[identifier] = 1;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of active usages of a given connection.
|
* Returns the number of active usages of a given connection.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The identifier of the data source containing the given
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
* @param {Connection} connection
|
* @param {Connection} connection
|
||||||
* The connection whose active connections should be counted.
|
* The connection whose active connections should be counted.
|
||||||
*
|
*
|
||||||
@@ -136,8 +132,8 @@ angular.module('groupList').directive('guacGroupList', [function guacGroupList()
|
|||||||
* The number of currently-active usages of the given
|
* The number of currently-active usages of the given
|
||||||
* connection.
|
* connection.
|
||||||
*/
|
*/
|
||||||
var countActiveConnections = function countActiveConnections(connection) {
|
var countActiveConnections = function countActiveConnections(dataSource, connection) {
|
||||||
return connectionCount[connection.identifier];
|
return connectionCount[dataSource][connection.identifier];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -173,29 +169,66 @@ angular.module('groupList').directive('guacGroupList', [function guacGroupList()
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Set contents whenever the connection group is assigned or changed
|
// Set contents whenever the connection group is assigned or changed
|
||||||
$scope.$watch("connectionGroup", function setContents(connectionGroup) {
|
$scope.$watch('connectionGroups', function setContents(connectionGroups) {
|
||||||
|
|
||||||
if (connectionGroup) {
|
// Reset stored data
|
||||||
|
var dataSources = [];
|
||||||
|
$scope.rootItems = [];
|
||||||
|
connectionCount = {};
|
||||||
|
|
||||||
// Create item hierarchy, including connections only if they will be visible
|
// If connection groups are given, add them to the interface
|
||||||
var rootItem = GroupListItem.fromConnectionGroup(connectionGroup,
|
if (connectionGroups) {
|
||||||
!!$scope.connectionTemplate, countActiveConnections);
|
|
||||||
|
|
||||||
// If root group is to be shown, wrap that group as the child of a fake root group
|
// Add each provided connection group
|
||||||
if ($scope.showRootGroup)
|
angular.forEach(connectionGroups, function addConnectionGroup(connectionGroup, dataSource) {
|
||||||
$scope.rootItem = new GroupListItem({
|
|
||||||
isConnectionGroup : true,
|
// Prepare data source for active connection counting
|
||||||
isBalancing : false,
|
dataSources.push(dataSource);
|
||||||
children : [ rootItem ]
|
connectionCount[dataSource] = {};
|
||||||
|
|
||||||
|
// Create root item for current connection group
|
||||||
|
var rootItem = GroupListItem.fromConnectionGroup(dataSource, connectionGroup,
|
||||||
|
!!$scope.connectionTemplate, countActiveConnections);
|
||||||
|
|
||||||
|
// If root group is to be shown, add it as a root item
|
||||||
|
if ($scope.showRootGroup)
|
||||||
|
$scope.rootItems.push(rootItem);
|
||||||
|
|
||||||
|
// Otherwise, add its children as root items
|
||||||
|
else {
|
||||||
|
angular.forEach(rootItem.children, function addRootItem(child) {
|
||||||
|
$scope.rootItems.push(child);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Count active connections by connection identifier
|
||||||
|
dataSourceService.apply(
|
||||||
|
activeConnectionService.getActiveConnections,
|
||||||
|
dataSources
|
||||||
|
)
|
||||||
|
.then(function activeConnectionsRetrieved(activeConnectionMap) {
|
||||||
|
|
||||||
|
// Within each data source, count each active connection by identifier
|
||||||
|
angular.forEach(activeConnectionMap, function addActiveConnections(activeConnections, dataSource) {
|
||||||
|
angular.forEach(activeConnections, function addActiveConnection(activeConnection) {
|
||||||
|
|
||||||
|
// If counter already exists, increment
|
||||||
|
var identifier = activeConnection.connectionIdentifier;
|
||||||
|
if (connectionCount[dataSource][identifier])
|
||||||
|
connectionCount[dataSource][identifier]++;
|
||||||
|
|
||||||
|
// Otherwise, initialize counter to 1
|
||||||
|
else
|
||||||
|
connectionCount[dataSource][identifier] = 1;
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// If not wrapped, only the descendants of the root will be shown
|
});
|
||||||
else
|
|
||||||
$scope.rootItem = rootItem;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
$scope.rootItem = null;
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -57,7 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pager for connections / groups -->
|
<!-- Pager for connections / groups -->
|
||||||
<guac-pager page="childrenPage" items="rootItem.children | orderBy : 'name'"
|
<guac-pager page="childrenPage" items="rootItems | orderBy : 'name'"
|
||||||
page-size="pageSize"></guac-pager>
|
page-size="pageSize"></guac-pager>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@@ -39,6 +39,14 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
|
|||||||
// Use empty object by default
|
// Use empty object by default
|
||||||
template = template || {};
|
template = template || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier of the data source associated with the connection or
|
||||||
|
* connection group this item represents.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.dataSource = template.dataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unique identifier associated with the connection or connection
|
* The unique identifier associated with the connection or connection
|
||||||
* group this item represents.
|
* group this item represents.
|
||||||
@@ -124,6 +132,10 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
|
|||||||
/**
|
/**
|
||||||
* Creates a new GroupListItem using the contents of the given connection.
|
* Creates a new GroupListItem using the contents of the given connection.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The identifier of the data source containing the given connection
|
||||||
|
* group.
|
||||||
|
*
|
||||||
* @param {ConnectionGroup} connection
|
* @param {ConnectionGroup} connection
|
||||||
* The connection whose contents should be represented by the new
|
* The connection whose contents should be represented by the new
|
||||||
* GroupListItem.
|
* GroupListItem.
|
||||||
@@ -131,12 +143,15 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
|
|||||||
* @param {Function} [countActiveConnections]
|
* @param {Function} [countActiveConnections]
|
||||||
* A getter which returns the current number of active connections for
|
* A getter which returns the current number of active connections for
|
||||||
* the given connection. If omitted, the number of active connections
|
* the given connection. If omitted, the number of active connections
|
||||||
* known at the time this function was called is used instead.
|
* known at the time this function was called is used instead. This
|
||||||
|
* function will be passed, in order, the data source identifier and
|
||||||
|
* the connection in question.
|
||||||
*
|
*
|
||||||
* @returns {GroupListItem}
|
* @returns {GroupListItem}
|
||||||
* A new GroupListItem which represents the given connection.
|
* A new GroupListItem which represents the given connection.
|
||||||
*/
|
*/
|
||||||
GroupListItem.fromConnection = function fromConnection(connection, countActiveConnections) {
|
GroupListItem.fromConnection = function fromConnection(dataSource,
|
||||||
|
connection, countActiveConnections) {
|
||||||
|
|
||||||
// Return item representing the given connection
|
// Return item representing the given connection
|
||||||
return new GroupListItem({
|
return new GroupListItem({
|
||||||
@@ -145,6 +160,7 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
|
|||||||
name : connection.name,
|
name : connection.name,
|
||||||
identifier : connection.identifier,
|
identifier : connection.identifier,
|
||||||
protocol : connection.protocol,
|
protocol : connection.protocol,
|
||||||
|
dataSource : dataSource,
|
||||||
|
|
||||||
// Type information
|
// Type information
|
||||||
isConnection : true,
|
isConnection : true,
|
||||||
@@ -155,7 +171,7 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
|
|||||||
|
|
||||||
// Use getter, if provided
|
// Use getter, if provided
|
||||||
if (countActiveConnections)
|
if (countActiveConnections)
|
||||||
return countActiveConnections(connection);
|
return countActiveConnections(dataSource, connection);
|
||||||
|
|
||||||
return connection.activeConnections;
|
return connection.activeConnections;
|
||||||
|
|
||||||
@@ -172,6 +188,10 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
|
|||||||
* Creates a new GroupListItem using the contents and descendants of the
|
* Creates a new GroupListItem using the contents and descendants of the
|
||||||
* given connection group.
|
* given connection group.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The identifier of the data source containing the given connection
|
||||||
|
* group.
|
||||||
|
*
|
||||||
* @param {ConnectionGroup} connectionGroup
|
* @param {ConnectionGroup} connectionGroup
|
||||||
* The connection group whose contents and descendants should be
|
* The connection group whose contents and descendants should be
|
||||||
* represented by the new GroupListItem and its descendants.
|
* represented by the new GroupListItem and its descendants.
|
||||||
@@ -183,34 +203,41 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
|
|||||||
* @param {Function} [countActiveConnections]
|
* @param {Function} [countActiveConnections]
|
||||||
* A getter which returns the current number of active connections for
|
* A getter which returns the current number of active connections for
|
||||||
* the given connection. If omitted, the number of active connections
|
* the given connection. If omitted, the number of active connections
|
||||||
* known at the time this function was called is used instead.
|
* known at the time this function was called is used instead. This
|
||||||
|
* function will be passed, in order, the data source identifier and
|
||||||
|
* the connection group in question.
|
||||||
*
|
*
|
||||||
* @param {Function} [countActiveConnectionGroups]
|
* @param {Function} [countActiveConnectionGroups]
|
||||||
* A getter which returns the current number of active connections for
|
* A getter which returns the current number of active connections for
|
||||||
* the given connection group. If omitted, the number of active
|
* the given connection group. If omitted, the number of active
|
||||||
* connections known at the time this function was called is used
|
* connections known at the time this function was called is used
|
||||||
* instead.
|
* instead. This function will be passed, in order, the data source
|
||||||
|
* identifier and the connection group in question.
|
||||||
*
|
*
|
||||||
* @returns {GroupListItem}
|
* @returns {GroupListItem}
|
||||||
* A new GroupListItem which represents the given connection group,
|
* A new GroupListItem which represents the given connection group,
|
||||||
* including all descendants.
|
* including all descendants.
|
||||||
*/
|
*/
|
||||||
GroupListItem.fromConnectionGroup = function fromConnectionGroup(connectionGroup,
|
GroupListItem.fromConnectionGroup = function fromConnectionGroup(dataSource,
|
||||||
includeConnections, countActiveConnections, countActiveConnectionGroups) {
|
connectionGroup, includeConnections, countActiveConnections,
|
||||||
|
countActiveConnectionGroups) {
|
||||||
|
|
||||||
var children = [];
|
var children = [];
|
||||||
|
|
||||||
// Add any child connections
|
// Add any child connections
|
||||||
if (connectionGroup.childConnections && includeConnections !== false) {
|
if (connectionGroup.childConnections && includeConnections !== false) {
|
||||||
connectionGroup.childConnections.forEach(function addChildConnection(child) {
|
connectionGroup.childConnections.forEach(function addChildConnection(child) {
|
||||||
children.push(GroupListItem.fromConnection(child, countActiveConnections));
|
children.push(GroupListItem.fromConnection(dataSource, child,
|
||||||
|
countActiveConnections));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add any child groups
|
// Add any child groups
|
||||||
if (connectionGroup.childConnectionGroups) {
|
if (connectionGroup.childConnectionGroups) {
|
||||||
connectionGroup.childConnectionGroups.forEach(function addChildGroup(child) {
|
connectionGroup.childConnectionGroups.forEach(function addChildGroup(child) {
|
||||||
children.push(GroupListItem.fromConnectionGroup(child, includeConnections, countActiveConnections, countActiveConnectionGroups));
|
children.push(GroupListItem.fromConnectionGroup(dataSource,
|
||||||
|
child, includeConnections, countActiveConnections,
|
||||||
|
countActiveConnectionGroups));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,6 +247,7 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
|
|||||||
// Identifying information
|
// Identifying information
|
||||||
name : connectionGroup.name,
|
name : connectionGroup.name,
|
||||||
identifier : connectionGroup.identifier,
|
identifier : connectionGroup.identifier,
|
||||||
|
dataSource : dataSource,
|
||||||
|
|
||||||
// Type information
|
// Type information
|
||||||
isConnection : false,
|
isConnection : false,
|
||||||
@@ -234,7 +262,7 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio
|
|||||||
|
|
||||||
// Use getter, if provided
|
// Use getter, if provided
|
||||||
if (countActiveConnectionGroups)
|
if (countActiveConnectionGroups)
|
||||||
return countActiveConnectionGroups(connectionGroup);
|
return countActiveConnectionGroups(dataSource, connectionGroup);
|
||||||
|
|
||||||
return connectionGroup.activeConnections;
|
return connectionGroup.activeConnections;
|
||||||
|
|
||||||
|
@@ -27,19 +27,22 @@ angular.module('home').controller('homeController', ['$scope', '$injector',
|
|||||||
function homeController($scope, $injector) {
|
function homeController($scope, $injector) {
|
||||||
|
|
||||||
// Get required types
|
// Get required types
|
||||||
var ConnectionGroup = $injector.get("ConnectionGroup");
|
var ConnectionGroup = $injector.get('ConnectionGroup');
|
||||||
|
var ClientIdentifier = $injector.get('ClientIdentifier');
|
||||||
|
|
||||||
// Get required services
|
// Get required services
|
||||||
var authenticationService = $injector.get("authenticationService");
|
var authenticationService = $injector.get('authenticationService');
|
||||||
var connectionGroupService = $injector.get("connectionGroupService");
|
var connectionGroupService = $injector.get('connectionGroupService');
|
||||||
|
var dataSourceService = $injector.get('dataSourceService');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root connection group, or null if the connection group hierarchy has
|
* Map of data source identifier to the root connection group of that data
|
||||||
* not yet been loaded.
|
* source, or null if the connection group hierarchy has not yet been
|
||||||
|
* loaded.
|
||||||
*
|
*
|
||||||
* @type ConnectionGroup
|
* @type Object.<String, ConnectionGroup>
|
||||||
*/
|
*/
|
||||||
$scope.rootConnectionGroup = null;
|
$scope.rootConnectionGroups = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether critical data has completed being loaded.
|
* Returns whether critical data has completed being loaded.
|
||||||
@@ -54,10 +57,59 @@ angular.module('home').controller('homeController', ['$scope', '$injector',
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Retrieve root group and all descendants
|
/**
|
||||||
connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER)
|
* Object passed to the guacGroupList directive, providing context-specific
|
||||||
.success(function rootGroupRetrieved(rootConnectionGroup) {
|
* functions or data.
|
||||||
$scope.rootConnectionGroup = rootConnectionGroup;
|
*/
|
||||||
|
$scope.context = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unique string identifier which must be used when
|
||||||
|
* connecting to a connection or connection group represented by the
|
||||||
|
* given GroupListItem.
|
||||||
|
*
|
||||||
|
* @param {GroupListItem} item
|
||||||
|
* The GroupListItem to determine the client identifier of.
|
||||||
|
*
|
||||||
|
* @returns {String}
|
||||||
|
* The client identifier associated with the connection or
|
||||||
|
* connection group represented by the given GroupListItem, or null
|
||||||
|
* if the GroupListItem cannot have an associated client
|
||||||
|
* identifier.
|
||||||
|
*/
|
||||||
|
getClientIdentifier : function getClientIdentifier(item) {
|
||||||
|
|
||||||
|
// If the item is a connection, generate a connection identifier
|
||||||
|
if (item.isConnection)
|
||||||
|
return ClientIdentifier.toString({
|
||||||
|
dataSource : item.dataSource,
|
||||||
|
type : ClientIdentifier.Types.CONNECTION,
|
||||||
|
id : item.identifier
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the item is a connection, generate a connection group identifier
|
||||||
|
if (item.isConnectionGroup)
|
||||||
|
return ClientIdentifier.toString({
|
||||||
|
dataSource : item.dataSource,
|
||||||
|
type : ClientIdentifier.Types.CONNECTION_GROUP,
|
||||||
|
id : item.identifier
|
||||||
|
});
|
||||||
|
|
||||||
|
// Otherwise, no such identifier can exist
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Retrieve root groups and all descendants
|
||||||
|
dataSourceService.apply(
|
||||||
|
connectionGroupService.getConnectionGroupTree,
|
||||||
|
authenticationService.getAvailableDataSources(),
|
||||||
|
ConnectionGroup.ROOT_IDENTIFIER
|
||||||
|
)
|
||||||
|
.then(function rootGroupsRetrieved(rootConnectionGroups) {
|
||||||
|
$scope.rootConnectionGroups = rootConnectionGroups;
|
||||||
});
|
});
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
@@ -31,13 +31,15 @@ angular.module('home').directive('guacRecentConnections', [function guacRecentCo
|
|||||||
scope: {
|
scope: {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root connection group, and all visible descendants.
|
* The root connection groups to display, and all visible
|
||||||
* Recent connections will only be shown if they exist within this
|
* descendants, as a map of data source identifier to the root
|
||||||
* hierarchy, regardless of their existence within the history.
|
* connection group within that data source. Recent connections
|
||||||
|
* will only be shown if they exist within this hierarchy,
|
||||||
|
* regardless of their existence within the history.
|
||||||
*
|
*
|
||||||
* @type ConnectionGroup
|
* @type Object.<String, ConnectionGroup>
|
||||||
*/
|
*/
|
||||||
rootGroup : '='
|
rootGroups : '='
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -46,6 +48,7 @@ angular.module('home').directive('guacRecentConnections', [function guacRecentCo
|
|||||||
|
|
||||||
// Required types
|
// Required types
|
||||||
var ActiveConnection = $injector.get('ActiveConnection');
|
var ActiveConnection = $injector.get('ActiveConnection');
|
||||||
|
var ClientIdentifier = $injector.get('ClientIdentifier');
|
||||||
var RecentConnection = $injector.get('RecentConnection');
|
var RecentConnection = $injector.get('RecentConnection');
|
||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
@@ -91,42 +94,62 @@ angular.module('home').directive('guacRecentConnections', [function guacRecentCo
|
|||||||
/**
|
/**
|
||||||
* Adds the given connection to the internal set of visible
|
* Adds the given connection to the internal set of visible
|
||||||
* objects.
|
* objects.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The identifier of the data source associated with the
|
||||||
|
* given connection group.
|
||||||
|
*
|
||||||
* @param {Connection} connection
|
* @param {Connection} connection
|
||||||
* The connection to add to the internal set of visible objects.
|
* The connection to add to the internal set of visible objects.
|
||||||
*/
|
*/
|
||||||
var addVisibleConnection = function addVisibleConnection(connection) {
|
var addVisibleConnection = function addVisibleConnection(dataSource, connection) {
|
||||||
|
|
||||||
// Add given connection to set of visible objects
|
// Add given connection to set of visible objects
|
||||||
visibleObjects['c/' + connection.identifier] = connection;
|
visibleObjects[ClientIdentifier.toString({
|
||||||
|
dataSource : dataSource,
|
||||||
|
type : ClientIdentifier.Types.CONNECTION,
|
||||||
|
id : connection.identifier
|
||||||
|
})] = connection;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given connection group to the internal set of visible
|
* Adds the given connection group to the internal set of visible
|
||||||
* objects, along with any descendants.
|
* objects, along with any descendants.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The identifier of the data source associated with the
|
||||||
|
* given connection group.
|
||||||
|
*
|
||||||
* @param {ConnectionGroup} connectionGroup
|
* @param {ConnectionGroup} connectionGroup
|
||||||
* The connection group to add to the internal set of visible
|
* The connection group to add to the internal set of visible
|
||||||
* objects, along with any descendants.
|
* objects, along with any descendants.
|
||||||
*/
|
*/
|
||||||
var addVisibleConnectionGroup = function addVisibleConnectionGroup(connectionGroup) {
|
var addVisibleConnectionGroup = function addVisibleConnectionGroup(dataSource, connectionGroup) {
|
||||||
|
|
||||||
// Add given connection group to set of visible objects
|
// Add given connection group to set of visible objects
|
||||||
visibleObjects['g/' + connectionGroup.identifier] = connectionGroup;
|
visibleObjects[ClientIdentifier.toString({
|
||||||
|
dataSource : dataSource,
|
||||||
|
type : ClientIdentifier.Types.CONNECTION_GROUP,
|
||||||
|
id : connectionGroup.identifier
|
||||||
|
})] = connectionGroup;
|
||||||
|
|
||||||
// Add all child connections
|
// Add all child connections
|
||||||
if (connectionGroup.childConnections)
|
if (connectionGroup.childConnections)
|
||||||
connectionGroup.childConnections.forEach(addVisibleConnection);
|
connectionGroup.childConnections.forEach(function addChildConnection(child) {
|
||||||
|
addVisibleConnection(dataSource, child);
|
||||||
|
});
|
||||||
|
|
||||||
// Add all child connection groups
|
// Add all child connection groups
|
||||||
if (connectionGroup.childConnectionGroups)
|
if (connectionGroup.childConnectionGroups)
|
||||||
connectionGroup.childConnectionGroups.forEach(addVisibleConnectionGroup);
|
connectionGroup.childConnectionGroups.forEach(function addChildConnectionGroup(child) {
|
||||||
|
addVisibleConnectionGroup(dataSource, child);
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update visible objects when root group is set
|
// Update visible objects when root groups are set
|
||||||
$scope.$watch("rootGroup", function setRootGroup(rootGroup) {
|
$scope.$watch("rootGroups", function setRootGroups(rootGroups) {
|
||||||
|
|
||||||
// Clear connection arrays
|
// Clear connection arrays
|
||||||
$scope.activeConnections = [];
|
$scope.activeConnections = [];
|
||||||
@@ -134,8 +157,11 @@ angular.module('home').directive('guacRecentConnections', [function guacRecentCo
|
|||||||
|
|
||||||
// Produce collection of visible objects
|
// Produce collection of visible objects
|
||||||
visibleObjects = {};
|
visibleObjects = {};
|
||||||
if (rootGroup)
|
if (rootGroups) {
|
||||||
addVisibleConnectionGroup(rootGroup);
|
angular.forEach(rootGroups, function addConnectionGroup(rootGroup, dataSource) {
|
||||||
|
addVisibleConnectionGroup(dataSource, rootGroup);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var managedClients = guacClientManager.getManagedClients();
|
var managedClients = guacClientManager.getManagedClients();
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<a ng-href="#/client/c/{{item.identifier}}">
|
<a ng-href="#/client/{{context.getClientIdentifier(item)}}">
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2014 Glyptodon LLC
|
Copyright (C) 2014 Glyptodon LLC
|
||||||
|
|
||||||
|
@@ -21,6 +21,6 @@
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<a ng-show="item.isBalancing" ng-href="#/client/g/{{item.identifier}}">{{item.name}}</a>
|
<a ng-show="item.isBalancing" ng-href="#/client/{{context.getClientIdentifier(item)}}">{{item.name}}</a>
|
||||||
<span ng-show="!item.isBalancing">{{item.name}}</span>
|
<span ng-show="!item.isBalancing">{{item.name}}</span>
|
||||||
</span>
|
</span>
|
||||||
|
@@ -30,14 +30,15 @@
|
|||||||
<guac-user-menu></guac-user-menu>
|
<guac-user-menu></guac-user-menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="recent-connections">
|
<div class="recent-connections">
|
||||||
<guac-recent-connections root-group="rootConnectionGroup"></guac-recent-connections>
|
<guac-recent-connections root-groups="rootConnectionGroups"></guac-recent-connections>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- All connections for this user -->
|
<!-- All connections for this user -->
|
||||||
<h2 class="header">{{'HOME.SECTION_HEADER_ALL_CONNECTIONS' | translate}}</h2>
|
<h2 class="header">{{'HOME.SECTION_HEADER_ALL_CONNECTIONS' | translate}}</h2>
|
||||||
<div class="all-connections">
|
<div class="all-connections">
|
||||||
<guac-group-list
|
<guac-group-list
|
||||||
connection-group="rootConnectionGroup"
|
context="context"
|
||||||
|
connection-groups="rootConnectionGroups"
|
||||||
connection-template="'app/home/templates/connection.html'"
|
connection-template="'app/home/templates/connection.html'"
|
||||||
connection-group-template="'app/home/templates/connectionGroup.html'"
|
connection-group-template="'app/home/templates/connectionGroup.html'"
|
||||||
page-size="20"></guac-group-list>
|
page-size="20"></guac-group-list>
|
||||||
|
@@ -123,7 +123,7 @@ angular.module('index').config(['$routeProvider', '$locationProvider',
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Management screen
|
// Management screen
|
||||||
.when('/settings/:tab', {
|
.when('/settings/:dataSource?/:tab', {
|
||||||
title : 'APP.NAME',
|
title : 'APP.NAME',
|
||||||
bodyClassName : 'settings',
|
bodyClassName : 'settings',
|
||||||
templateUrl : 'app/settings/templates/settings.html',
|
templateUrl : 'app/settings/templates/settings.html',
|
||||||
@@ -132,7 +132,7 @@ angular.module('index').config(['$routeProvider', '$locationProvider',
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Connection editor
|
// Connection editor
|
||||||
.when('/manage/connections/:id?', {
|
.when('/manage/:dataSource/connections/:id?', {
|
||||||
title : 'APP.NAME',
|
title : 'APP.NAME',
|
||||||
bodyClassName : 'manage',
|
bodyClassName : 'manage',
|
||||||
templateUrl : 'app/manage/templates/manageConnection.html',
|
templateUrl : 'app/manage/templates/manageConnection.html',
|
||||||
@@ -141,7 +141,7 @@ angular.module('index').config(['$routeProvider', '$locationProvider',
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Connection group editor
|
// Connection group editor
|
||||||
.when('/manage/connectionGroups/:id?', {
|
.when('/manage/:dataSource/connectionGroups/:id?', {
|
||||||
title : 'APP.NAME',
|
title : 'APP.NAME',
|
||||||
bodyClassName : 'manage',
|
bodyClassName : 'manage',
|
||||||
templateUrl : 'app/manage/templates/manageConnectionGroup.html',
|
templateUrl : 'app/manage/templates/manageConnectionGroup.html',
|
||||||
@@ -150,7 +150,7 @@ angular.module('index').config(['$routeProvider', '$locationProvider',
|
|||||||
})
|
})
|
||||||
|
|
||||||
// User editor
|
// User editor
|
||||||
.when('/manage/users/:id', {
|
.when('/manage/:dataSource/users/:id', {
|
||||||
title : 'APP.NAME',
|
title : 'APP.NAME',
|
||||||
bodyClassName : 'manage',
|
bodyClassName : 'manage',
|
||||||
templateUrl : 'app/manage/templates/manageUser.html',
|
templateUrl : 'app/manage/templates/manageUser.html',
|
||||||
@@ -159,7 +159,7 @@ angular.module('index').config(['$routeProvider', '$locationProvider',
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Client view
|
// Client view
|
||||||
.when('/client/:type/:id/:params?', {
|
.when('/client/:id/:params?', {
|
||||||
bodyClassName : 'client',
|
bodyClassName : 'client',
|
||||||
templateUrl : 'app/client/templates/client.html',
|
templateUrl : 'app/client/templates/client.html',
|
||||||
controller : 'clientController',
|
controller : 'clientController',
|
||||||
|
@@ -55,7 +55,15 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
guacNotification.showStatus(false);
|
guacNotification.showStatus(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of the data source containing the connection being
|
||||||
|
* edited.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
var dataSource = $routeParams.dataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the original connection from which this connection is
|
* The identifier of the original connection from which this connection is
|
||||||
* being cloned. Only valid if this is a new connection.
|
* being cloned. Only valid if this is a new connection.
|
||||||
@@ -178,20 +186,24 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Pull connection attribute schema
|
// Pull connection attribute schema
|
||||||
schemaService.getConnectionAttributes().success(function attributesReceived(attributes) {
|
schemaService.getConnectionAttributes(dataSource)
|
||||||
|
.success(function attributesReceived(attributes) {
|
||||||
$scope.attributes = attributes;
|
$scope.attributes = attributes;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pull connection group hierarchy
|
// Pull connection group hierarchy
|
||||||
connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER,
|
connectionGroupService.getConnectionGroupTree(
|
||||||
[PermissionSet.ObjectPermissionType.ADMINISTER])
|
dataSource,
|
||||||
|
ConnectionGroup.ROOT_IDENTIFIER,
|
||||||
|
[PermissionSet.ObjectPermissionType.ADMINISTER]
|
||||||
|
)
|
||||||
.success(function connectionGroupReceived(rootGroup) {
|
.success(function connectionGroupReceived(rootGroup) {
|
||||||
$scope.rootGroup = rootGroup;
|
$scope.rootGroup = rootGroup;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Query the user's permissions for the current connection
|
// Query the user's permissions for the current connection
|
||||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
permissionService.getPermissions(dataSource, authenticationService.getCurrentUsername())
|
||||||
.success(function permissionsReceived(permissions) {
|
.success(function permissionsReceived(permissions) {
|
||||||
|
|
||||||
$scope.permissions = permissions;
|
$scope.permissions = permissions;
|
||||||
|
|
||||||
@@ -220,7 +232,8 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Get protocol metadata
|
// Get protocol metadata
|
||||||
schemaService.getProtocols().success(function protocolsReceived(protocols) {
|
schemaService.getProtocols(dataSource)
|
||||||
|
.success(function protocolsReceived(protocols) {
|
||||||
$scope.protocols = protocols;
|
$scope.protocols = protocols;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -233,12 +246,14 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
if (identifier) {
|
if (identifier) {
|
||||||
|
|
||||||
// Pull data from existing connection
|
// Pull data from existing connection
|
||||||
connectionService.getConnection(identifier).success(function connectionRetrieved(connection) {
|
connectionService.getConnection(dataSource, identifier)
|
||||||
|
.success(function connectionRetrieved(connection) {
|
||||||
$scope.connection = connection;
|
$scope.connection = connection;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pull connection history
|
// Pull connection history
|
||||||
connectionService.getConnectionHistory(identifier).success(function historyReceived(historyEntries) {
|
connectionService.getConnectionHistory(dataSource, identifier)
|
||||||
|
.success(function historyReceived(historyEntries) {
|
||||||
|
|
||||||
// Wrap all history entries for sake of display
|
// Wrap all history entries for sake of display
|
||||||
$scope.historyEntryWrappers = [];
|
$scope.historyEntryWrappers = [];
|
||||||
@@ -249,7 +264,8 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Pull connection parameters
|
// Pull connection parameters
|
||||||
connectionService.getConnectionParameters(identifier).success(function parametersReceived(parameters) {
|
connectionService.getConnectionParameters(dataSource, identifier)
|
||||||
|
.success(function parametersReceived(parameters) {
|
||||||
$scope.parameters = parameters;
|
$scope.parameters = parameters;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -258,7 +274,8 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
else if (cloneSourceIdentifier) {
|
else if (cloneSourceIdentifier) {
|
||||||
|
|
||||||
// Pull data from cloned connection
|
// Pull data from cloned connection
|
||||||
connectionService.getConnection(cloneSourceIdentifier).success(function connectionRetrieved(connection) {
|
connectionService.getConnection(dataSource, cloneSourceIdentifier)
|
||||||
|
.success(function connectionRetrieved(connection) {
|
||||||
$scope.connection = connection;
|
$scope.connection = connection;
|
||||||
|
|
||||||
// Clear the identifier field because this connection is new
|
// Clear the identifier field because this connection is new
|
||||||
@@ -269,7 +286,8 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
$scope.historyEntryWrappers = [];
|
$scope.historyEntryWrappers = [];
|
||||||
|
|
||||||
// Pull connection parameters from cloned connection
|
// Pull connection parameters from cloned connection
|
||||||
connectionService.getConnectionParameters(cloneSourceIdentifier).success(function parametersReceived(parameters) {
|
connectionService.getConnectionParameters(dataSource, cloneSourceIdentifier)
|
||||||
|
.success(function parametersReceived(parameters) {
|
||||||
$scope.parameters = parameters;
|
$scope.parameters = parameters;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -332,7 +350,7 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
* Cancels all pending edits, returning to the management page.
|
* Cancels all pending edits, returning to the management page.
|
||||||
*/
|
*/
|
||||||
$scope.cancel = function cancel() {
|
$scope.cancel = function cancel() {
|
||||||
$location.path('/settings/connections');
|
$location.path('/settings/' + encodeURIComponent(dataSource) + '/connections');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -340,7 +358,7 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
* which is prepopulated with the data from the connection currently being edited.
|
* which is prepopulated with the data from the connection currently being edited.
|
||||||
*/
|
*/
|
||||||
$scope.cloneConnection = function cloneConnection() {
|
$scope.cloneConnection = function cloneConnection() {
|
||||||
$location.path('/manage/connections').search('clone', identifier);
|
$location.path('/manage/' + encodeURIComponent(dataSource) + '/connections').search('clone', identifier);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -352,9 +370,9 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
$scope.connection.parameters = $scope.parameters;
|
$scope.connection.parameters = $scope.parameters;
|
||||||
|
|
||||||
// Save the connection
|
// Save the connection
|
||||||
connectionService.saveConnection($scope.connection)
|
connectionService.saveConnection(dataSource, $scope.connection)
|
||||||
.success(function savedConnection() {
|
.success(function savedConnection() {
|
||||||
$location.path('/settings/connections');
|
$location.path('/settings/' + encodeURIComponent(dataSource) + '/connections');
|
||||||
})
|
})
|
||||||
|
|
||||||
// Notify of any errors
|
// Notify of any errors
|
||||||
@@ -402,9 +420,9 @@ angular.module('manage').controller('manageConnectionController', ['$scope', '$i
|
|||||||
var deleteConnectionImmediately = function deleteConnectionImmediately() {
|
var deleteConnectionImmediately = function deleteConnectionImmediately() {
|
||||||
|
|
||||||
// Delete the connection
|
// Delete the connection
|
||||||
connectionService.deleteConnection($scope.connection)
|
connectionService.deleteConnection(dataSource, $scope.connection)
|
||||||
.success(function deletedConnection() {
|
.success(function deletedConnection() {
|
||||||
$location.path('/settings/connections');
|
$location.path('/settings/' + encodeURIComponent(dataSource) + '/connections');
|
||||||
})
|
})
|
||||||
|
|
||||||
// Notify of any errors
|
// Notify of any errors
|
||||||
|
@@ -51,6 +51,14 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope'
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of the data source containing the connection group
|
||||||
|
* being edited.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
var dataSource = $routeParams.dataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the connection group being edited. If a new connection
|
* The identifier of the connection group being edited. If a new connection
|
||||||
* group is being created, this will not be defined.
|
* group is being created, this will not be defined.
|
||||||
@@ -123,13 +131,14 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope'
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Pull connection group attribute schema
|
// Pull connection group attribute schema
|
||||||
schemaService.getConnectionGroupAttributes().success(function attributesReceived(attributes) {
|
schemaService.getConnectionGroupAttributes(dataSource)
|
||||||
|
.success(function attributesReceived(attributes) {
|
||||||
$scope.attributes = attributes;
|
$scope.attributes = attributes;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Query the user's permissions for the current connection group
|
// Query the user's permissions for the current connection group
|
||||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
permissionService.getPermissions(dataSource, authenticationService.getCurrentUsername())
|
||||||
.success(function permissionsReceived(permissions) {
|
.success(function permissionsReceived(permissions) {
|
||||||
|
|
||||||
$scope.permissions = permissions;
|
$scope.permissions = permissions;
|
||||||
|
|
||||||
@@ -150,14 +159,19 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope'
|
|||||||
|
|
||||||
|
|
||||||
// Pull connection group hierarchy
|
// Pull connection group hierarchy
|
||||||
connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER, [PermissionSet.ObjectPermissionType.ADMINISTER])
|
connectionGroupService.getConnectionGroupTree(
|
||||||
|
dataSource,
|
||||||
|
ConnectionGroup.ROOT_IDENTIFIER,
|
||||||
|
[PermissionSet.ObjectPermissionType.ADMINISTER]
|
||||||
|
)
|
||||||
.success(function connectionGroupReceived(rootGroup) {
|
.success(function connectionGroupReceived(rootGroup) {
|
||||||
$scope.rootGroup = rootGroup;
|
$scope.rootGroup = rootGroup;
|
||||||
});
|
});
|
||||||
|
|
||||||
// If we are editing an existing connection group, pull its data
|
// If we are editing an existing connection group, pull its data
|
||||||
if (identifier) {
|
if (identifier) {
|
||||||
connectionGroupService.getConnectionGroup(identifier).success(function connectionGroupReceived(connectionGroup) {
|
connectionGroupService.getConnectionGroup(dataSource, identifier)
|
||||||
|
.success(function connectionGroupReceived(connectionGroup) {
|
||||||
$scope.connectionGroup = connectionGroup;
|
$scope.connectionGroup = connectionGroup;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -187,7 +201,7 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope'
|
|||||||
* Cancels all pending edits, returning to the management page.
|
* Cancels all pending edits, returning to the management page.
|
||||||
*/
|
*/
|
||||||
$scope.cancel = function cancel() {
|
$scope.cancel = function cancel() {
|
||||||
$location.path('/settings/connections');
|
$location.path('/settings/' + encodeURIComponent(dataSource) + '/connections');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,9 +211,9 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope'
|
|||||||
$scope.saveConnectionGroup = function saveConnectionGroup() {
|
$scope.saveConnectionGroup = function saveConnectionGroup() {
|
||||||
|
|
||||||
// Save the connection
|
// Save the connection
|
||||||
connectionGroupService.saveConnectionGroup($scope.connectionGroup)
|
connectionGroupService.saveConnectionGroup(dataSource, $scope.connectionGroup)
|
||||||
.success(function savedConnectionGroup() {
|
.success(function savedConnectionGroup() {
|
||||||
$location.path('/settings/connections');
|
$location.path('/settings/' + encodeURIComponent(dataSource) + '/connections');
|
||||||
})
|
})
|
||||||
|
|
||||||
// Notify of any errors
|
// Notify of any errors
|
||||||
@@ -247,9 +261,9 @@ angular.module('manage').controller('manageConnectionGroupController', ['$scope'
|
|||||||
var deleteConnectionGroupImmediately = function deleteConnectionGroupImmediately() {
|
var deleteConnectionGroupImmediately = function deleteConnectionGroupImmediately() {
|
||||||
|
|
||||||
// Delete the connection group
|
// Delete the connection group
|
||||||
connectionGroupService.deleteConnectionGroup($scope.connectionGroup)
|
connectionGroupService.deleteConnectionGroup(dataSource, $scope.connectionGroup)
|
||||||
.success(function deletedConnectionGroup() {
|
.success(function deletedConnectionGroup() {
|
||||||
$location.path('/settings/connections');
|
$location.path('/settings/' + encodeURIComponent(dataSource) + '/connections');
|
||||||
})
|
})
|
||||||
|
|
||||||
// Notify of any errors
|
// Notify of any errors
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -28,18 +28,23 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
|
|||||||
|
|
||||||
// Required types
|
// Required types
|
||||||
var ConnectionGroup = $injector.get('ConnectionGroup');
|
var ConnectionGroup = $injector.get('ConnectionGroup');
|
||||||
|
var PageDefinition = $injector.get('PageDefinition');
|
||||||
var PermissionFlagSet = $injector.get('PermissionFlagSet');
|
var PermissionFlagSet = $injector.get('PermissionFlagSet');
|
||||||
var PermissionSet = $injector.get('PermissionSet');
|
var PermissionSet = $injector.get('PermissionSet');
|
||||||
|
var User = $injector.get('User');
|
||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $location = $injector.get('$location');
|
var $location = $injector.get('$location');
|
||||||
var $routeParams = $injector.get('$routeParams');
|
var $routeParams = $injector.get('$routeParams');
|
||||||
var authenticationService = $injector.get('authenticationService');
|
var $q = $injector.get('$q');
|
||||||
var connectionGroupService = $injector.get('connectionGroupService');
|
var authenticationService = $injector.get('authenticationService');
|
||||||
var guacNotification = $injector.get('guacNotification');
|
var connectionGroupService = $injector.get('connectionGroupService');
|
||||||
var permissionService = $injector.get('permissionService');
|
var dataSourceService = $injector.get('dataSourceService');
|
||||||
var schemaService = $injector.get('schemaService');
|
var guacNotification = $injector.get('guacNotification');
|
||||||
var userService = $injector.get('userService');
|
var permissionService = $injector.get('permissionService');
|
||||||
|
var schemaService = $injector.get('schemaService');
|
||||||
|
var translationStringService = $injector.get('translationStringService');
|
||||||
|
var userService = $injector.get('userService');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action to be provided along with the object sent to showStatus which
|
* An action to be provided along with the object sent to showStatus which
|
||||||
@@ -53,6 +58,29 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifiers of all data sources currently available to the
|
||||||
|
* authenticated user.
|
||||||
|
*
|
||||||
|
* @type String[]
|
||||||
|
*/
|
||||||
|
var dataSources = authenticationService.getAvailableDataSources();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username of the current, authenticated user.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
var currentUsername = authenticationService.getCurrentUsername();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of the data source containing the user being
|
||||||
|
* edited.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
var dataSource = $routeParams.dataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The username of the user being edited.
|
* The username of the user being edited.
|
||||||
*
|
*
|
||||||
@@ -60,6 +88,16 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
|
|||||||
*/
|
*/
|
||||||
var username = $routeParams.id;
|
var username = $routeParams.id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user being modified actually exists. If the user does not
|
||||||
|
* yet exist, a different REST service call must be made to create that
|
||||||
|
* user rather than update an existing user. If the user has not yet been
|
||||||
|
* loaded, this will be null.
|
||||||
|
*
|
||||||
|
* @type Boolean
|
||||||
|
*/
|
||||||
|
var userExists = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The user being modified.
|
* The user being modified.
|
||||||
*
|
*
|
||||||
@@ -75,26 +113,14 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
|
|||||||
$scope.permissionFlags = null;
|
$scope.permissionFlags = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root connection group of the connection group hierarchy.
|
* A map of data source identifiers to the root connection groups within
|
||||||
|
* thost data sources. As only one data source is applicable to any one
|
||||||
|
* user being edited/created, this will only contain a single key.
|
||||||
*
|
*
|
||||||
* @type ConnectionGroup
|
* @type Object.<String, ConnectionGroup>
|
||||||
*/
|
*/
|
||||||
$scope.rootGroup = null;
|
$scope.rootGroups = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the authenticated user has UPDATE permission for the user being edited.
|
|
||||||
*
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
$scope.hasUpdatePermission = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the authenticated user has DELETE permission for the user being edited.
|
|
||||||
*
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
$scope.hasDeletePermission = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All permissions associated with the current user, or null if the user's
|
* All permissions associated with the current user, or null if the user's
|
||||||
* permissions have not yet been loaded.
|
* permissions have not yet been loaded.
|
||||||
@@ -112,6 +138,14 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
|
|||||||
*/
|
*/
|
||||||
$scope.attributes = null;
|
$scope.attributes = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The pages associated with each user account having the given username.
|
||||||
|
* Each user account will be associated with a particular data source.
|
||||||
|
*
|
||||||
|
* @type PageDefinition[]
|
||||||
|
*/
|
||||||
|
$scope.accountPages = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether critical data has completed being loaded.
|
* Returns whether critical data has completed being loaded.
|
||||||
*
|
*
|
||||||
@@ -123,54 +157,227 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
|
|||||||
|
|
||||||
return $scope.user !== null
|
return $scope.user !== null
|
||||||
&& $scope.permissionFlags !== null
|
&& $scope.permissionFlags !== null
|
||||||
&& $scope.rootGroup !== null
|
&& $scope.rootGroups !== null
|
||||||
&& $scope.permissions !== null
|
&& $scope.permissions !== null
|
||||||
&& $scope.attributes !== null
|
&& $scope.attributes !== null;
|
||||||
&& $scope.canSaveUser !== null
|
|
||||||
&& $scope.canDeleteUser !== null;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can change attributes associated with
|
||||||
|
* the user being edited.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the current user can change attributes associated with the
|
||||||
|
* user being edited, false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.canChangeAttributes = function canChangeAttributes() {
|
||||||
|
|
||||||
|
// Do not check if permissions are not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Attributes can always be set if we are creating the user
|
||||||
|
if (!userExists)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// The administrator can always change attributes
|
||||||
|
if (PermissionSet.hasSystemPermission($scope.permissions,
|
||||||
|
PermissionSet.SystemPermissionType.ADMINISTER))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Otherwise, can change attributes if we have permission to update this user
|
||||||
|
return PermissionSet.hasUserPermission($scope.permissions,
|
||||||
|
PermissionSet.ObjectPermissionType.UPDATE, username);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can change permissions of any kind
|
||||||
|
* which are associated with the user being edited.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the current user can grant or revoke permissions of any kind
|
||||||
|
* which are associated with the user being edited, false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.canChangePermissions = function canChangePermissions() {
|
||||||
|
|
||||||
|
// Do not check if permissions are not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Permissions can always be set if we are creating the user
|
||||||
|
if (!userExists)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// The administrator can always modify permissions
|
||||||
|
if (PermissionSet.hasSystemPermission($scope.permissions,
|
||||||
|
PermissionSet.SystemPermissionType.ADMINISTER))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Otherwise, can only modify permissions if we have explicit
|
||||||
|
// ADMINISTER permission
|
||||||
|
return PermissionSet.hasUserPermission($scope.permissions,
|
||||||
|
PermissionSet.ObjectPermissionType.ADMINISTER, username);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can change the system permissions
|
||||||
|
* granted to the user being edited.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the current user can grant or revoke system permissions to
|
||||||
|
* the user being edited, false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.canChangeSystemPermissions = function canChangeSystemPermissions() {
|
||||||
|
|
||||||
|
// Do not check if permissions are not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Only the administrator can modify system permissions
|
||||||
|
return PermissionSet.hasSystemPermission($scope.permissions,
|
||||||
|
PermissionSet.SystemPermissionType.ADMINISTER);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can save the user being edited. Saving
|
||||||
|
* will create or update that user depending on whether the user already
|
||||||
|
* exists.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the current user can save changes to the user being edited,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.canSaveUser = function canSaveUser() {
|
||||||
|
|
||||||
|
// Do not check if permissions are not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The administrator can always save users
|
||||||
|
if (PermissionSet.hasSystemPermission($scope.permissions,
|
||||||
|
PermissionSet.SystemPermissionType.ADMINISTER))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If user does not exist, can only save if we have permission to create users
|
||||||
|
if (!userExists)
|
||||||
|
return PermissionSet.hasSystemPermission($scope.permissions,
|
||||||
|
PermissionSet.SystemPermissionType.CREATE_USER);
|
||||||
|
|
||||||
|
// Otherwise, can only save if we have permission to update this user
|
||||||
|
return PermissionSet.hasUserPermission($scope.permissions,
|
||||||
|
PermissionSet.ObjectPermissionType.UPDATE, username);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can delete the user being edited.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the current user can delete the user being edited, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
$scope.canDeleteUser = function canDeleteUser() {
|
||||||
|
|
||||||
|
// Do not check if permissions are not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Can't delete what doesn't exist
|
||||||
|
if (!userExists)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The administrator can always delete users
|
||||||
|
if (PermissionSet.hasSystemPermission($scope.permissions,
|
||||||
|
PermissionSet.SystemPermissionType.ADMINISTER))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Otherwise, require explicit DELETE permission on the user
|
||||||
|
return PermissionSet.hasUserPermission($scope.permissions,
|
||||||
|
PermissionSet.ObjectPermissionType.DELETE, username);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the user being edited is read-only, and thus cannot be
|
||||||
|
* modified by the current user.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the user being edited is actually read-only and cannot be
|
||||||
|
* edited at all, false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.isReadOnly = function isReadOnly() {
|
||||||
|
return !$scope.canSaveUser();
|
||||||
|
};
|
||||||
|
|
||||||
// Pull user attribute schema
|
// Pull user attribute schema
|
||||||
schemaService.getUserAttributes().success(function attributesReceived(attributes) {
|
schemaService.getUserAttributes(dataSource).success(function attributesReceived(attributes) {
|
||||||
$scope.attributes = attributes;
|
$scope.attributes = attributes;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pull user data
|
// Pull user data
|
||||||
userService.getUser(username).success(function userReceived(user) {
|
dataSourceService.apply(userService.getUser, dataSources, username)
|
||||||
$scope.user = user;
|
.then(function usersReceived(users) {
|
||||||
|
|
||||||
|
// Get user for currently-selected data source
|
||||||
|
$scope.user = users[dataSource];
|
||||||
|
|
||||||
|
// Create skeleton user if user does not exist
|
||||||
|
if (!$scope.user) {
|
||||||
|
userExists = false;
|
||||||
|
$scope.user = new User({
|
||||||
|
'username' : username
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
userExists = true;
|
||||||
|
|
||||||
|
// Generate pages for each applicable data source
|
||||||
|
$scope.accountPages = [];
|
||||||
|
angular.forEach(dataSources, function addAccountPage(dataSource) {
|
||||||
|
|
||||||
|
// Determine whether data source contains this user
|
||||||
|
var linked = dataSource in users;
|
||||||
|
|
||||||
|
// Add page entry
|
||||||
|
$scope.accountPages.push(new PageDefinition({
|
||||||
|
name : translationStringService.canonicalize('DATA_SOURCE_' + dataSource) + '.NAME',
|
||||||
|
url : '/manage/' + encodeURIComponent(dataSource) + '/users/' + encodeURIComponent(username),
|
||||||
|
className : linked ? 'linked' : 'unlinked'
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pull user permissions
|
// Pull user permissions
|
||||||
permissionService.getPermissions(username).success(function gotPermissions(permissions) {
|
permissionService.getPermissions(dataSource, username).success(function gotPermissions(permissions) {
|
||||||
$scope.permissionFlags = PermissionFlagSet.fromPermissionSet(permissions);
|
$scope.permissionFlags = PermissionFlagSet.fromPermissionSet(permissions);
|
||||||
|
})
|
||||||
|
|
||||||
|
// If permissions cannot be retrieved, use empty permissions
|
||||||
|
.error(function permissionRetrievalFailed() {
|
||||||
|
$scope.permissionFlags = new PermissionFlagSet();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Retrieve all connections for which we have ADMINISTER permission
|
// Retrieve all connections for which we have ADMINISTER permission
|
||||||
connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER, [PermissionSet.ObjectPermissionType.ADMINISTER])
|
dataSourceService.apply(
|
||||||
.success(function connectionGroupReceived(rootGroup) {
|
connectionGroupService.getConnectionGroupTree,
|
||||||
$scope.rootGroup = rootGroup;
|
[dataSource],
|
||||||
|
ConnectionGroup.ROOT_IDENTIFIER,
|
||||||
|
[PermissionSet.ObjectPermissionType.ADMINISTER]
|
||||||
|
)
|
||||||
|
.then(function connectionGroupReceived(rootGroups) {
|
||||||
|
$scope.rootGroups = rootGroups;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Query the user's permissions for the current connection
|
// Query the user's permissions for the current user
|
||||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
permissionService.getPermissions(dataSource, currentUsername)
|
||||||
.success(function permissionsReceived(permissions) {
|
.success(function permissionsReceived(permissions) {
|
||||||
|
|
||||||
$scope.permissions = permissions;
|
$scope.permissions = permissions;
|
||||||
|
|
||||||
// Check if the user is new or if the user has UPDATE permission
|
|
||||||
$scope.canSaveUser =
|
|
||||||
!username
|
|
||||||
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
|
||||||
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, username);
|
|
||||||
|
|
||||||
// Check if user is not new and the user has DELETE permission
|
|
||||||
$scope.canDeleteUser =
|
|
||||||
!!username && (
|
|
||||||
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
|
||||||
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.DELETE, username)
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -507,12 +714,17 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the user
|
// Save or create the user, depending on whether the user exists
|
||||||
userService.saveUser($scope.user)
|
var saveUserPromise;
|
||||||
.success(function savedUser() {
|
if (userExists)
|
||||||
|
saveUserPromise = userService.saveUser(dataSource, $scope.user);
|
||||||
|
else
|
||||||
|
saveUserPromise = userService.createUser(dataSource, $scope.user);
|
||||||
|
|
||||||
|
saveUserPromise.success(function savedUser() {
|
||||||
|
|
||||||
// Upon success, save any changed permissions
|
// Upon success, save any changed permissions
|
||||||
permissionService.patchPermissions($scope.user.username, permissionsAdded, permissionsRemoved)
|
permissionService.patchPermissions(dataSource, $scope.user.username, permissionsAdded, permissionsRemoved)
|
||||||
.success(function patchedUserPermissions() {
|
.success(function patchedUserPermissions() {
|
||||||
$location.path('/settings/users');
|
$location.path('/settings/users');
|
||||||
})
|
})
|
||||||
@@ -574,7 +786,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
|
|||||||
var deleteUserImmediately = function deleteUserImmediately() {
|
var deleteUserImmediately = function deleteUserImmediately() {
|
||||||
|
|
||||||
// Delete the user
|
// Delete the user
|
||||||
userService.deleteUser($scope.user)
|
userService.deleteUser(dataSource, $scope.user)
|
||||||
.success(function deletedUser() {
|
.success(function deletedUser() {
|
||||||
$location.path('/settings/users');
|
$location.path('/settings/users');
|
||||||
})
|
})
|
||||||
|
65
guacamole/src/main/webapp/app/manage/styles/manage-user.css
Normal file
65
guacamole/src/main/webapp/app/manage/styles/manage-user.css
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.manage-user .username.header {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-user .username.header h2 {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-user .page-tabs .page-list li.unlinked a[href],
|
||||||
|
.manage-user .page-tabs .page-list li.linked a[href] {
|
||||||
|
padding-right: 2.5em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-user .page-tabs .page-list li.unlinked a[href]:before,
|
||||||
|
.manage-user .page-tabs .page-list li.linked a[href]:before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 2.5em;
|
||||||
|
background-size: 1.25em;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-user .page-tabs .page-list li.unlinked a[href]:before {
|
||||||
|
background-image: url('images/plus.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-user .page-tabs .page-list li.unlinked a[href] {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-user .page-tabs .page-list li.unlinked a[href]:hover,
|
||||||
|
.manage-user .page-tabs .page-list li.unlinked a[href].current {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage-user .page-tabs .page-list li.linked a[href]:before {
|
||||||
|
background-image: url('images/checkmark.png');
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
Copyright 2014 Glyptodon LLC.
|
Copyright 2015 Glyptodon LLC.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -20,70 +20,84 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<div class="view" ng-class="{loading: !isLoaded()}">
|
<div class="manage-user view" ng-class="{loading: !isLoaded()}">
|
||||||
|
|
||||||
<!-- Main property editor -->
|
<!-- User header and data source tabs -->
|
||||||
<div class="header">
|
<div class="username header">
|
||||||
<h2>{{'MANAGE_USER.SECTION_HEADER_EDIT_USER' | translate}}</h2>
|
<h2>{{user.username}}</h2>
|
||||||
<guac-user-menu></guac-user-menu>
|
<guac-user-menu></guac-user-menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="section">
|
<div class="page-tabs">
|
||||||
<table class="properties">
|
<guac-page-list pages="accountPages"></guac-page-list>
|
||||||
<tr>
|
|
||||||
<th>{{'MANAGE_USER.FIELD_HEADER_USERNAME' | translate}}</th>
|
|
||||||
|
|
||||||
<td>{{user.username}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>{{'MANAGE_USER.FIELD_HEADER_PASSWORD' | translate}}</th>
|
|
||||||
|
|
||||||
<td><input ng-model="user.password" type="password" /></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>{{'MANAGE_USER.FIELD_HEADER_PASSWORD_AGAIN' | translate}}</th>
|
|
||||||
|
|
||||||
<td><input ng-model="passwordMatch" type="password" /></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- User attributes section -->
|
<!-- Warn if user is read-only -->
|
||||||
<div class="attributes">
|
<div class="section" ng-show="isReadOnly()">
|
||||||
<guac-form namespace="'USER_ATTRIBUTES'" content="attributes" model="user.attributes"></guac-form>
|
<p class="notice read-only">{{'MANAGE_USER.INFO_READ_ONLY' | translate}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- System permissions section -->
|
<!-- Sections applicable to non-read-only users -->
|
||||||
<h2 class="header">{{'MANAGE_USER.SECTION_HEADER_PERMISSIONS' | translate}}</h2>
|
<div ng-show="!isReadOnly()">
|
||||||
<div class="section">
|
|
||||||
<table class="properties">
|
<!-- User password section -->
|
||||||
<tr ng-repeat="systemPermissionType in systemPermissionTypes">
|
<div class="section">
|
||||||
<th>{{systemPermissionType.label | translate}}</th>
|
<table class="properties">
|
||||||
<td><input type="checkbox" ng-model="permissionFlags.systemPermissions[systemPermissionType.value]"
|
<tr>
|
||||||
ng-change="systemPermissionChanged(systemPermissionType.value)"/></td>
|
<th>{{'MANAGE_USER.FIELD_HEADER_PASSWORD' | translate}}</th>
|
||||||
</tr>
|
<td><input ng-model="user.password" type="password" /></td>
|
||||||
<tr>
|
</tr>
|
||||||
<th>{{'MANAGE_USER.FIELD_HEADER_CHANGE_OWN_PASSWORD' | translate}}</th>
|
<tr>
|
||||||
<td><input type="checkbox" ng-model="permissionFlags.userPermissions.UPDATE[user.username]"
|
<th>{{'MANAGE_USER.FIELD_HEADER_PASSWORD_AGAIN' | translate}}</th>
|
||||||
ng-change="userPermissionChanged('UPDATE', user.username)"/></td>
|
<td><input ng-model="passwordMatch" type="password" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 class="header">{{'MANAGE_USER.SECTION_HEADER_CONNECTIONS' | translate}}</h2>
|
<!-- User attributes section -->
|
||||||
<div class="section" ng-class="{loading: !rootGroup}">
|
<div class="attributes" ng-show="canChangeAttributes()">
|
||||||
<guac-group-list
|
<guac-form namespace="'USER_ATTRIBUTES'" content="attributes" model="user.attributes"></guac-form>
|
||||||
context="groupListContext"
|
</div>
|
||||||
connection-group="rootGroup"
|
|
||||||
connection-template="'app/manage/templates/connectionPermission.html'"
|
<!-- System permissions section -->
|
||||||
connection-group-template="'app/manage/templates/connectionGroupPermission.html'"
|
<div class="system-permissions" ng-show="canChangePermissions()">
|
||||||
page-size="20"/>
|
<h2 class="header">{{'MANAGE_USER.SECTION_HEADER_PERMISSIONS' | translate}}</h2>
|
||||||
|
<div class="section">
|
||||||
|
<table class="properties">
|
||||||
|
<tr ng-repeat="systemPermissionType in systemPermissionTypes"
|
||||||
|
ng-show="canChangeSystemPermissions()">
|
||||||
|
<th>{{systemPermissionType.label | translate}}</th>
|
||||||
|
<td><input type="checkbox" ng-model="permissionFlags.systemPermissions[systemPermissionType.value]"
|
||||||
|
ng-change="systemPermissionChanged(systemPermissionType.value)"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{{'MANAGE_USER.FIELD_HEADER_CHANGE_OWN_PASSWORD' | translate}}</th>
|
||||||
|
<td><input type="checkbox" ng-model="permissionFlags.userPermissions.UPDATE[user.username]"
|
||||||
|
ng-change="userPermissionChanged('UPDATE', user.username)"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Connection permissions section -->
|
||||||
|
<div class="connection-permissions" ng-show="canChangePermissions()">
|
||||||
|
<h2 class="header">{{'MANAGE_USER.SECTION_HEADER_CONNECTIONS' | translate}}</h2>
|
||||||
|
<div class="section">
|
||||||
|
<guac-group-list
|
||||||
|
context="groupListContext"
|
||||||
|
connection-groups="rootGroups"
|
||||||
|
connection-template="'app/manage/templates/connectionPermission.html'"
|
||||||
|
connection-group-template="'app/manage/templates/connectionGroupPermission.html'"
|
||||||
|
page-size="20"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Form action buttons -->
|
<!-- Form action buttons -->
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<button ng-show="canSaveUser" ng-click="saveUser()">{{'MANAGE_USER.ACTION_SAVE' | translate}}</button>
|
<button ng-show="canSaveUser()" ng-click="saveUser()">{{'MANAGE_USER.ACTION_SAVE' | translate}}</button>
|
||||||
<button ng-click="cancel()">{{'MANAGE_USER.ACTION_CANCEL' | translate}}</button>
|
<button ng-click="cancel()">{{'MANAGE_USER.ACTION_CANCEL' | translate}}</button>
|
||||||
<button ng-show="canDeleteUser" ng-click="deleteUser()" class="danger">{{'MANAGE_USER.ACTION_DELETE' | translate}}</button>
|
<button ng-show="canDeleteUser()" ng-click="deleteUser()" class="danger">{{'MANAGE_USER.ACTION_DELETE' | translate}}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
56
guacamole/src/main/webapp/app/manage/types/ManageableUser.js
Normal file
56
guacamole/src/main/webapp/app/manage/types/ManageableUser.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service for defining the ManageableUser class.
|
||||||
|
*/
|
||||||
|
angular.module('manage').factory('ManageableUser', [function defineManageableUser() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pairing of an @link{User} with the identifier of its corresponding
|
||||||
|
* data source.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {Object|ManageableUser} template
|
||||||
|
*/
|
||||||
|
var ManageableUser = function ManageableUser(template) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of the data source containing this user.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.dataSource = template.dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The @link{User} object represented by this ManageableUser and
|
||||||
|
* contained within the associated data source.
|
||||||
|
*
|
||||||
|
* @type User
|
||||||
|
*/
|
||||||
|
this.user = template.user;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return ManageableUser;
|
||||||
|
|
||||||
|
}]);
|
@@ -33,7 +33,7 @@ angular.module('navigation').directive('guacPageList', [function guacPageList()
|
|||||||
/**
|
/**
|
||||||
* The array of pages to display.
|
* The array of pages to display.
|
||||||
*
|
*
|
||||||
* @type Page[]
|
* @type PageDefinition[]
|
||||||
*/
|
*/
|
||||||
pages : '='
|
pages : '='
|
||||||
|
|
||||||
@@ -42,13 +42,119 @@ angular.module('navigation').directive('guacPageList', [function guacPageList()
|
|||||||
templateUrl: 'app/navigation/templates/guacPageList.html',
|
templateUrl: 'app/navigation/templates/guacPageList.html',
|
||||||
controller: ['$scope', '$injector', function guacPageListController($scope, $injector) {
|
controller: ['$scope', '$injector', function guacPageListController($scope, $injector) {
|
||||||
|
|
||||||
// Get required services
|
// Required types
|
||||||
|
var PageDefinition = $injector.get('PageDefinition');
|
||||||
|
|
||||||
|
// Required services
|
||||||
var $location = $injector.get('$location');
|
var $location = $injector.get('$location');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the currently-displayed page.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
var currentURL = $location.url();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The names associated with the current page, if the current page
|
||||||
|
* is known. The value of this property corresponds to the value of
|
||||||
|
* PageDefinition.name. Though PageDefinition.name may be a String,
|
||||||
|
* this will always be an Array.
|
||||||
|
*
|
||||||
|
* @type String[]
|
||||||
|
*/
|
||||||
|
var currentPageName = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of each level of the page list, where a level is defined
|
||||||
|
* by a mapping of names (translation strings) to the
|
||||||
|
* PageDefinitions corresponding to those names.
|
||||||
|
*
|
||||||
|
* @type Object.<String, PageDefinition>[]
|
||||||
|
*/
|
||||||
|
$scope.levels = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the names associated with the given page, in
|
||||||
|
* hierarchical order. If the page is only associated with a single
|
||||||
|
* name, and that name is not stored as an array, it will be still
|
||||||
|
* be returned as an array containing a single item.
|
||||||
|
*
|
||||||
|
* @param {PageDefinition} page
|
||||||
|
* The page to return the names of.
|
||||||
|
*
|
||||||
|
* @return {String[]}
|
||||||
|
* An array of all names associated with the given page, in
|
||||||
|
* hierarchical order.
|
||||||
|
*/
|
||||||
|
var getPageNames = function getPageNames(page) {
|
||||||
|
|
||||||
|
// If already an array, simply return the name
|
||||||
|
if (angular.isArray(page.name))
|
||||||
|
return page.name;
|
||||||
|
|
||||||
|
// Otherwise, transform into array
|
||||||
|
return [page.name];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given PageDefinition to the overall set of pages
|
||||||
|
* displayed by this guacPageList, automatically updating the
|
||||||
|
* available levels ($scope.levels) and the contents of those
|
||||||
|
* levels.
|
||||||
|
*
|
||||||
|
* @param {PageDefinition} page
|
||||||
|
* The PageDefinition to add.
|
||||||
|
*
|
||||||
|
* @param {Number} weight
|
||||||
|
* The sorting weight to use for the page if it does not
|
||||||
|
* already have an associated weight.
|
||||||
|
*/
|
||||||
|
var addPage = function addPage(page, weight) {
|
||||||
|
|
||||||
|
// Pull all names for page
|
||||||
|
var names = getPageNames(page);
|
||||||
|
|
||||||
|
// Copy the hierarchy of this page into the displayed levels
|
||||||
|
// as far as is relevant for the currently-displayed page
|
||||||
|
for (var i = 0; i < names.length; i++) {
|
||||||
|
|
||||||
|
// Create current level, if it doesn't yet exist
|
||||||
|
var pages = $scope.levels[i];
|
||||||
|
if (!pages)
|
||||||
|
pages = $scope.levels[i] = {};
|
||||||
|
|
||||||
|
// Get the name at the current level
|
||||||
|
var name = names[i];
|
||||||
|
|
||||||
|
// Determine whether this page definition is part of the
|
||||||
|
// hierarchy containing the current page
|
||||||
|
var isCurrentPage = (currentPageName[i] === name);
|
||||||
|
|
||||||
|
// Store new page if it doesn't yet exist at this level
|
||||||
|
if (!pages[name]) {
|
||||||
|
pages[name] = new PageDefinition({
|
||||||
|
name : name,
|
||||||
|
url : isCurrentPage ? currentURL : page.url,
|
||||||
|
className : page.className,
|
||||||
|
weight : page.weight || weight
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the name at this level no longer matches the
|
||||||
|
// hierarchy of the current page, do not go any deeper
|
||||||
|
if (currentPageName[i] !== name)
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate to the given page.
|
* Navigate to the given page.
|
||||||
*
|
*
|
||||||
* @param {Page} page
|
* @param {PageDefinition} page
|
||||||
* The page to navigate to.
|
* The page to navigate to.
|
||||||
*/
|
*/
|
||||||
$scope.navigateToPage = function navigateToPage(page) {
|
$scope.navigateToPage = function navigateToPage(page) {
|
||||||
@@ -58,16 +164,85 @@ angular.module('navigation').directive('guacPageList', [function guacPageList()
|
|||||||
/**
|
/**
|
||||||
* Tests whether the given page is the page currently being viewed.
|
* Tests whether the given page is the page currently being viewed.
|
||||||
*
|
*
|
||||||
* @param {Page} page
|
* @param {PageDefinition} page
|
||||||
* The page to test.
|
* The page to test.
|
||||||
*
|
*
|
||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
* true if the given page is the current page, false otherwise.
|
* true if the given page is the current page, false otherwise.
|
||||||
*/
|
*/
|
||||||
$scope.isCurrentPage = function isCurrentPage(page) {
|
$scope.isCurrentPage = function isCurrentPage(page) {
|
||||||
return $location.url() === page.url;
|
return currentURL === page.url;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an arbitrary map of PageDefinitions, returns an array of
|
||||||
|
* those PageDefinitions, sorted by weight.
|
||||||
|
*
|
||||||
|
* @param {Object.<*, PageDefinition>} level
|
||||||
|
* A map of PageDefinitions with arbitrary keys. The value of
|
||||||
|
* each key is ignored.
|
||||||
|
*
|
||||||
|
* @returns {PageDefinition[]}
|
||||||
|
* An array of all PageDefinitions in the given map, sorted by
|
||||||
|
* weight.
|
||||||
|
*/
|
||||||
|
$scope.getPages = function getPages(level) {
|
||||||
|
|
||||||
|
var pages = [];
|
||||||
|
|
||||||
|
// Convert contents of level to a flat array of pages
|
||||||
|
angular.forEach(level, function addPageFromLevel(page) {
|
||||||
|
pages.push(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort page array by weight
|
||||||
|
pages.sort(function comparePages(a, b) {
|
||||||
|
return a.weight - b.weight;
|
||||||
|
});
|
||||||
|
|
||||||
|
return pages;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update page levels whenever pages changes
|
||||||
|
$scope.$watch('pages', function setPages(pages) {
|
||||||
|
|
||||||
|
// Determine current page name
|
||||||
|
currentPageName = [];
|
||||||
|
angular.forEach(pages, function findCurrentPageName(page) {
|
||||||
|
|
||||||
|
// If page is current page, store its names
|
||||||
|
if ($scope.isCurrentPage(page))
|
||||||
|
currentPageName = getPageNames(page);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset contents of levels
|
||||||
|
$scope.levels = [];
|
||||||
|
|
||||||
|
// Add all page definitions
|
||||||
|
angular.forEach(pages, addPage);
|
||||||
|
|
||||||
|
// Filter to only relevant levels
|
||||||
|
$scope.levels = $scope.levels.filter(function isRelevant(level) {
|
||||||
|
|
||||||
|
// Determine relevancy by counting the number of pages
|
||||||
|
var pageCount = 0;
|
||||||
|
for (var name in level) {
|
||||||
|
|
||||||
|
// Level is relevant if it has two or more pages
|
||||||
|
if (++pageCount === 2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the level is not relevant
|
||||||
|
return false;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
}] // end controller
|
}] // end controller
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -23,4 +23,8 @@
|
|||||||
/**
|
/**
|
||||||
* Module for generating and implementing user navigation options.
|
* Module for generating and implementing user navigation options.
|
||||||
*/
|
*/
|
||||||
angular.module('navigation', ['notification', 'rest']);
|
angular.module('navigation', [
|
||||||
|
'auth',
|
||||||
|
'notification',
|
||||||
|
'rest'
|
||||||
|
]);
|
||||||
|
@@ -27,91 +27,104 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
|||||||
function userPageService($injector) {
|
function userPageService($injector) {
|
||||||
|
|
||||||
// Get required types
|
// Get required types
|
||||||
var ConnectionGroup = $injector.get('ConnectionGroup');
|
var ClientIdentifier = $injector.get('ClientIdentifier');
|
||||||
var PermissionSet = $injector.get('PermissionSet');
|
var ConnectionGroup = $injector.get('ConnectionGroup');
|
||||||
|
var PageDefinition = $injector.get('PageDefinition');
|
||||||
|
var PermissionSet = $injector.get('PermissionSet');
|
||||||
|
|
||||||
// Get required services
|
// Get required services
|
||||||
var $q = $injector.get('$q');
|
var $q = $injector.get('$q');
|
||||||
var authenticationService = $injector.get('authenticationService');
|
var authenticationService = $injector.get('authenticationService');
|
||||||
var connectionGroupService = $injector.get("connectionGroupService");
|
var connectionGroupService = $injector.get('connectionGroupService');
|
||||||
var permissionService = $injector.get("permissionService");
|
var dataSourceService = $injector.get('dataSourceService');
|
||||||
|
var permissionService = $injector.get('permissionService');
|
||||||
|
var translationStringService = $injector.get('translationStringService');
|
||||||
|
|
||||||
var service = {};
|
var service = {};
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new Page object with the given name and url.
|
|
||||||
* @constructor
|
|
||||||
*
|
|
||||||
* @param {String} name
|
|
||||||
* The i18n key for the name of the page.
|
|
||||||
*
|
|
||||||
* @param {String} url
|
|
||||||
* The url to the page.
|
|
||||||
*
|
|
||||||
* @returns {PageDefinition}
|
|
||||||
* The newly created PageDefinition object.
|
|
||||||
*/
|
|
||||||
var Page = function Page(name, url) {
|
|
||||||
this.name = name;
|
|
||||||
this.url = url;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The home page to assign to a user if they can navigate to more than one
|
* The home page to assign to a user if they can navigate to more than one
|
||||||
* page.
|
* page.
|
||||||
*
|
*
|
||||||
* @type Page
|
* @type PageDefinition
|
||||||
*/
|
*/
|
||||||
var SYSTEM_HOME_PAGE = new Page(
|
var SYSTEM_HOME_PAGE = new PageDefinition({
|
||||||
'USER_MENU.ACTION_NAVIGATE_HOME',
|
name : 'USER_MENU.ACTION_NAVIGATE_HOME',
|
||||||
'/'
|
url : '/'
|
||||||
);
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an appropriate home page for the current user.
|
* Returns an appropriate home page for the current user.
|
||||||
*
|
*
|
||||||
* @param {ConnectionGroup} rootGroup
|
* @param {Object.<String, ConnectionGroup>} rootGroups
|
||||||
* The root of the connection group tree for the current user.
|
* A map of all root connection groups visible to the current user,
|
||||||
|
* where each key is the identifier of the corresponding data source.
|
||||||
*
|
*
|
||||||
* @returns {Page}
|
* @returns {PageDefinition}
|
||||||
* The user's home page.
|
* The user's home page.
|
||||||
*/
|
*/
|
||||||
var generateHomePage = function generateHomePage(rootGroup) {
|
var generateHomePage = function generateHomePage(rootGroups) {
|
||||||
|
|
||||||
// Get children
|
var homePage = null;
|
||||||
var connections = rootGroup.childConnections || [];
|
|
||||||
var connectionGroups = rootGroup.childConnectionGroups || [];
|
|
||||||
|
|
||||||
// Use main connection list screen as home if multiple connections
|
// Determine whether a connection or balancing group should serve as
|
||||||
// are available
|
// the home page
|
||||||
if (connections.length + connectionGroups.length === 1) {
|
for (var dataSource in rootGroups) {
|
||||||
|
|
||||||
var connection = connections[0];
|
// Get corresponding root group
|
||||||
var connectionGroup = connectionGroups[0];
|
var rootGroup = rootGroups[dataSource];
|
||||||
|
|
||||||
|
// Get children
|
||||||
|
var connections = rootGroup.childConnections || [];
|
||||||
|
var connectionGroups = rootGroup.childConnectionGroups || [];
|
||||||
|
|
||||||
|
// If exactly one connection or balancing group is available, use
|
||||||
|
// that as the home page
|
||||||
|
if (homePage === null && connections.length + connectionGroups.length === 1) {
|
||||||
|
|
||||||
|
var connection = connections[0];
|
||||||
|
var connectionGroup = connectionGroups[0];
|
||||||
|
|
||||||
|
// Only one connection present, use as home page
|
||||||
|
if (connection) {
|
||||||
|
homePage = new PageDefinition({
|
||||||
|
name : connection.name,
|
||||||
|
url : '/client/' + ClientIdentifier.toString({
|
||||||
|
dataSource : dataSource,
|
||||||
|
type : ClientIdentifier.Types.CONNECTION,
|
||||||
|
id : connection.identifier
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only one balancing group present, use as home page
|
||||||
|
if (connectionGroup
|
||||||
|
&& connectionGroup.type === ConnectionGroup.Type.BALANCING
|
||||||
|
&& _.isEmpty(connectionGroup.childConnections)
|
||||||
|
&& _.isEmpty(connectionGroup.childConnectionGroups)) {
|
||||||
|
homePage = new PageDefinition({
|
||||||
|
name : connectionGroup.name,
|
||||||
|
url : '/client/' + ClientIdentifier.toString({
|
||||||
|
dataSource : dataSource,
|
||||||
|
type : ClientIdentifier.Types.CONNECTION_GROUP,
|
||||||
|
id : connectionGroup.identifier
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Only one connection present, use as home page
|
|
||||||
if (connection) {
|
|
||||||
return new Page(
|
|
||||||
connection.name,
|
|
||||||
'/client/c/' + connection.identifier
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only one connection present, use as home page
|
// Otherwise, a connection or balancing group cannot serve as the
|
||||||
if (connectionGroup
|
// home page
|
||||||
&& connectionGroup.type === ConnectionGroup.Type.BALANCING
|
else {
|
||||||
&& _.isEmpty(connectionGroup.childConnections)
|
homePage = null;
|
||||||
&& _.isEmpty(connectionGroup.childConnectionGroups)) {
|
break;
|
||||||
return new Page(
|
|
||||||
connectionGroup.name,
|
|
||||||
'/client/g/' + connectionGroup.identifier
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // end for each data source
|
||||||
|
|
||||||
// Resolve promise with default home page
|
// Use default home page if no other is available
|
||||||
return SYSTEM_HOME_PAGE;
|
return homePage || SYSTEM_HOME_PAGE;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -126,10 +139,14 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
|||||||
|
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
|
||||||
// Resolve promise using home page derived from root connection group
|
// Resolve promise using home page derived from root connection groups
|
||||||
connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER)
|
dataSourceService.apply(
|
||||||
.success(function rootConnectionGroupRetrieved(rootGroup) {
|
connectionGroupService.getConnectionGroupTree,
|
||||||
deferred.resolve(generateHomePage(rootGroup));
|
authenticationService.getAvailableDataSources(),
|
||||||
|
ConnectionGroup.ROOT_IDENTIFIER
|
||||||
|
)
|
||||||
|
.then(function rootConnectionGroupsRetrieved(rootGroups) {
|
||||||
|
deferred.resolve(generateHomePage(rootGroups));
|
||||||
});
|
});
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
@@ -140,94 +157,115 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
|||||||
* Returns all settings pages that the current user can visit. This can
|
* Returns all settings pages that the current user can visit. This can
|
||||||
* include any of the various manage pages.
|
* include any of the various manage pages.
|
||||||
*
|
*
|
||||||
* @param {PermissionSet} permissions
|
* @param {Object.<String, PermissionSet>} permissionSets
|
||||||
* The permissions for the current user.
|
* A map of all permissions granted to the current user, where each
|
||||||
|
* key is the identifier of the corresponding data source.
|
||||||
*
|
*
|
||||||
* @returns {Page[]}
|
* @returns {Page[]}
|
||||||
* An array of all settings pages that the current user can visit.
|
* An array of all settings pages that the current user can visit.
|
||||||
*/
|
*/
|
||||||
var generateSettingsPages = function generateSettingsPages(permissions) {
|
var generateSettingsPages = function generateSettingsPages(permissionSets) {
|
||||||
|
|
||||||
var pages = [];
|
var pages = [];
|
||||||
|
|
||||||
permissions = angular.copy(permissions);
|
var canManageUsers = [];
|
||||||
|
var canManageConnections = [];
|
||||||
|
var canManageSessions = [];
|
||||||
|
|
||||||
// Ignore permission to update root group
|
// Inspect the contents of each provided permission set
|
||||||
PermissionSet.removeConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, ConnectionGroup.ROOT_IDENTIFIER);
|
angular.forEach(permissionSets, function inspectPermissions(permissions, dataSource) {
|
||||||
|
|
||||||
// Ignore permission to update self
|
permissions = angular.copy(permissions);
|
||||||
PermissionSet.removeUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, authenticationService.getCurrentUsername());
|
|
||||||
|
|
||||||
// Determine whether the current user needs access to the user management UI
|
// Ignore permission to update root group
|
||||||
var canManageUsers =
|
PermissionSet.removeConnectionGroupPermission(permissions,
|
||||||
|
PermissionSet.ObjectPermissionType.UPDATE,
|
||||||
|
ConnectionGroup.ROOT_IDENTIFIER);
|
||||||
|
|
||||||
// System permissions
|
// Ignore permission to update self
|
||||||
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
PermissionSet.removeUserPermission(permissions,
|
||||||
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_USER)
|
PermissionSet.ObjectPermissionType.UPDATE,
|
||||||
|
authenticationService.getCurrentUsername());
|
||||||
|
|
||||||
// Permission to update users
|
// Determine whether the current user needs access to the user management UI
|
||||||
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE)
|
if (
|
||||||
|
// System permissions
|
||||||
|
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
||||||
|
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_USER)
|
||||||
|
|
||||||
// Permission to delete users
|
// Permission to update users
|
||||||
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.DELETE)
|
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE)
|
||||||
|
|
||||||
// Permission to administer users
|
// Permission to delete users
|
||||||
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER);
|
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.DELETE)
|
||||||
|
|
||||||
// Determine whether the current user needs access to the connection management UI
|
// Permission to administer users
|
||||||
var canManageConnections =
|
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER)
|
||||||
|
)
|
||||||
|
canManageUsers.push(dataSource);
|
||||||
|
|
||||||
// System permissions
|
// Determine whether the current user needs access to the connection management UI
|
||||||
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
if (
|
||||||
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION)
|
// System permissions
|
||||||
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION_GROUP)
|
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
||||||
|
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION)
|
||||||
|
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION_GROUP)
|
||||||
|
|
||||||
// Permission to update connections or connection groups
|
// Permission to update connections or connection groups
|
||||||
|| PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE)
|
|| PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE)
|
||||||
|| PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE)
|
|| PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE)
|
||||||
|
|
||||||
// Permission to delete connections or connection groups
|
// Permission to delete connections or connection groups
|
||||||
|| PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.DELETE)
|
|| PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.DELETE)
|
||||||
|| PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.DELETE)
|
|| PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.DELETE)
|
||||||
|
|
||||||
// Permission to administer connections or connection groups
|
// Permission to administer connections or connection groups
|
||||||
|| PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER)
|
|| PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER)
|
||||||
|| PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER);
|
|| PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER)
|
||||||
|
)
|
||||||
|
canManageConnections.push(dataSource);
|
||||||
|
|
||||||
var canManageSessions =
|
// Determine whether the current user needs access to the session management UI
|
||||||
|
if (
|
||||||
|
// A user must be a system administrator to manage sessions
|
||||||
|
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
||||||
|
)
|
||||||
|
canManageSessions.push(dataSource);
|
||||||
|
|
||||||
// A user must be a system administrator to manage sessions
|
});
|
||||||
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER);
|
|
||||||
|
|
||||||
// If user can manage sessions, add link to sessions management page
|
// If user can manage sessions, add link to sessions management page
|
||||||
if (canManageSessions) {
|
if (canManageSessions.length) {
|
||||||
pages.push(new Page(
|
pages.push(new PageDefinition({
|
||||||
'USER_MENU.ACTION_MANAGE_SESSIONS',
|
name : 'USER_MENU.ACTION_MANAGE_SESSIONS',
|
||||||
'/settings/sessions'
|
url : '/settings/sessions'
|
||||||
));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If user can manage users, add link to user management page
|
// If user can manage users, add link to user management page
|
||||||
if (canManageUsers) {
|
if (canManageUsers.length) {
|
||||||
pages.push(new Page(
|
pages.push(new PageDefinition({
|
||||||
'USER_MENU.ACTION_MANAGE_USERS',
|
name : 'USER_MENU.ACTION_MANAGE_USERS',
|
||||||
'/settings/users'
|
url : '/settings/users'
|
||||||
));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If user can manage connections, add link to connections management page
|
// If user can manage connections, add links for connection management pages
|
||||||
if (canManageConnections) {
|
angular.forEach(canManageConnections, function addConnectionManagementLink(dataSource) {
|
||||||
pages.push(new Page(
|
pages.push(new PageDefinition({
|
||||||
'USER_MENU.ACTION_MANAGE_CONNECTIONS',
|
name : [
|
||||||
'/settings/connections'
|
'USER_MENU.ACTION_MANAGE_CONNECTIONS',
|
||||||
));
|
translationStringService.canonicalize('DATA_SOURCE_' + dataSource) + '.NAME'
|
||||||
}
|
],
|
||||||
|
url : '/settings/' + encodeURIComponent(dataSource) + '/connections'
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
// Add link to user preferences (always accessible)
|
// Add link to user preferences (always accessible)
|
||||||
pages.push(new Page(
|
pages.push(new PageDefinition({
|
||||||
'USER_MENU.ACTION_MANAGE_PREFERENCES',
|
name : 'USER_MENU.ACTION_MANAGE_PREFERENCES',
|
||||||
'/settings/preferences'
|
url : '/settings/preferences'
|
||||||
));
|
}));
|
||||||
|
|
||||||
return pages;
|
return pages;
|
||||||
};
|
};
|
||||||
@@ -245,10 +283,15 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
|||||||
|
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
|
||||||
// Retrieve current permissions, resolving main pages if possible
|
// Retrieve current permissions
|
||||||
|
dataSourceService.apply(
|
||||||
|
permissionService.getPermissions,
|
||||||
|
authenticationService.getAvailableDataSources(),
|
||||||
|
authenticationService.getCurrentUsername()
|
||||||
|
)
|
||||||
|
|
||||||
// Resolve promise using settings pages derived from permissions
|
// Resolve promise using settings pages derived from permissions
|
||||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
.then(function permissionsRetrieved(permissions) {
|
||||||
.success(function permissionsRetrieved(permissions) {
|
|
||||||
deferred.resolve(generateSettingsPages(permissions));
|
deferred.resolve(generateSettingsPages(permissions));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -261,21 +304,23 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
|||||||
* include the home page, manage pages, etc. In the case that there are no
|
* include the home page, manage pages, etc. In the case that there are no
|
||||||
* applicable pages of this sort, it may return a client page.
|
* applicable pages of this sort, it may return a client page.
|
||||||
*
|
*
|
||||||
* @param {ConnectionGroup} rootGroup
|
* @param {Object.<String, ConnectionGroup>} rootGroups
|
||||||
* The root of the connection group tree for the current user.
|
* A map of all root connection groups visible to the current user,
|
||||||
|
* where each key is the identifier of the corresponding data source.
|
||||||
*
|
*
|
||||||
* @param {PermissionSet} permissions
|
* @param {Object.<String, PermissionSet>} permissions
|
||||||
* The permissions for the current user.
|
* A map of all permissions granted to the current user, where each
|
||||||
|
* key is the identifier of the corresponding data source.
|
||||||
*
|
*
|
||||||
* @returns {Page[]}
|
* @returns {Page[]}
|
||||||
* An array of all main pages that the current user can visit.
|
* An array of all main pages that the current user can visit.
|
||||||
*/
|
*/
|
||||||
var generateMainPages = function generateMainPages(rootGroup, permissions) {
|
var generateMainPages = function generateMainPages(rootGroups, permissions) {
|
||||||
|
|
||||||
var pages = [];
|
var pages = [];
|
||||||
|
|
||||||
// Get home page and settings pages
|
// Get home page and settings pages
|
||||||
var homePage = generateHomePage(rootGroup);
|
var homePage = generateHomePage(rootGroups);
|
||||||
var settingsPages = generateSettingsPages(permissions);
|
var settingsPages = generateSettingsPages(permissions);
|
||||||
|
|
||||||
// Only include the home page in the list of main pages if the user
|
// Only include the home page in the list of main pages if the user
|
||||||
@@ -285,10 +330,10 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
|||||||
|
|
||||||
// Add generic link to the first-available settings page
|
// Add generic link to the first-available settings page
|
||||||
if (settingsPages.length) {
|
if (settingsPages.length) {
|
||||||
pages.push(new Page(
|
pages.push(new PageDefinition({
|
||||||
'USER_MENU.ACTION_MANAGE_SETTINGS',
|
name : 'USER_MENU.ACTION_MANAGE_SETTINGS',
|
||||||
settingsPages[0].url
|
url : settingsPages[0].url
|
||||||
));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return pages;
|
return pages;
|
||||||
@@ -308,7 +353,7 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
|||||||
|
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
|
||||||
var rootGroup = null;
|
var rootGroups = null;
|
||||||
var permissions = null;
|
var permissions = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -316,20 +361,30 @@ angular.module('navigation').factory('userPageService', ['$injector',
|
|||||||
* insufficient data is available, this function does nothing.
|
* insufficient data is available, this function does nothing.
|
||||||
*/
|
*/
|
||||||
var resolveMainPages = function resolveMainPages() {
|
var resolveMainPages = function resolveMainPages() {
|
||||||
if (rootGroup && permissions)
|
if (rootGroups && permissions)
|
||||||
deferred.resolve(generateMainPages(rootGroup, permissions));
|
deferred.resolve(generateMainPages(rootGroups, permissions));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Retrieve root group, resolving main pages if possible
|
// Retrieve root group, resolving main pages if possible
|
||||||
connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER)
|
dataSourceService.apply(
|
||||||
.success(function rootConnectionGroupRetrieved(retrievedRootGroup) {
|
connectionGroupService.getConnectionGroupTree,
|
||||||
rootGroup = retrievedRootGroup;
|
authenticationService.getAvailableDataSources(),
|
||||||
|
ConnectionGroup.ROOT_IDENTIFIER
|
||||||
|
)
|
||||||
|
.then(function rootConnectionGroupsRetrieved(retrievedRootGroups) {
|
||||||
|
rootGroups = retrievedRootGroups;
|
||||||
resolveMainPages();
|
resolveMainPages();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Retrieve current permissions, resolving main pages if possible
|
// Retrieve current permissions
|
||||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
dataSourceService.apply(
|
||||||
.success(function permissionsRetrieved(retrievedPermissions) {
|
permissionService.getPermissions,
|
||||||
|
authenticationService.getAvailableDataSources(),
|
||||||
|
authenticationService.getCurrentUsername()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resolving main pages if possible
|
||||||
|
.then(function permissionsRetrieved(retrievedPermissions) {
|
||||||
permissions = retrievedPermissions;
|
permissions = retrievedPermissions;
|
||||||
resolveMainPages();
|
resolveMainPages();
|
||||||
});
|
});
|
||||||
|
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.page-tabs .page-list ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.0125);
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-tabs .page-list ul + ul {
|
||||||
|
font-size: 0.75em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-tabs .page-list li {
|
||||||
|
display: inline-block;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-tabs .page-list li a[href] {
|
||||||
|
display: block;
|
||||||
|
color: black;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0.75em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-tabs .page-list li a[href]:visited {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-tabs .page-list li a[href]:hover {
|
||||||
|
background-color: #CDA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-tabs .page-list li a[href].current,
|
||||||
|
.page-tabs .page-list li a[href].current:hover {
|
||||||
|
background: rgba(0,0,0,0.3);
|
||||||
|
cursor: default;
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
<ul class="page-list">
|
<div class="page-list" ng-show="levels.length">
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2015 Glyptodon LLC
|
Copyright (C) 2015 Glyptodon LLC
|
||||||
|
|
||||||
@@ -22,11 +22,13 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- Navigation links -->
|
<!-- Navigation links -->
|
||||||
<li ng-repeat="page in pages">
|
<ul class="page-list-level" ng-repeat="level in levels track by $index">
|
||||||
<a class="home" ng-click="navigateToPage(page)"
|
<li ng-repeat="page in getPages(level)" class="{{page.className}}">
|
||||||
ng-class="{current: isCurrentPage(page)}" href="#{{page.url}}">
|
<a class="home" ng-click="navigateToPage(page)"
|
||||||
{{page.name | translate}}
|
ng-class="{current: isCurrentPage(page)}" href="#{{page.url}}">
|
||||||
</a>
|
{{page.name | translate}}
|
||||||
</li>
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
</ul>
|
</div>
|
||||||
|
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the ClientIdentifier class definition.
|
||||||
|
*/
|
||||||
|
angular.module('client').factory('ClientIdentifier', ['$injector',
|
||||||
|
function defineClientIdentifier($injector) {
|
||||||
|
|
||||||
|
// Required services
|
||||||
|
var authenticationService = $injector.get('authenticationService');
|
||||||
|
var $window = $injector.get('$window');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object which uniquely identifies a particular connection or connection
|
||||||
|
* group within Guacamole. This object can be converted to/from a string to
|
||||||
|
* generate a guaranteed-unique, deterministic identifier for client URLs.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {ClientIdentifier|Object} [template={}]
|
||||||
|
* The object whose properties should be copied within the new
|
||||||
|
* ClientIdentifier.
|
||||||
|
*/
|
||||||
|
var ClientIdentifier = function ClientIdentifier(template) {
|
||||||
|
|
||||||
|
// Use empty object by default
|
||||||
|
template = template || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier of the data source associated with the object to
|
||||||
|
* which the client will connect. This identifier will be the
|
||||||
|
* identifier of an AuthenticationProvider within the Guacamole web
|
||||||
|
* application.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.dataSource = template.dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of object to which the client will connect. Possible values
|
||||||
|
* are defined within ClientIdentifier.Types.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.type = template.type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of the object to which the client will
|
||||||
|
* connect.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.id = template.id;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All possible ClientIdentifier types.
|
||||||
|
*
|
||||||
|
* @type Object.<String, String>
|
||||||
|
*/
|
||||||
|
ClientIdentifier.Types = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type string for a Guacamole connection.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
CONNECTION : 'c',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type string for a Guacamole connection group.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
CONNECTION_GROUP : 'g'
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given ClientIdentifier or ClientIdentifier-like object to
|
||||||
|
* a String representation. Any object having the same properties as
|
||||||
|
* ClientIdentifier may be used, but only those properties will be taken
|
||||||
|
* into account when producing the resulting String.
|
||||||
|
*
|
||||||
|
* @param {ClientIdentifier|Object} id
|
||||||
|
* The ClientIdentifier or ClientIdentifier-like object to convert to
|
||||||
|
* a String representation.
|
||||||
|
*
|
||||||
|
* @returns {String}
|
||||||
|
* A deterministic String representation of the given ClientIdentifier
|
||||||
|
* or ClientIdentifier-like object.
|
||||||
|
*/
|
||||||
|
ClientIdentifier.toString = function toString(id) {
|
||||||
|
return $window.btoa([
|
||||||
|
id.id,
|
||||||
|
id.type,
|
||||||
|
id.dataSource
|
||||||
|
].join('\0'));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the given String into the corresponding ClientIdentifier. If
|
||||||
|
* the provided String is not a valid identifier, it will be interpreted
|
||||||
|
* as the identifier of a connection within the data source that
|
||||||
|
* authenticated the current user.
|
||||||
|
*
|
||||||
|
* @param {String} str
|
||||||
|
* The String to convert to a ClientIdentifier.
|
||||||
|
*
|
||||||
|
* @returns {ClientIdentifier}
|
||||||
|
* The ClientIdentifier represented by the given String.
|
||||||
|
*/
|
||||||
|
ClientIdentifier.fromString = function fromString(str) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
var values = $window.atob(str).split('\0');
|
||||||
|
return new ClientIdentifier({
|
||||||
|
id : values[0],
|
||||||
|
type : values[1],
|
||||||
|
dataSource : values[2]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the provided string is invalid, transform into a reasonable guess
|
||||||
|
catch (e) {
|
||||||
|
return new ClientIdentifier({
|
||||||
|
id : str,
|
||||||
|
type : ClientIdentifier.Types.CONNECTION,
|
||||||
|
dataSource : authenticationService.getDataSource() || 'default'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return ClientIdentifier;
|
||||||
|
|
||||||
|
}]);
|
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the PageDefinition class definition.
|
||||||
|
*/
|
||||||
|
angular.module('navigation').factory('PageDefinition', [function definePageDefinition() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new PageDefinition object which pairs the URL of a page with
|
||||||
|
* an arbitrary, human-readable name.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {PageDefinition|Object} template
|
||||||
|
* The object whose properties should be copied within the new
|
||||||
|
* PageDefinition.
|
||||||
|
*/
|
||||||
|
var PageDefinition = function PageDefinition(template) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The the name of the page, which should be a translation table key.
|
||||||
|
* Alternatively, this may also be a list of names, where the final
|
||||||
|
* name represents the page and earlier names represent categorization.
|
||||||
|
* Those categorical names may be rendered hierarchically as a system
|
||||||
|
* of menus, tabs, etc.
|
||||||
|
*
|
||||||
|
* @type String|String[]
|
||||||
|
*/
|
||||||
|
this.name = template.name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the page.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.url = template.url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CSS class name to associate with this page, if any. This will be
|
||||||
|
* an empty string by default.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.className = template.className || '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A numeric value denoting the relative sort order when compared to
|
||||||
|
* other sibling PageDefinitions. If unspecified, sort order is
|
||||||
|
* determined by the system using the PageDefinition.
|
||||||
|
*
|
||||||
|
* @type Number
|
||||||
|
*/
|
||||||
|
this.weight = template.weight;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return PageDefinition;
|
||||||
|
|
||||||
|
}]);
|
@@ -23,8 +23,13 @@
|
|||||||
/**
|
/**
|
||||||
* Service for operating on active connections via the REST API.
|
* Service for operating on active connections via the REST API.
|
||||||
*/
|
*/
|
||||||
angular.module('rest').factory('activeConnectionService', ['$http', 'authenticationService',
|
angular.module('rest').factory('activeConnectionService', ['$injector',
|
||||||
function activeConnectionService($http, authenticationService) {
|
function activeConnectionService($injector) {
|
||||||
|
|
||||||
|
// Required services
|
||||||
|
var $http = $injector.get('$http');
|
||||||
|
var $q = $injector.get('$q');
|
||||||
|
var authenticationService = $injector.get('authenticationService');
|
||||||
|
|
||||||
var service = {};
|
var service = {};
|
||||||
|
|
||||||
@@ -39,13 +44,12 @@ angular.module('rest').factory('activeConnectionService', ['$http', 'authenticat
|
|||||||
* result. If null, no filtering will be performed. Valid values are
|
* result. If null, no filtering will be performed. Valid values are
|
||||||
* listed within PermissionSet.ObjectType.
|
* listed within PermissionSet.ObjectType.
|
||||||
*
|
*
|
||||||
|
|
||||||
* @returns {Promise.<Object.<String, ActiveConnection>>}
|
* @returns {Promise.<Object.<String, ActiveConnection>>}
|
||||||
* A promise which will resolve with a map of @link{ActiveConnection}
|
* A promise which will resolve with a map of @link{ActiveConnection}
|
||||||
* objects, where each key is the identifier of the corresponding
|
* objects, where each key is the identifier of the corresponding
|
||||||
* active connection.
|
* active connection.
|
||||||
*/
|
*/
|
||||||
service.getActiveConnections = function getActiveConnections(permissionTypes) {
|
service.getActiveConnections = function getActiveConnections(dataSource, permissionTypes) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -59,12 +63,74 @@ angular.module('rest').factory('activeConnectionService', ['$http', 'authenticat
|
|||||||
// Retrieve tunnels
|
// Retrieve tunnels
|
||||||
return $http({
|
return $http({
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/activeConnections',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/activeConnections',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise which resolves with all active connections accessible
|
||||||
|
* by the current user, as a map of @link{ActiveConnection} maps, as would
|
||||||
|
* be returned by getActiveConnections(), grouped by the identifier of
|
||||||
|
* their corresponding data source. All given data sources are queried. If
|
||||||
|
* an error occurs while retrieving any ActiveConnection map, the promise
|
||||||
|
* will be rejected.
|
||||||
|
*
|
||||||
|
* @param {String[]} dataSources
|
||||||
|
* The unique identifier of the data sources containing the active
|
||||||
|
* connections to be retrieved. These identifiers correspond to
|
||||||
|
* AuthenticationProviders within the Guacamole web application.
|
||||||
|
*
|
||||||
|
* @param {String[]} [permissionTypes]
|
||||||
|
* The set of permissions to filter with. A user must have one or more
|
||||||
|
* of these permissions for an active connection to appear in the
|
||||||
|
* result. If null, no filtering will be performed. Valid values are
|
||||||
|
* listed within PermissionSet.ObjectType.
|
||||||
|
*
|
||||||
|
* @returns {Promise.<Object.<String, Object.<String, ActiveConnection>>>}
|
||||||
|
* A promise which resolves with all active connections available to
|
||||||
|
* the current user, as a map of ActiveConnection maps, as would be
|
||||||
|
* returned by getActiveConnections(), grouped by the identifier of
|
||||||
|
* their corresponding data source.
|
||||||
|
*/
|
||||||
|
service.getAllActiveConnections = function getAllActiveConnections(dataSources, permissionTypes) {
|
||||||
|
|
||||||
|
var deferred = $q.defer();
|
||||||
|
|
||||||
|
var activeConnectionRequests = [];
|
||||||
|
var activeConnectionMaps = {};
|
||||||
|
|
||||||
|
// Retrieve all active connections from all data sources
|
||||||
|
angular.forEach(dataSources, function retrieveActiveConnections(dataSource) {
|
||||||
|
activeConnectionRequests.push(
|
||||||
|
service.getActiveConnections(dataSource, permissionTypes)
|
||||||
|
.success(function activeConnectionsRetrieved(activeConnections) {
|
||||||
|
activeConnectionMaps[dataSource] = activeConnections;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Resolve when all requests are completed
|
||||||
|
$q.all(activeConnectionRequests)
|
||||||
|
.then(
|
||||||
|
|
||||||
|
// All requests completed successfully
|
||||||
|
function allActiveConnectionsRetrieved() {
|
||||||
|
deferred.resolve(userArrays);
|
||||||
|
},
|
||||||
|
|
||||||
|
// At least one request failed
|
||||||
|
function activeConnectionRetrievalFailed(e) {
|
||||||
|
deferred.reject(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a request to the REST API to delete the active connections having
|
* Makes a request to the REST API to delete the active connections having
|
||||||
* the given identifiers, effectively disconnecting them, returning a
|
* the given identifiers, effectively disconnecting them, returning a
|
||||||
@@ -77,7 +143,7 @@ angular.module('rest').factory('activeConnectionService', ['$http', 'authenticat
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* delete operation is successful.
|
* delete operation is successful.
|
||||||
*/
|
*/
|
||||||
service.deleteActiveConnections = function deleteActiveConnections(identifiers) {
|
service.deleteActiveConnections = function deleteActiveConnections(dataSource, identifiers) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -96,7 +162,7 @@ angular.module('rest').factory('activeConnectionService', ['$http', 'authenticat
|
|||||||
// Perform active connection deletion via PATCH
|
// Perform active connection deletion via PATCH
|
||||||
return $http({
|
return $http({
|
||||||
method : 'PATCH',
|
method : 'PATCH',
|
||||||
url : 'api/activeConnections',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/activeConnections',
|
||||||
params : httpParameters,
|
params : httpParameters,
|
||||||
data : activeConnectionPatch
|
data : activeConnectionPatch
|
||||||
});
|
});
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -28,6 +28,7 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $http = $injector.get('$http');
|
var $http = $injector.get('$http');
|
||||||
|
var $q = $injector.get('$q');
|
||||||
var authenticationService = $injector.get('authenticationService');
|
var authenticationService = $injector.get('authenticationService');
|
||||||
var cacheService = $injector.get('cacheService');
|
var cacheService = $injector.get('cacheService');
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
* A promise which will resolve with a @link{ConnectionGroup} upon
|
* A promise which will resolve with a @link{ConnectionGroup} upon
|
||||||
* success.
|
* success.
|
||||||
*/
|
*/
|
||||||
service.getConnectionGroupTree = function getConnectionGroupTree(connectionGroupID, permissionTypes) {
|
service.getConnectionGroupTree = function getConnectionGroupTree(dataSource, connectionGroupID, permissionTypes) {
|
||||||
|
|
||||||
// Use the root connection group ID if no ID is passed in
|
// Use the root connection group ID if no ID is passed in
|
||||||
connectionGroupID = connectionGroupID || ConnectionGroup.ROOT_IDENTIFIER;
|
connectionGroupID = connectionGroupID || ConnectionGroup.ROOT_IDENTIFIER;
|
||||||
@@ -75,12 +76,12 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.connections,
|
cache : cacheService.connections,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/connectionGroups/' + encodeURIComponent(connectionGroupID) + '/tree',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connectionGroups/' + encodeURIComponent(connectionGroupID) + '/tree',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a request to the REST API to get an individual connection group,
|
* Makes a request to the REST API to get an individual connection group,
|
||||||
* returning a promise that provides the corresponding
|
* returning a promise that provides the corresponding
|
||||||
@@ -94,7 +95,7 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
* A promise which will resolve with a @link{ConnectionGroup} upon
|
* A promise which will resolve with a @link{ConnectionGroup} upon
|
||||||
* success.
|
* success.
|
||||||
*/
|
*/
|
||||||
service.getConnectionGroup = function getConnectionGroup(connectionGroupID) {
|
service.getConnectionGroup = function getConnectionGroup(dataSource, connectionGroupID) {
|
||||||
|
|
||||||
// Use the root connection group ID if no ID is passed in
|
// Use the root connection group ID if no ID is passed in
|
||||||
connectionGroupID = connectionGroupID || ConnectionGroup.ROOT_IDENTIFIER;
|
connectionGroupID = connectionGroupID || ConnectionGroup.ROOT_IDENTIFIER;
|
||||||
@@ -108,7 +109,7 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.connections,
|
cache : cacheService.connections,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/connectionGroups/' + encodeURIComponent(connectionGroupID),
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connectionGroups/' + encodeURIComponent(connectionGroupID),
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -127,7 +128,7 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* save operation is successful.
|
* save operation is successful.
|
||||||
*/
|
*/
|
||||||
service.saveConnectionGroup = function saveConnectionGroup(connectionGroup) {
|
service.saveConnectionGroup = function saveConnectionGroup(dataSource, connectionGroup) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -138,7 +139,7 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
if (!connectionGroup.identifier) {
|
if (!connectionGroup.identifier) {
|
||||||
return $http({
|
return $http({
|
||||||
method : 'POST',
|
method : 'POST',
|
||||||
url : 'api/connectionGroups',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connectionGroups',
|
||||||
params : httpParameters,
|
params : httpParameters,
|
||||||
data : connectionGroup
|
data : connectionGroup
|
||||||
})
|
})
|
||||||
@@ -154,7 +155,7 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
else {
|
else {
|
||||||
return $http({
|
return $http({
|
||||||
method : 'PUT',
|
method : 'PUT',
|
||||||
url : 'api/connectionGroups/' + encodeURIComponent(connectionGroup.identifier),
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connectionGroups/' + encodeURIComponent(connectionGroup.identifier),
|
||||||
params : httpParameters,
|
params : httpParameters,
|
||||||
data : connectionGroup
|
data : connectionGroup
|
||||||
})
|
})
|
||||||
@@ -177,7 +178,7 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* delete operation is successful.
|
* delete operation is successful.
|
||||||
*/
|
*/
|
||||||
service.deleteConnectionGroup = function deleteConnectionGroup(connectionGroup) {
|
service.deleteConnectionGroup = function deleteConnectionGroup(dataSource, connectionGroup) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -187,7 +188,7 @@ angular.module('rest').factory('connectionGroupService', ['$injector',
|
|||||||
// Delete connection group
|
// Delete connection group
|
||||||
return $http({
|
return $http({
|
||||||
method : 'DELETE',
|
method : 'DELETE',
|
||||||
url : 'api/connectionGroups/' + encodeURIComponent(connectionGroup.identifier),
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connectionGroups/' + encodeURIComponent(connectionGroup.identifier),
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -48,7 +48,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
* // Do something with the connection
|
* // Do something with the connection
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
service.getConnection = function getConnection(id) {
|
service.getConnection = function getConnection(dataSource, id) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -59,7 +59,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.connections,
|
cache : cacheService.connections,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/connections/' + encodeURIComponent(id),
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connections/' + encodeURIComponent(id),
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
* A promise which will resolve with an array of
|
* A promise which will resolve with an array of
|
||||||
* @link{ConnectionHistoryEntry} objects upon success.
|
* @link{ConnectionHistoryEntry} objects upon success.
|
||||||
*/
|
*/
|
||||||
service.getConnectionHistory = function getConnectionHistory(id) {
|
service.getConnectionHistory = function getConnectionHistory(dataSource, id) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -87,7 +87,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
// Retrieve connection history
|
// Retrieve connection history
|
||||||
return $http({
|
return $http({
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/connections/' + encodeURIComponent(id) + '/history',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connections/' + encodeURIComponent(id) + '/history',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
* A promise which will resolve with an map of parameter name/value
|
* A promise which will resolve with an map of parameter name/value
|
||||||
* pairs upon success.
|
* pairs upon success.
|
||||||
*/
|
*/
|
||||||
service.getConnectionParameters = function getConnectionParameters(id) {
|
service.getConnectionParameters = function getConnectionParameters(dataSource, id) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -116,7 +116,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.connections,
|
cache : cacheService.connections,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/connections/' + encodeURIComponent(id) + '/parameters',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connections/' + encodeURIComponent(id) + '/parameters',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* save operation is successful.
|
* save operation is successful.
|
||||||
*/
|
*/
|
||||||
service.saveConnection = function saveConnection(connection) {
|
service.saveConnection = function saveConnection(dataSource, connection) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -146,7 +146,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
if (!connection.identifier) {
|
if (!connection.identifier) {
|
||||||
return $http({
|
return $http({
|
||||||
method : 'POST',
|
method : 'POST',
|
||||||
url : 'api/connections',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connections',
|
||||||
params : httpParameters,
|
params : httpParameters,
|
||||||
data : connection
|
data : connection
|
||||||
})
|
})
|
||||||
@@ -162,7 +162,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
else {
|
else {
|
||||||
return $http({
|
return $http({
|
||||||
method : 'PUT',
|
method : 'PUT',
|
||||||
url : 'api/connections/' + encodeURIComponent(connection.identifier),
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connections/' + encodeURIComponent(connection.identifier),
|
||||||
params : httpParameters,
|
params : httpParameters,
|
||||||
data : connection
|
data : connection
|
||||||
})
|
})
|
||||||
@@ -185,7 +185,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* delete operation is successful.
|
* delete operation is successful.
|
||||||
*/
|
*/
|
||||||
service.deleteConnection = function deleteConnection(connection) {
|
service.deleteConnection = function deleteConnection(dataSource, connection) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -195,7 +195,7 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
// Delete connection
|
// Delete connection
|
||||||
return $http({
|
return $http({
|
||||||
method : 'DELETE',
|
method : 'DELETE',
|
||||||
url : 'api/connections/' + encodeURIComponent(connection.identifier),
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/connections/' + encodeURIComponent(connection.identifier),
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
})
|
})
|
||||||
|
|
||||||
|
125
guacamole/src/main/webapp/app/rest/services/dataSourceService.js
Normal file
125
guacamole/src/main/webapp/app/rest/services/dataSourceService.js
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service which contains all REST API response caches.
|
||||||
|
*/
|
||||||
|
angular.module('rest').factory('dataSourceService', ['$injector',
|
||||||
|
function dataSourceService($injector) {
|
||||||
|
|
||||||
|
// Required services
|
||||||
|
var $q = $injector.get('$q');
|
||||||
|
|
||||||
|
// Service containing all caches
|
||||||
|
var service = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the given function once for each of the given data sources,
|
||||||
|
* passing that data source as the first argument to each invocation,
|
||||||
|
* followed by any additional arguments passed to apply(). The results of
|
||||||
|
* each invocation are aggregated into a map by data source identifier,
|
||||||
|
* and handled through a single promise which is resolved or rejected
|
||||||
|
* depending on the success/failure of each resulting REST call. Any error
|
||||||
|
* results in rejection of the entire apply() operation, except 404 ("NOT
|
||||||
|
* FOUND") errors, which are ignored.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* The function to call for each of the given data sources. The data
|
||||||
|
* source identifier will be given as the first argument, followed by
|
||||||
|
* the rest of the arguments given to apply(), in order. The function
|
||||||
|
* must return a Promise which is resolved or rejected depending on the
|
||||||
|
* result of the REST call.
|
||||||
|
*
|
||||||
|
* @param {String[]} dataSources
|
||||||
|
* The array or data source identifiers against which the given
|
||||||
|
* function should be called.
|
||||||
|
*
|
||||||
|
* @param {...*} args
|
||||||
|
* Any additional arguments to pass to the given function each time it
|
||||||
|
* is called.
|
||||||
|
*
|
||||||
|
* @returns {Promise.<Object.<String, *>>}
|
||||||
|
* A Promise which resolves with a map of data source identifier to
|
||||||
|
* corresponding result. The result will be the exact object or value
|
||||||
|
* provided as the resolution to the Promise returned by calls to the
|
||||||
|
* given function.
|
||||||
|
*/
|
||||||
|
service.apply = function apply(fn, dataSources) {
|
||||||
|
|
||||||
|
var deferred = $q.defer();
|
||||||
|
|
||||||
|
var requests = [];
|
||||||
|
var results = {};
|
||||||
|
|
||||||
|
// Build array of arguments to pass to the given function
|
||||||
|
var args = [];
|
||||||
|
for (var i = 2; i < arguments.length; i++)
|
||||||
|
args.push(arguments[i]);
|
||||||
|
|
||||||
|
// Retrieve the root group from all data sources
|
||||||
|
angular.forEach(dataSources, function invokeAgainstDataSource(dataSource) {
|
||||||
|
|
||||||
|
// Add promise to list of pending requests
|
||||||
|
var deferredRequest = $q.defer();
|
||||||
|
requests.push(deferredRequest.promise);
|
||||||
|
|
||||||
|
// Retrieve root group from data source
|
||||||
|
fn.apply(this, [dataSource].concat(args))
|
||||||
|
|
||||||
|
// Store result on success
|
||||||
|
.then(function immediateRequestSucceeded(response) {
|
||||||
|
results[dataSource] = response.data;
|
||||||
|
deferredRequest.resolve();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Fail on any errors (except "NOT FOUND")
|
||||||
|
function immediateRequestFailed(response) {
|
||||||
|
|
||||||
|
// Ignore "NOT FOUND" errors
|
||||||
|
if (response.status === 404)
|
||||||
|
deferredRequest.resolve();
|
||||||
|
|
||||||
|
// Explicitly abort for all other errors
|
||||||
|
else
|
||||||
|
deferredRequest.reject(response);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Resolve if all requests succeed
|
||||||
|
$q.all(requests).then(function requestsSucceeded() {
|
||||||
|
deferred.resolve(results);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Reject if at least one request fails
|
||||||
|
function requestFailed(response) {
|
||||||
|
deferred.reject(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
return deferred.promise;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return service;
|
||||||
|
|
||||||
|
}]);
|
@@ -28,6 +28,7 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $http = $injector.get('$http');
|
var $http = $injector.get('$http');
|
||||||
|
var $q = $injector.get('$q');
|
||||||
var authenticationService = $injector.get('authenticationService');
|
var authenticationService = $injector.get('authenticationService');
|
||||||
var cacheService = $injector.get('cacheService');
|
var cacheService = $injector.get('cacheService');
|
||||||
|
|
||||||
@@ -41,6 +42,11 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
* given user, returning a promise that provides an array of
|
* given user, returning a promise that provides an array of
|
||||||
* @link{Permission} objects if successful.
|
* @link{Permission} objects if successful.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the user whose
|
||||||
|
* permissions should be retrieved. This identifier corresponds to an
|
||||||
|
* AuthenticationProvider within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {String} userID
|
* @param {String} userID
|
||||||
* The ID of the user to retrieve the permissions for.
|
* The ID of the user to retrieve the permissions for.
|
||||||
*
|
*
|
||||||
@@ -48,7 +54,7 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
* A promise which will resolve with a @link{PermissionSet} upon
|
* A promise which will resolve with a @link{PermissionSet} upon
|
||||||
* success.
|
* success.
|
||||||
*/
|
*/
|
||||||
service.getPermissions = function getPermissions(userID) {
|
service.getPermissions = function getPermissions(dataSource, userID) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -59,17 +65,22 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.users,
|
cache : cacheService.users,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/users/' + encodeURIComponent(userID) + '/permissions',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/users/' + encodeURIComponent(userID) + '/permissions',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a request to the REST API to add permissions for a given user,
|
* Makes a request to the REST API to add permissions for a given user,
|
||||||
* returning a promise that can be used for processing the results of the
|
* returning a promise that can be used for processing the results of the
|
||||||
* call.
|
* call.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the user whose
|
||||||
|
* permissions should be modified. This identifier corresponds to an
|
||||||
|
* AuthenticationProvider within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {String} userID
|
* @param {String} userID
|
||||||
* The ID of the user to modify the permissions of.
|
* The ID of the user to modify the permissions of.
|
||||||
*
|
*
|
||||||
@@ -80,8 +91,8 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* add operation is successful.
|
* add operation is successful.
|
||||||
*/
|
*/
|
||||||
service.addPermissions = function addPermissions(userID, permissions) {
|
service.addPermissions = function addPermissions(dataSource, userID, permissions) {
|
||||||
return service.patchPermissions(userID, permissions, null);
|
return service.patchPermissions(dataSource, userID, permissions, null);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,6 +100,11 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
* returning a promise that can be used for processing the results of the
|
* returning a promise that can be used for processing the results of the
|
||||||
* call.
|
* call.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the user whose
|
||||||
|
* permissions should be modified. This identifier corresponds to an
|
||||||
|
* AuthenticationProvider within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {String} userID
|
* @param {String} userID
|
||||||
* The ID of the user to modify the permissions of.
|
* The ID of the user to modify the permissions of.
|
||||||
*
|
*
|
||||||
@@ -99,8 +115,8 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* remove operation is successful.
|
* remove operation is successful.
|
||||||
*/
|
*/
|
||||||
service.removePermissions = function removePermissions(userID, permissions) {
|
service.removePermissions = function removePermissions(dataSource, userID, permissions) {
|
||||||
return service.patchPermissions(userID, null, permissions);
|
return service.patchPermissions(dataSource, userID, null, permissions);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,6 +202,11 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
* user, returning a promise that can be used for processing the results of
|
* user, returning a promise that can be used for processing the results of
|
||||||
* the call.
|
* the call.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the user whose
|
||||||
|
* permissions should be modified. This identifier corresponds to an
|
||||||
|
* AuthenticationProvider within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {String} userID
|
* @param {String} userID
|
||||||
* The ID of the user to modify the permissions of.
|
* The ID of the user to modify the permissions of.
|
||||||
*
|
*
|
||||||
@@ -199,7 +220,7 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* patch operation is successful.
|
* patch operation is successful.
|
||||||
*/
|
*/
|
||||||
service.patchPermissions = function patchPermissions(userID, permissionsToAdd, permissionsToRemove) {
|
service.patchPermissions = function patchPermissions(dataSource, userID, permissionsToAdd, permissionsToRemove) {
|
||||||
|
|
||||||
var permissionPatch = [];
|
var permissionPatch = [];
|
||||||
|
|
||||||
@@ -217,7 +238,7 @@ angular.module('rest').factory('permissionService', ['$injector',
|
|||||||
// Patch user permissions
|
// Patch user permissions
|
||||||
return $http({
|
return $http({
|
||||||
method : 'PATCH',
|
method : 'PATCH',
|
||||||
url : 'api/users/' + encodeURIComponent(userID) + '/permissions',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/users/' + encodeURIComponent(userID) + '/permissions',
|
||||||
params : httpParameters,
|
params : httpParameters,
|
||||||
data : permissionPatch
|
data : permissionPatch
|
||||||
})
|
})
|
||||||
|
@@ -39,12 +39,18 @@ angular.module('rest').factory('schemaService', ['$injector',
|
|||||||
* @link{Form} objects if successful. Each element of the array describes
|
* @link{Form} objects if successful. Each element of the array describes
|
||||||
* a logical grouping of possible attributes.
|
* a logical grouping of possible attributes.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the users whose
|
||||||
|
* available attributes are to be retrieved. This identifier
|
||||||
|
* corresponds to an AuthenticationProvider within the Guacamole web
|
||||||
|
* application.
|
||||||
|
*
|
||||||
* @returns {Promise.<Form[]>}
|
* @returns {Promise.<Form[]>}
|
||||||
* A promise which will resolve with an array of @link{Form}
|
* A promise which will resolve with an array of @link{Form}
|
||||||
* objects, where each @link{Form} describes a logical grouping of
|
* objects, where each @link{Form} describes a logical grouping of
|
||||||
* possible attributes.
|
* possible attributes.
|
||||||
*/
|
*/
|
||||||
service.getUserAttributes = function getUserAttributes() {
|
service.getUserAttributes = function getUserAttributes(dataSource) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -55,7 +61,7 @@ angular.module('rest').factory('schemaService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.schema,
|
cache : cacheService.schema,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/schema/users/attributes',
|
url : 'api/schema/' + encodeURIComponent(dataSource) + '/users/attributes',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -67,12 +73,18 @@ angular.module('rest').factory('schemaService', ['$injector',
|
|||||||
* @link{Form} objects if successful. Each element of the array describes
|
* @link{Form} objects if successful. Each element of the array describes
|
||||||
* a logical grouping of possible attributes.
|
* a logical grouping of possible attributes.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the connections
|
||||||
|
* whose available attributes are to be retrieved. This identifier
|
||||||
|
* corresponds to an AuthenticationProvider within the Guacamole web
|
||||||
|
* application.
|
||||||
|
*
|
||||||
* @returns {Promise.<Form[]>}
|
* @returns {Promise.<Form[]>}
|
||||||
* A promise which will resolve with an array of @link{Form}
|
* A promise which will resolve with an array of @link{Form}
|
||||||
* objects, where each @link{Form} describes a logical grouping of
|
* objects, where each @link{Form} describes a logical grouping of
|
||||||
* possible attributes.
|
* possible attributes.
|
||||||
*/
|
*/
|
||||||
service.getConnectionAttributes = function getConnectionAttributes() {
|
service.getConnectionAttributes = function getConnectionAttributes(dataSource) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -83,7 +95,7 @@ angular.module('rest').factory('schemaService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.schema,
|
cache : cacheService.schema,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/schema/connections/attributes',
|
url : 'api/schema/' + encodeURIComponent(dataSource) + '/connections/attributes',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -95,12 +107,18 @@ angular.module('rest').factory('schemaService', ['$injector',
|
|||||||
* of @link{Form} objects if successful. Each element of the array
|
* of @link{Form} objects if successful. Each element of the array
|
||||||
* a logical grouping of possible attributes.
|
* a logical grouping of possible attributes.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the connection
|
||||||
|
* groups whose available attributes are to be retrieved. This
|
||||||
|
* identifier corresponds to an AuthenticationProvider within the
|
||||||
|
* Guacamole web application.
|
||||||
|
*
|
||||||
* @returns {Promise.<Form[]>}
|
* @returns {Promise.<Form[]>}
|
||||||
* A promise which will resolve with an array of @link{Form}
|
* A promise which will resolve with an array of @link{Form}
|
||||||
* objects, where each @link{Form} describes a logical grouping of
|
* objects, where each @link{Form} describes a logical grouping of
|
||||||
* possible attributes.
|
* possible attributes.
|
||||||
*/
|
*/
|
||||||
service.getConnectionGroupAttributes = function getConnectionGroupAttributes() {
|
service.getConnectionGroupAttributes = function getConnectionGroupAttributes(dataSource) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -111,7 +129,7 @@ angular.module('rest').factory('schemaService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.schema,
|
cache : cacheService.schema,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/schema/connectionGroups/attributes',
|
url : 'api/schema/' + encodeURIComponent(dataSource) + '/connectionGroups/attributes',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,11 +140,16 @@ angular.module('rest').factory('schemaService', ['$injector',
|
|||||||
* a promise that provides a map of @link{Protocol} objects by protocol
|
* a promise that provides a map of @link{Protocol} objects by protocol
|
||||||
* name if successful.
|
* name if successful.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source defining available
|
||||||
|
* protocols. This identifier corresponds to an AuthenticationProvider
|
||||||
|
* within the Guacamole web application.
|
||||||
|
*
|
||||||
* @returns {Promise.<Object.<String, Protocol>>}
|
* @returns {Promise.<Object.<String, Protocol>>}
|
||||||
* A promise which will resolve with a map of @link{Protocol}
|
* A promise which will resolve with a map of @link{Protocol}
|
||||||
* objects by protocol name upon success.
|
* objects by protocol name upon success.
|
||||||
*/
|
*/
|
||||||
service.getProtocols = function getProtocols() {
|
service.getProtocols = function getProtocols(dataSource) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -137,7 +160,7 @@ angular.module('rest').factory('schemaService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.schema,
|
cache : cacheService.schema,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/schema/protocols',
|
url : 'api/schema/' + encodeURIComponent(dataSource) + '/protocols',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -28,6 +28,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $http = $injector.get('$http');
|
var $http = $injector.get('$http');
|
||||||
|
var $q = $injector.get('$q');
|
||||||
var authenticationService = $injector.get('authenticationService');
|
var authenticationService = $injector.get('authenticationService');
|
||||||
var cacheService = $injector.get('cacheService');
|
var cacheService = $injector.get('cacheService');
|
||||||
|
|
||||||
@@ -41,6 +42,11 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* returning a promise that provides an array of @link{User} objects if
|
* returning a promise that provides an array of @link{User} objects if
|
||||||
* successful.
|
* successful.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the users to be
|
||||||
|
* retrieved. This identifier corresponds to an AuthenticationProvider
|
||||||
|
* within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {String[]} [permissionTypes]
|
* @param {String[]} [permissionTypes]
|
||||||
* The set of permissions to filter with. A user must have one or more
|
* The set of permissions to filter with. A user must have one or more
|
||||||
* of these permissions for a user to appear in the result.
|
* of these permissions for a user to appear in the result.
|
||||||
@@ -51,7 +57,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* A promise which will resolve with an array of @link{User} objects
|
* A promise which will resolve with an array of @link{User} objects
|
||||||
* upon success.
|
* upon success.
|
||||||
*/
|
*/
|
||||||
service.getUsers = function getUsers(permissionTypes) {
|
service.getUsers = function getUsers(dataSource, permissionTypes) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -66,7 +72,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.users,
|
cache : cacheService.users,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/users',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/users',
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -76,14 +82,19 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* Makes a request to the REST API to get the user having the given
|
* Makes a request to the REST API to get the user having the given
|
||||||
* username, returning a promise that provides the corresponding
|
* username, returning a promise that provides the corresponding
|
||||||
* @link{User} if successful.
|
* @link{User} if successful.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the user to be
|
||||||
|
* retrieved. This identifier corresponds to an AuthenticationProvider
|
||||||
|
* within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {String} username
|
* @param {String} username
|
||||||
* The username of the user to retrieve.
|
* The username of the user to retrieve.
|
||||||
*
|
*
|
||||||
* @returns {Promise.<User>}
|
* @returns {Promise.<User>}
|
||||||
* A promise which will resolve with a @link{User} upon success.
|
* A promise which will resolve with a @link{User} upon success.
|
||||||
*/
|
*/
|
||||||
service.getUser = function getUser(username) {
|
service.getUser = function getUser(dataSource, username) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -94,7 +105,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
return $http({
|
return $http({
|
||||||
cache : cacheService.users,
|
cache : cacheService.users,
|
||||||
method : 'GET',
|
method : 'GET',
|
||||||
url : 'api/users/' + encodeURIComponent(username),
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/users/' + encodeURIComponent(username),
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -104,6 +115,11 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* Makes a request to the REST API to delete a user, returning a promise
|
* Makes a request to the REST API to delete a user, returning a promise
|
||||||
* that can be used for processing the results of the call.
|
* that can be used for processing the results of the call.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the user to be
|
||||||
|
* deleted. This identifier corresponds to an AuthenticationProvider
|
||||||
|
* within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {User} user
|
* @param {User} user
|
||||||
* The user to delete.
|
* The user to delete.
|
||||||
*
|
*
|
||||||
@@ -111,7 +127,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* delete operation is successful.
|
* delete operation is successful.
|
||||||
*/
|
*/
|
||||||
service.deleteUser = function deleteUser(user) {
|
service.deleteUser = function deleteUser(dataSource, user) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -121,7 +137,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
// Delete user
|
// Delete user
|
||||||
return $http({
|
return $http({
|
||||||
method : 'DELETE',
|
method : 'DELETE',
|
||||||
url : 'api/users/' + encodeURIComponent(user.username),
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/users/' + encodeURIComponent(user.username),
|
||||||
params : httpParameters
|
params : httpParameters
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -137,6 +153,11 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* Makes a request to the REST API to create a user, returning a promise
|
* Makes a request to the REST API to create a user, returning a promise
|
||||||
* that can be used for processing the results of the call.
|
* that can be used for processing the results of the call.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source in which the user should be
|
||||||
|
* created. This identifier corresponds to an AuthenticationProvider
|
||||||
|
* within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {User} user
|
* @param {User} user
|
||||||
* The user to create.
|
* The user to create.
|
||||||
*
|
*
|
||||||
@@ -144,7 +165,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* create operation is successful.
|
* create operation is successful.
|
||||||
*/
|
*/
|
||||||
service.createUser = function createUser(user) {
|
service.createUser = function createUser(dataSource, user) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -154,7 +175,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
// Create user
|
// Create user
|
||||||
return $http({
|
return $http({
|
||||||
method : 'POST',
|
method : 'POST',
|
||||||
url : 'api/users',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/users',
|
||||||
params : httpParameters,
|
params : httpParameters,
|
||||||
data : user
|
data : user
|
||||||
})
|
})
|
||||||
@@ -170,6 +191,11 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* Makes a request to the REST API to save a user, returning a promise that
|
* Makes a request to the REST API to save a user, returning a promise that
|
||||||
* can be used for processing the results of the call.
|
* can be used for processing the results of the call.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the user to be
|
||||||
|
* updated. This identifier corresponds to an AuthenticationProvider
|
||||||
|
* within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {User} user
|
* @param {User} user
|
||||||
* The user to update.
|
* The user to update.
|
||||||
*
|
*
|
||||||
@@ -177,7 +203,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* save operation is successful.
|
* save operation is successful.
|
||||||
*/
|
*/
|
||||||
service.saveUser = function saveUser(user) {
|
service.saveUser = function saveUser(dataSource, user) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
var httpParameters = {
|
var httpParameters = {
|
||||||
@@ -187,7 +213,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
// Update user
|
// Update user
|
||||||
return $http({
|
return $http({
|
||||||
method : 'PUT',
|
method : 'PUT',
|
||||||
url : 'api/users/' + encodeURIComponent(user.username),
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/users/' + encodeURIComponent(user.username),
|
||||||
params : httpParameters,
|
params : httpParameters,
|
||||||
data : user
|
data : user
|
||||||
})
|
})
|
||||||
@@ -203,6 +229,11 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* Makes a request to the REST API to update the password for a user,
|
* Makes a request to the REST API to update the password for a user,
|
||||||
* returning a promise that can be used for processing the results of the call.
|
* returning a promise that can be used for processing the results of the call.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The unique identifier of the data source containing the user to be
|
||||||
|
* updated. This identifier corresponds to an AuthenticationProvider
|
||||||
|
* within the Guacamole web application.
|
||||||
|
*
|
||||||
* @param {String} username
|
* @param {String} username
|
||||||
* The username of the user to update.
|
* The username of the user to update.
|
||||||
*
|
*
|
||||||
@@ -216,7 +247,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* password update operation is successful.
|
* password update operation is successful.
|
||||||
*/
|
*/
|
||||||
service.updateUserPassword = function updateUserPassword(username,
|
service.updateUserPassword = function updateUserPassword(dataSource, username,
|
||||||
oldPassword, newPassword) {
|
oldPassword, newPassword) {
|
||||||
|
|
||||||
// Build HTTP parameters set
|
// Build HTTP parameters set
|
||||||
@@ -227,7 +258,7 @@ angular.module('rest').factory('userService', ['$injector',
|
|||||||
// Update user password
|
// Update user password
|
||||||
return $http({
|
return $http({
|
||||||
method : 'PUT',
|
method : 'PUT',
|
||||||
url : 'api/users/' + encodeURIComponent(username) + '/password',
|
url : 'api/data/' + encodeURIComponent(dataSource) + '/users/' + encodeURIComponent(username) + '/password',
|
||||||
params : httpParameters,
|
params : httpParameters,
|
||||||
data : new UserPasswordUpdate({
|
data : new UserPasswordUpdate({
|
||||||
oldPassword : oldPassword,
|
oldPassword : oldPassword,
|
||||||
|
@@ -46,17 +46,6 @@ angular.module('manage').controller('settingsController', ['$scope', '$injector'
|
|||||||
*/
|
*/
|
||||||
$scope.activeTab = $routeParams.tab;
|
$scope.activeTab = $routeParams.tab;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the list of all available settings tabs should be shown.
|
|
||||||
*
|
|
||||||
* @returns {Boolean}
|
|
||||||
* true if the list of available settings tabs should be shown, false
|
|
||||||
* otherwise.
|
|
||||||
*/
|
|
||||||
$scope.showAvailableTabs = function showAvailableTabs() {
|
|
||||||
return !!$scope.settingsPages && $scope.settingsPages.length > 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Retrieve settings pages
|
// Retrieve settings pages
|
||||||
userPageService.getSettingsPages()
|
userPageService.getSettingsPages()
|
||||||
.then(function settingsPagesRetrieved(pages) {
|
.then(function settingsPagesRetrieved(pages) {
|
||||||
|
@@ -41,13 +41,18 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
|
|||||||
var PermissionSet = $injector.get('PermissionSet');
|
var PermissionSet = $injector.get('PermissionSet');
|
||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $location = $injector.get('$location');
|
var $routeParams = $injector.get('$routeParams');
|
||||||
var authenticationService = $injector.get('authenticationService');
|
var authenticationService = $injector.get('authenticationService');
|
||||||
var connectionGroupService = $injector.get('connectionGroupService');
|
var connectionGroupService = $injector.get('connectionGroupService');
|
||||||
|
var dataSourceService = $injector.get('dataSourceService');
|
||||||
var guacNotification = $injector.get('guacNotification');
|
var guacNotification = $injector.get('guacNotification');
|
||||||
var permissionService = $injector.get('permissionService');
|
var permissionService = $injector.get('permissionService');
|
||||||
|
|
||||||
// Identifier of the current user
|
/**
|
||||||
|
* The identifier of the current user.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
var currentUsername = authenticationService.getCurrentUsername();
|
var currentUsername = authenticationService.getCurrentUsername();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,12 +67,19 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier of the currently-selected data source.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
$scope.dataSource = $routeParams.dataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The root connection group of the connection group hierarchy.
|
* The root connection group of the connection group hierarchy.
|
||||||
*
|
*
|
||||||
* @type ConnectionGroup
|
* @type Object.<String, ConnectionGroup>
|
||||||
*/
|
*/
|
||||||
$scope.rootGroup = null;
|
$scope.rootGroups = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the current user can manage connections. If the current
|
* Whether the current user can manage connections. If the current
|
||||||
@@ -98,7 +110,7 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
|
|||||||
* All permissions associated with the current user, or null if the
|
* All permissions associated with the current user, or null if the
|
||||||
* user's permissions have not yet been loaded.
|
* user's permissions have not yet been loaded.
|
||||||
*
|
*
|
||||||
* @type PermissionSet
|
* @type Object.<String, PermissionSet>
|
||||||
*/
|
*/
|
||||||
$scope.permissions = null;
|
$scope.permissions = null;
|
||||||
|
|
||||||
@@ -111,57 +123,142 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
|
|||||||
*/
|
*/
|
||||||
$scope.isLoaded = function isLoaded() {
|
$scope.isLoaded = function isLoaded() {
|
||||||
|
|
||||||
return $scope.rootGroup !== null
|
return $scope.rootGroup !== null
|
||||||
&& $scope.permissions !== null
|
&& $scope.permissions !== null;
|
||||||
&& $scope.canManageConnections !== null
|
|
||||||
&& $scope.canCreateConnections !== null
|
};
|
||||||
&& $scope.canCreateConnectionGroups !== null;
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can create new connections
|
||||||
|
* within at least one data source.
|
||||||
|
*
|
||||||
|
* @return {Boolean}
|
||||||
|
* true if the current user can create new connections within
|
||||||
|
* at least one data source, false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.canCreateConnections = function canCreateConnections() {
|
||||||
|
|
||||||
|
// Abort if permissions have not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// For each data source
|
||||||
|
for (var dataSource in $scope.permissions) {
|
||||||
|
|
||||||
|
// Retrieve corresponding permission set
|
||||||
|
var permissionSet = $scope.permissions[dataSource];
|
||||||
|
|
||||||
|
// Can create connections if adminstrator or have explicit permission
|
||||||
|
if (PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.ADMINISTER)
|
||||||
|
|| PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.CREATE_CONNECTION))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// No data sources allow connection creation
|
||||||
|
return false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can create new connection
|
||||||
|
* groups within at least one data source.
|
||||||
|
*
|
||||||
|
* @return {Boolean}
|
||||||
|
* true if the current user can create new connection groups
|
||||||
|
* within at least one data source, false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.canCreateConnectionGroups = function canCreateConnectionGroups() {
|
||||||
|
|
||||||
|
// Abort if permissions have not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// For each data source
|
||||||
|
for (var dataSource in $scope.permissions) {
|
||||||
|
|
||||||
|
// Retrieve corresponding permission set
|
||||||
|
var permissionSet = $scope.permissions[dataSource];
|
||||||
|
|
||||||
|
// Can create connections groups if adminstrator or have explicit permission
|
||||||
|
if (PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.ADMINISTER)
|
||||||
|
|| PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.CREATE_CONNECTION_GROUP))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// No data sources allow connection group creation
|
||||||
|
return false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can create new connections or
|
||||||
|
* connection groups or make changes to existing connections or
|
||||||
|
* connection groups within at least one data source. The
|
||||||
|
* connection management interface as a whole is useless if this
|
||||||
|
* function returns false.
|
||||||
|
*
|
||||||
|
* @return {Boolean}
|
||||||
|
* true if the current user can create new connections/groups
|
||||||
|
* or make changes to existing connections/groups within at
|
||||||
|
* least one data source, false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.canManageConnections = function canManageConnections() {
|
||||||
|
|
||||||
|
// Abort if permissions have not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Creating connections/groups counts as management
|
||||||
|
if ($scope.canCreateConnections() || $scope.canCreateConnectionGroups())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Ignore permission to update root group
|
||||||
|
PermissionSet.removeConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, ConnectionGroup.ROOT_IDENTIFIER);
|
||||||
|
|
||||||
|
// For each data source
|
||||||
|
for (var dataSource in $scope.permissions) {
|
||||||
|
|
||||||
|
// Retrieve corresponding permission set
|
||||||
|
var permissionSet = $scope.permissions[dataSource];
|
||||||
|
|
||||||
|
// Can manage connections if granted explicit update or delete
|
||||||
|
if (PermissionSet.hasConnectionPermission(permissionSet, PermissionSet.ObjectPermissionType.UPDATE)
|
||||||
|
|| PermissionSet.hasConnectionPermission(permissionSet, PermissionSet.ObjectPermissionType.DELETE))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Can manage connections groups if granted explicit update or delete
|
||||||
|
if (PermissionSet.hasConnectionGroupPermission(permissionSet, PermissionSet.ObjectPermissionType.UPDATE)
|
||||||
|
|| PermissionSet.hasConnectionGroupPermission(permissionSet, PermissionSet.ObjectPermissionType.DELETE))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// No data sources allow management of connections or groups
|
||||||
|
return false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Retrieve current permissions
|
// Retrieve current permissions
|
||||||
permissionService.getPermissions(currentUsername)
|
dataSourceService.apply(
|
||||||
.success(function permissionsRetrieved(permissions) {
|
permissionService.getPermissions,
|
||||||
|
[$scope.dataSource],
|
||||||
|
currentUsername
|
||||||
|
)
|
||||||
|
.then(function permissionsRetrieved(permissions) {
|
||||||
$scope.permissions = permissions;
|
$scope.permissions = permissions;
|
||||||
|
|
||||||
// Ignore permission to update root group
|
|
||||||
PermissionSet.removeConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, ConnectionGroup.ROOT_IDENTIFIER);
|
|
||||||
|
|
||||||
// Determine whether the current user can create new users
|
|
||||||
$scope.canCreateConnections =
|
|
||||||
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
|
||||||
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION);
|
|
||||||
|
|
||||||
// Determine whether the current user can create new users
|
|
||||||
$scope.canCreateConnectionGroups =
|
|
||||||
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
|
||||||
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION_GROUP);
|
|
||||||
|
|
||||||
// Determine whether the current user can manage other connections or groups
|
|
||||||
$scope.canManageConnections =
|
|
||||||
|
|
||||||
// Permission to manage connections
|
|
||||||
$scope.canCreateConnections
|
|
||||||
|| PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE)
|
|
||||||
|| PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.DELETE)
|
|
||||||
|
|
||||||
// Permission to manage groups
|
|
||||||
|| $scope.canCreateConnectionGroups
|
|
||||||
|| PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE)
|
|
||||||
|| PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.DELETE);
|
|
||||||
|
|
||||||
// Return to home if there's nothing to do here
|
|
||||||
if (!$scope.canManageConnections)
|
|
||||||
$location.path('/');
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Retrieve all connections for which we have UPDATE or DELETE permission
|
// Retrieve all connections for which we have UPDATE or DELETE permission
|
||||||
connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER,
|
dataSourceService.apply(
|
||||||
[PermissionSet.ObjectPermissionType.UPDATE, PermissionSet.ObjectPermissionType.DELETE])
|
connectionGroupService.getConnectionGroupTree,
|
||||||
.success(function connectionGroupReceived(rootGroup) {
|
[$scope.dataSource],
|
||||||
$scope.rootGroup = rootGroup;
|
ConnectionGroup.ROOT_IDENTIFIER,
|
||||||
|
[PermissionSet.ObjectPermissionType.UPDATE, PermissionSet.ObjectPermissionType.DELETE]
|
||||||
|
)
|
||||||
|
.then(function connectionGroupsReceived(rootGroups) {
|
||||||
|
$scope.rootGroups = rootGroups;
|
||||||
});
|
});
|
||||||
|
|
||||||
}]
|
}]
|
||||||
|
@@ -66,6 +66,14 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe
|
|||||||
*/
|
*/
|
||||||
var username = authenticationService.getCurrentUsername();
|
var username = authenticationService.getCurrentUsername();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier of the data source which authenticated the
|
||||||
|
* current user.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
var dataSource = authenticationService.getDataSource();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All currently-set preferences, or their defaults if not yet set.
|
* All currently-set preferences, or their defaults if not yet set.
|
||||||
*
|
*
|
||||||
@@ -140,7 +148,7 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save the user with the new password
|
// Save the user with the new password
|
||||||
userService.updateUserPassword(username, $scope.oldPassword, $scope.newPassword)
|
userService.updateUserPassword(dataSource, username, $scope.oldPassword, $scope.newPassword)
|
||||||
.success(function passwordUpdated() {
|
.success(function passwordUpdated() {
|
||||||
|
|
||||||
// Clear the password fields
|
// Clear the password fields
|
||||||
@@ -174,7 +182,7 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Retrieve current permissions
|
// Retrieve current permissions
|
||||||
permissionService.getPermissions(username)
|
permissionService.getPermissions(dataSource, username)
|
||||||
.success(function permissionsRetrieved(permissions) {
|
.success(function permissionsRetrieved(permissions) {
|
||||||
|
|
||||||
// Add action for changing password if permission is granted
|
// Add action for changing password if permission is granted
|
||||||
|
@@ -44,19 +44,20 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
// Required services
|
// Required services
|
||||||
var $filter = $injector.get('$filter');
|
var $filter = $injector.get('$filter');
|
||||||
var $translate = $injector.get('$translate');
|
var $translate = $injector.get('$translate');
|
||||||
|
var $q = $injector.get('$q');
|
||||||
var activeConnectionService = $injector.get('activeConnectionService');
|
var activeConnectionService = $injector.get('activeConnectionService');
|
||||||
var authenticationService = $injector.get('authenticationService');
|
var authenticationService = $injector.get('authenticationService');
|
||||||
var connectionGroupService = $injector.get('connectionGroupService');
|
var connectionGroupService = $injector.get('connectionGroupService');
|
||||||
|
var dataSourceService = $injector.get('dataSourceService');
|
||||||
var guacNotification = $injector.get('guacNotification');
|
var guacNotification = $injector.get('guacNotification');
|
||||||
var permissionService = $injector.get('permissionService');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All permissions associated with the current user, or null if the
|
* The identifiers of all data sources accessible by the current
|
||||||
* user's permissions have not yet been loaded.
|
* user.
|
||||||
*
|
*
|
||||||
* @type PermissionSet
|
* @type String[]
|
||||||
*/
|
*/
|
||||||
$scope.permissions = null;
|
var dataSources = authenticationService.getAvailableDataSources();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ActiveConnectionWrappers of all active sessions accessible
|
* The ActiveConnectionWrappers of all active sessions accessible
|
||||||
@@ -93,20 +94,22 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All active connections, if known, or null if active connections
|
* All active connections, if known, grouped by corresponding data
|
||||||
* have not yet been loaded.
|
* source identifier, or null if active connections have not yet
|
||||||
|
* been loaded.
|
||||||
*
|
*
|
||||||
* @type ActiveConnection
|
* @type Object.<String, Object.<String, ActiveConnection>>
|
||||||
*/
|
*/
|
||||||
var activeConnections = null;
|
var allActiveConnections = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of all visible connections by object identifier, or null if
|
* Map of all visible connections by data source identifier and
|
||||||
* visible connections have not yet been loaded.
|
* object identifier, or null if visible connections have not yet
|
||||||
|
* been loaded.
|
||||||
*
|
*
|
||||||
* @type Object.<String, Connection>
|
* @type Object.<String, Object.<String, Connection>>
|
||||||
*/
|
*/
|
||||||
var connections = null;
|
var allConnections = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The date format for use for session-related dates.
|
* The date format for use for session-related dates.
|
||||||
@@ -117,24 +120,28 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of all currently-selected active connection wrappers by
|
* Map of all currently-selected active connection wrappers by
|
||||||
* identifier.
|
* data source and identifier.
|
||||||
*
|
*
|
||||||
* @type Object.<String, ActiveConnectionWrapper>
|
* @type Object.<String, Object.<String, ActiveConnectionWrapper>>
|
||||||
*/
|
*/
|
||||||
var selectedWrappers = {};
|
var allSelectedWrappers = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given connection to the internal set of visible
|
* Adds the given connection to the internal set of visible
|
||||||
* connections.
|
* connections.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The identifier of the data source associated with the given
|
||||||
|
* connection.
|
||||||
|
*
|
||||||
* @param {Connection} connection
|
* @param {Connection} connection
|
||||||
* The connection to add to the internal set of visible
|
* The connection to add to the internal set of visible
|
||||||
* connections.
|
* connections.
|
||||||
*/
|
*/
|
||||||
var addConnection = function addConnection(connection) {
|
var addConnection = function addConnection(dataSource, connection) {
|
||||||
|
|
||||||
// Add given connection to set of visible connections
|
// Add given connection to set of visible connections
|
||||||
connections[connection.identifier] = connection;
|
allConnections[dataSource][connection.identifier] = connection;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,19 +149,25 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
* Adds all descendant connections of the given connection group to
|
* Adds all descendant connections of the given connection group to
|
||||||
* the internal set of connections.
|
* the internal set of connections.
|
||||||
*
|
*
|
||||||
|
* @param {String} dataSource
|
||||||
|
* The identifier of the data source associated with the given
|
||||||
|
* connection group.
|
||||||
|
*
|
||||||
* @param {ConnectionGroup} connectionGroup
|
* @param {ConnectionGroup} connectionGroup
|
||||||
* The connection group whose descendant connections should be
|
* The connection group whose descendant connections should be
|
||||||
* added to the internal set of connections.
|
* added to the internal set of connections.
|
||||||
*/
|
*/
|
||||||
var addDescendantConnections = function addDescendantConnections(connectionGroup) {
|
var addDescendantConnections = function addDescendantConnections(dataSource, connectionGroup) {
|
||||||
|
|
||||||
// Add all child connections
|
// Add all child connections
|
||||||
if (connectionGroup.childConnections)
|
angular.forEach(connectionGroup.childConnections, function addConnectionForDataSource(connection) {
|
||||||
connectionGroup.childConnections.forEach(addConnection);
|
addConnection(dataSource, connection);
|
||||||
|
});
|
||||||
|
|
||||||
// Add all child connection groups
|
// Add all child connection groups
|
||||||
if (connectionGroup.childConnectionGroups)
|
angular.forEach(connectionGroup.childConnectionGroups, function addConnectionGroupForDataSource(connectionGroup) {
|
||||||
connectionGroup.childConnectionGroups.forEach(addDescendantConnections);
|
addDescendantConnections(dataSource, connectionGroup);
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -163,56 +176,66 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
* within the scope. If required data has not yet finished loading,
|
* within the scope. If required data has not yet finished loading,
|
||||||
* this function has no effect.
|
* this function has no effect.
|
||||||
*/
|
*/
|
||||||
var wrapActiveConnections = function wrapActiveConnections() {
|
var wrapAllActiveConnections = function wrapAllActiveConnections() {
|
||||||
|
|
||||||
// Abort if not all required data is available
|
// Abort if not all required data is available
|
||||||
if (!activeConnections || !connections || !sessionDateFormat)
|
if (!allActiveConnections || !allConnections || !sessionDateFormat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Wrap all active connections for sake of display
|
// Wrap all active connections for sake of display
|
||||||
$scope.wrappers = [];
|
$scope.wrappers = [];
|
||||||
for (var identifier in activeConnections) {
|
angular.forEach(allActiveConnections, function wrapActiveConnections(activeConnections, dataSource) {
|
||||||
|
angular.forEach(activeConnections, function wrapActiveConnection(activeConnection, identifier) {
|
||||||
|
|
||||||
var activeConnection = activeConnections[identifier];
|
// Retrieve corresponding connection
|
||||||
var connection = connections[activeConnection.connectionIdentifier];
|
var connection = allConnections[dataSource][activeConnection.connectionIdentifier];
|
||||||
|
|
||||||
$scope.wrappers.push(new ActiveConnectionWrapper(
|
// Add wrapper
|
||||||
connection.name,
|
$scope.wrappers.push(new ActiveConnectionWrapper({
|
||||||
$filter('date')(activeConnection.startDate, sessionDateFormat),
|
dataSource : dataSource,
|
||||||
activeConnection
|
name : connection.name,
|
||||||
));
|
startDate : $filter('date')(activeConnection.startDate, sessionDateFormat),
|
||||||
|
activeConnection : activeConnection
|
||||||
|
}));
|
||||||
|
|
||||||
}
|
});
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Query the user's permissions
|
|
||||||
permissionService.getPermissions(authenticationService.getCurrentUsername())
|
|
||||||
.success(function permissionsReceived(retrievedPermissions) {
|
|
||||||
$scope.permissions = retrievedPermissions;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Retrieve all connections
|
// Retrieve all connections
|
||||||
connectionGroupService.getConnectionGroupTree(ConnectionGroup.ROOT_IDENTIFIER)
|
dataSourceService.apply(
|
||||||
.success(function connectionGroupReceived(retrievedRootGroup) {
|
connectionGroupService.getConnectionGroupTree,
|
||||||
|
dataSources,
|
||||||
|
ConnectionGroup.ROOT_IDENTIFIER
|
||||||
|
)
|
||||||
|
.then(function connectionGroupsReceived(rootGroups) {
|
||||||
|
|
||||||
// Load connections from retrieved group tree
|
allConnections = {};
|
||||||
connections = {};
|
|
||||||
addDescendantConnections(retrievedRootGroup);
|
// Load connections from each received root group
|
||||||
|
angular.forEach(rootGroups, function connectionGroupReceived(rootGroup, dataSource) {
|
||||||
|
allConnections[dataSource] = {};
|
||||||
|
addDescendantConnections(dataSource, rootGroup);
|
||||||
|
});
|
||||||
|
|
||||||
// Attempt to produce wrapped list of active connections
|
// Attempt to produce wrapped list of active connections
|
||||||
wrapActiveConnections();
|
wrapAllActiveConnections();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Query active sessions
|
// Query active sessions
|
||||||
activeConnectionService.getActiveConnections().success(function sessionsRetrieved(retrievedActiveConnections) {
|
dataSourceService.apply(
|
||||||
|
activeConnectionService.getActiveConnections,
|
||||||
|
dataSources
|
||||||
|
)
|
||||||
|
.then(function sessionsRetrieved(retrievedActiveConnections) {
|
||||||
|
|
||||||
// Store received list
|
// Store received map of active connections
|
||||||
activeConnections = retrievedActiveConnections;
|
allActiveConnections = retrievedActiveConnections;
|
||||||
|
|
||||||
// Attempt to produce wrapped list of active connections
|
// Attempt to produce wrapped list of active connections
|
||||||
wrapActiveConnections();
|
wrapAllActiveConnections();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -223,7 +246,7 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
sessionDateFormat = retrievedSessionDateFormat;
|
sessionDateFormat = retrievedSessionDateFormat;
|
||||||
|
|
||||||
// Attempt to produce wrapped list of active connections
|
// Attempt to produce wrapped list of active connections
|
||||||
wrapActiveConnections();
|
wrapAllActiveConnections();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -235,11 +258,7 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
* to be useful, false otherwise.
|
* to be useful, false otherwise.
|
||||||
*/
|
*/
|
||||||
$scope.isLoaded = function isLoaded() {
|
$scope.isLoaded = function isLoaded() {
|
||||||
|
return $scope.wrappers !== null;
|
||||||
return $scope.wrappers !== null
|
|
||||||
&& $scope.sessionDateFormat !== null
|
|
||||||
&& $scope.permissions !== null;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -276,7 +295,7 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
className : "danger",
|
className : "danger",
|
||||||
// Handle action
|
// Handle action
|
||||||
callback : function deleteCallback() {
|
callback : function deleteCallback() {
|
||||||
deleteSessionsImmediately();
|
deleteAllSessionsImmediately();
|
||||||
guacNotification.showStatus(false);
|
guacNotification.showStatus(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -285,24 +304,36 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
* Immediately deletes the selected sessions, without prompting the
|
* Immediately deletes the selected sessions, without prompting the
|
||||||
* user for confirmation.
|
* user for confirmation.
|
||||||
*/
|
*/
|
||||||
var deleteSessionsImmediately = function deleteSessionsImmediately() {
|
var deleteAllSessionsImmediately = function deleteAllSessionsImmediately() {
|
||||||
|
|
||||||
// Perform deletion
|
var deletionRequests = [];
|
||||||
activeConnectionService.deleteActiveConnections(Object.keys(selectedWrappers))
|
|
||||||
.success(function activeConnectionsDeleted() {
|
// Perform deletion for each relevant data source
|
||||||
|
angular.forEach(allSelectedWrappers, function deleteSessionsImmediately(selectedWrappers, dataSource) {
|
||||||
|
|
||||||
|
// Delete sessions, if any are selected
|
||||||
|
var identifiers = Object.keys(selectedWrappers);
|
||||||
|
if (identifiers.length)
|
||||||
|
deletionRequests.push(activeConnectionService.deleteActiveConnections(dataSource, identifiers));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update interface
|
||||||
|
$q.all(deletionRequests)
|
||||||
|
.then(function activeConnectionsDeleted() {
|
||||||
|
|
||||||
// Remove deleted connections from wrapper array
|
// Remove deleted connections from wrapper array
|
||||||
$scope.wrappers = $scope.wrappers.filter(function activeConnectionStillExists(wrapper) {
|
$scope.wrappers = $scope.wrappers.filter(function activeConnectionStillExists(wrapper) {
|
||||||
return !(wrapper.activeConnection.identifier in selectedWrappers);
|
return !(wrapper.activeConnection.identifier in (allSelectedWrappers[wrapper.dataSource] || {}));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clear selection
|
// Clear selection
|
||||||
selectedWrappers = {};
|
allSelectedWrappers = {};
|
||||||
|
|
||||||
})
|
},
|
||||||
|
|
||||||
// Notify of any errors
|
// Notify of any errors
|
||||||
.error(function activeConnectionDeletionFailed(error) {
|
function activeConnectionDeletionFailed(error) {
|
||||||
guacNotification.showStatus({
|
guacNotification.showStatus({
|
||||||
'className' : 'error',
|
'className' : 'error',
|
||||||
'title' : 'SETTINGS_SESSIONS.DIALOG_HEADER_ERROR',
|
'title' : 'SETTINGS_SESSIONS.DIALOG_HEADER_ERROR',
|
||||||
@@ -335,8 +366,10 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
$scope.canDeleteSessions = function canDeleteSessions() {
|
$scope.canDeleteSessions = function canDeleteSessions() {
|
||||||
|
|
||||||
// We can delete sessions if at least one is selected
|
// We can delete sessions if at least one is selected
|
||||||
for (var identifier in selectedWrappers)
|
for (var dataSource in allSelectedWrappers) {
|
||||||
return true;
|
for (var identifier in allSelectedWrappers[dataSource])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -351,6 +384,11 @@ angular.module('settings').directive('guacSettingsSessions', [function guacSetti
|
|||||||
*/
|
*/
|
||||||
$scope.wrapperSelectionChange = function wrapperSelectionChange(wrapper) {
|
$scope.wrapperSelectionChange = function wrapperSelectionChange(wrapper) {
|
||||||
|
|
||||||
|
// Get selection map for associated data source, creating if necessary
|
||||||
|
var selectedWrappers = allSelectedWrappers[wrapper.dataSource];
|
||||||
|
if (!selectedWrappers)
|
||||||
|
selectedWrappers = allSelectedWrappers[wrapper.dataSource] = {};
|
||||||
|
|
||||||
// Add wrapper to map if selected
|
// Add wrapper to map if selected
|
||||||
if (wrapper.checked)
|
if (wrapper.checked)
|
||||||
selectedWrappers[wrapper.activeConnection.identifier] = wrapper;
|
selectedWrappers[wrapper.activeConnection.identifier] = wrapper;
|
||||||
|
@@ -37,12 +37,13 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
|
|||||||
controller: ['$scope', '$injector', function settingsUsersController($scope, $injector) {
|
controller: ['$scope', '$injector', function settingsUsersController($scope, $injector) {
|
||||||
|
|
||||||
// Required types
|
// Required types
|
||||||
|
var ManageableUser = $injector.get('ManageableUser');
|
||||||
var PermissionSet = $injector.get('PermissionSet');
|
var PermissionSet = $injector.get('PermissionSet');
|
||||||
var User = $injector.get('User');
|
|
||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $location = $injector.get('$location');
|
var $location = $injector.get('$location');
|
||||||
var authenticationService = $injector.get('authenticationService');
|
var authenticationService = $injector.get('authenticationService');
|
||||||
|
var dataSourceService = $injector.get('dataSourceService');
|
||||||
var guacNotification = $injector.get('guacNotification');
|
var guacNotification = $injector.get('guacNotification');
|
||||||
var permissionService = $injector.get('permissionService');
|
var permissionService = $injector.get('permissionService');
|
||||||
var userService = $injector.get('userService');
|
var userService = $injector.get('userService');
|
||||||
@@ -63,27 +64,19 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All visible users.
|
* The identifiers of all data sources accessible by the current
|
||||||
|
* user.
|
||||||
*
|
*
|
||||||
* @type User[]
|
* @type String[]
|
||||||
*/
|
*/
|
||||||
$scope.users = null;
|
var dataSources = authenticationService.getAvailableDataSources();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the current user can manage users. If the current
|
* All visible users, along with their corresponding data sources.
|
||||||
* permissions have not yet been loaded, this will be null.
|
|
||||||
*
|
*
|
||||||
* @type Boolean
|
* @type ManageableUser[]
|
||||||
*/
|
*/
|
||||||
$scope.canManageUsers = null;
|
$scope.manageableUsers = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the current user can create new users. If the current
|
|
||||||
* permissions have not yet been loaded, this will be null.
|
|
||||||
*
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
$scope.canCreateUsers = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the new user to create, if any, when user creation
|
* The name of the new user to create, if any, when user creation
|
||||||
@@ -94,10 +87,11 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
|
|||||||
$scope.newUsername = "";
|
$scope.newUsername = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All permissions associated with the current user, or null if the
|
* Map of data source identifiers to all permissions associated
|
||||||
|
* with the current user within that data source, or null if the
|
||||||
* user's permissions have not yet been loaded.
|
* user's permissions have not yet been loaded.
|
||||||
*
|
*
|
||||||
* @type PermissionSet
|
* @type Object.<String, PermissionSet>
|
||||||
*/
|
*/
|
||||||
$scope.permissions = null;
|
$scope.permissions = null;
|
||||||
|
|
||||||
@@ -110,80 +104,152 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
|
|||||||
*/
|
*/
|
||||||
$scope.isLoaded = function isLoaded() {
|
$scope.isLoaded = function isLoaded() {
|
||||||
|
|
||||||
return $scope.users !== null
|
return $scope.manageableUsers !== null
|
||||||
&& $scope.permissions !== null
|
&& $scope.permissions !== null;
|
||||||
&& $scope.canManageUsers !== null
|
|
||||||
&& $scope.canCreateUsers !== null;
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the identifier of the data source that should be used by
|
||||||
|
* default when creating a new user.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
* The identifier of the data source that should be used by
|
||||||
|
* default when creating a new user, or null if user creation
|
||||||
|
* is not allowed.
|
||||||
|
*/
|
||||||
|
var getDefaultDataSource = function getDefaultDataSource() {
|
||||||
|
|
||||||
|
// Abort if permissions have not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// For each data source
|
||||||
|
for (var dataSource in $scope.permissions) {
|
||||||
|
|
||||||
|
// Retrieve corresponding permission set
|
||||||
|
var permissionSet = $scope.permissions[dataSource];
|
||||||
|
|
||||||
|
// Can create users if adminstrator or have explicit permission
|
||||||
|
if (PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.ADMINISTER)
|
||||||
|
|| PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.CREATE_USER))
|
||||||
|
return dataSource;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// No data sources allow user creation
|
||||||
|
return null;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can create new users within at
|
||||||
|
* least one data source.
|
||||||
|
*
|
||||||
|
* @return {Boolean}
|
||||||
|
* true if the current user can create new users within at
|
||||||
|
* least one data source, false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.canCreateUsers = function canCreateUsers() {
|
||||||
|
return getDefaultDataSource() !== null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user can create new users or make
|
||||||
|
* changes to existing users within at least one data source. The
|
||||||
|
* user management interface as a whole is useless if this function
|
||||||
|
* returns false.
|
||||||
|
*
|
||||||
|
* @return {Boolean}
|
||||||
|
* true if the current user can create new users or make
|
||||||
|
* changes to existing users within at least one data source,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
var canManageUsers = function canManageUsers() {
|
||||||
|
|
||||||
|
// Abort if permissions have not yet loaded
|
||||||
|
if (!$scope.permissions)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Creating users counts as management
|
||||||
|
if ($scope.canCreateUsers())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// For each data source
|
||||||
|
for (var dataSource in $scope.permissions) {
|
||||||
|
|
||||||
|
// Retrieve corresponding permission set
|
||||||
|
var permissionSet = $scope.permissions[dataSource];
|
||||||
|
|
||||||
|
// Can manage users if granted explicit update or delete
|
||||||
|
if (PermissionSet.hasUserPermission(permissionSet, PermissionSet.ObjectPermissionType.UPDATE)
|
||||||
|
|| PermissionSet.hasUserPermission(permissionSet, PermissionSet.ObjectPermissionType.DELETE))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// No data sources allow management of users
|
||||||
|
return false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Retrieve current permissions
|
// Retrieve current permissions
|
||||||
permissionService.getPermissions(currentUsername)
|
dataSourceService.apply(permissionService.getPermissions, dataSources, currentUsername)
|
||||||
.success(function permissionsRetrieved(permissions) {
|
.then(function permissionsRetrieved(permissions) {
|
||||||
|
|
||||||
|
// Store retrieved permissions
|
||||||
$scope.permissions = permissions;
|
$scope.permissions = permissions;
|
||||||
|
|
||||||
// Determine whether the current user can create new users
|
|
||||||
$scope.canCreateUsers =
|
|
||||||
PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|
|
||||||
|| PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_USER);
|
|
||||||
|
|
||||||
// Determine whether the current user can manage other users
|
|
||||||
$scope.canManageUsers =
|
|
||||||
$scope.canCreateUsers
|
|
||||||
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE)
|
|
||||||
|| PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.DELETE);
|
|
||||||
|
|
||||||
// Return to home if there's nothing to do here
|
// Return to home if there's nothing to do here
|
||||||
if (!$scope.canManageUsers)
|
if (!canManageUsers())
|
||||||
$location.path('/');
|
$location.path('/');
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Retrieve all users for whom we have UPDATE or DELETE permission
|
var userPromise;
|
||||||
userService.getUsers([PermissionSet.ObjectPermissionType.UPDATE,
|
|
||||||
PermissionSet.ObjectPermissionType.DELETE])
|
// If users can be created, list all readable users
|
||||||
.success(function usersReceived(users) {
|
if ($scope.canCreateUsers())
|
||||||
|
userPromise = dataSourceService.apply(userService.getUsers, dataSources);
|
||||||
|
|
||||||
|
// Otherwise, list only updateable/deletable users
|
||||||
|
else
|
||||||
|
userPromise = dataSourceService.apply(userService.getUsers, dataSources, [
|
||||||
|
PermissionSet.ObjectPermissionType.UPDATE,
|
||||||
|
PermissionSet.ObjectPermissionType.DELETE
|
||||||
|
]);
|
||||||
|
|
||||||
|
userPromise.then(function usersReceived(userArrays) {
|
||||||
|
|
||||||
|
var addedUsers = {};
|
||||||
|
$scope.manageableUsers = [];
|
||||||
|
|
||||||
|
// For each user in each data source
|
||||||
|
angular.forEach(dataSources, function addUserList(dataSource) {
|
||||||
|
angular.forEach(userArrays[dataSource], function addUser(user) {
|
||||||
|
|
||||||
|
// Do not add the same user twice
|
||||||
|
if (addedUsers[user.username])
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Add user to overall list
|
||||||
|
addedUsers[user.username] = user;
|
||||||
|
$scope.manageableUsers.push(new ManageableUser ({
|
||||||
|
'dataSource' : dataSource,
|
||||||
|
'user' : user
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Display only other users, not self
|
|
||||||
$scope.users = users.filter(function isNotSelf(user) {
|
|
||||||
return user.username !== currentUsername;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new user having the username specified in the user
|
* Navigates to an interface for creating a new user having the
|
||||||
* creation interface.
|
* username specified.
|
||||||
*/
|
*/
|
||||||
$scope.newUser = function newUser() {
|
$scope.newUser = function newUser() {
|
||||||
|
$location.url('/manage/' + encodeURIComponent(getDefaultDataSource()) + '/users/' + encodeURIComponent($scope.newUsername));
|
||||||
// Create user skeleton
|
|
||||||
var user = new User({
|
|
||||||
username: $scope.newUsername || ''
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create specified user
|
|
||||||
userService.createUser(user)
|
|
||||||
|
|
||||||
// Add user to visible list upon success
|
|
||||||
.success(function userCreated() {
|
|
||||||
$scope.users.push(user);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Notify of any errors
|
|
||||||
.error(function userCreationFailed(error) {
|
|
||||||
guacNotification.showStatus({
|
|
||||||
'className' : 'error',
|
|
||||||
'title' : 'SETTINGS_USERS.DIALOG_HEADER_ERROR',
|
|
||||||
'text' : error.message,
|
|
||||||
'actions' : [ ACKNOWLEDGE_ACTION ]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reset username
|
|
||||||
$scope.newUsername = "";
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}]
|
}]
|
||||||
|
@@ -34,36 +34,3 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-tabs .page-list {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
background: rgba(0, 0, 0, 0.0125);
|
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-tabs .page-list li {
|
|
||||||
display: inline-block;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-tabs .page-list li a[href] {
|
|
||||||
display: block;
|
|
||||||
color: black;
|
|
||||||
text-decoration: none;
|
|
||||||
padding: 0.75em 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-tabs .page-list li a[href]:visited {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-tabs .page-list li a[href]:hover {
|
|
||||||
background-color: #CDA;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings-tabs .page-list li a[href].current,
|
|
||||||
.settings-tabs .page-list li a[href].current:hover {
|
|
||||||
background: rgba(0,0,0,0.3);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<a ng-href="#/manage/connections/{{item.identifier}}">
|
<a ng-href="#/manage/{{item.dataSource}}/connections/{{item.identifier}}">
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2014 Glyptodon LLC
|
Copyright (C) 2014 Glyptodon LLC
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<a ng-href="#/manage/connectionGroups/{{item.identifier}}">
|
<a ng-href="#/manage/{{item.dataSource}}/connectionGroups/{{item.identifier}}">
|
||||||
<!--
|
<!--
|
||||||
Copyright (C) 2014 Glyptodon LLC
|
Copyright (C) 2014 Glyptodon LLC
|
||||||
|
|
||||||
|
@@ -28,8 +28,8 @@ THE SOFTWARE.
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Available tabs -->
|
<!-- Available tabs -->
|
||||||
<div class="settings-tabs">
|
<div class="page-tabs">
|
||||||
<guac-page-list pages="settingsPages" ng-show="showAvailableTabs()"></guac-page-list>
|
<guac-page-list pages="settingsPages"></guac-page-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Selected tab -->
|
<!-- Selected tab -->
|
||||||
|
@@ -29,11 +29,11 @@
|
|||||||
|
|
||||||
<a class="add-connection button"
|
<a class="add-connection button"
|
||||||
ng-show="canCreateConnections"
|
ng-show="canCreateConnections"
|
||||||
href="#/manage/connections/">{{'SETTINGS_CONNECTIONS.ACTION_NEW_CONNECTION' | translate}}</a>
|
href="#/manage/{{dataSource}}/connections/">{{'SETTINGS_CONNECTIONS.ACTION_NEW_CONNECTION' | translate}}</a>
|
||||||
|
|
||||||
<a class="add-connection-group button"
|
<a class="add-connection-group button"
|
||||||
ng-show="canCreateConnectionGroups"
|
ng-show="canCreateConnectionGroups"
|
||||||
href="#/manage/connectionGroups/">{{'SETTINGS_CONNECTIONS.ACTION_NEW_CONNECTION_GROUP' | translate}}</a>
|
href="#/manage/{{dataSource}}/connectionGroups/">{{'SETTINGS_CONNECTIONS.ACTION_NEW_CONNECTION_GROUP' | translate}}</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<div class="connection-list">
|
<div class="connection-list">
|
||||||
<guac-group-list
|
<guac-group-list
|
||||||
page-size="25"
|
page-size="25"
|
||||||
connection-group="rootGroup"
|
connection-groups="rootGroups"
|
||||||
connection-template="'app/settings/templates/connection.html'"
|
connection-template="'app/settings/templates/connection.html'"
|
||||||
connection-group-template="'app/settings/templates/connectionGroup.html'"/>
|
connection-group-template="'app/settings/templates/connectionGroup.html'"/>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -25,24 +25,25 @@
|
|||||||
<p>{{'SETTINGS_USERS.HELP_USERS' | translate}}</p>
|
<p>{{'SETTINGS_USERS.HELP_USERS' | translate}}</p>
|
||||||
|
|
||||||
<!-- Form action buttons -->
|
<!-- Form action buttons -->
|
||||||
<div class="action-buttons" ng-show="canCreateUsers">
|
<div class="action-buttons" ng-show="canCreateUsers()">
|
||||||
<input type="text" ng-model="newUsername" class="name username" autocorrect="off" autocapitalize="off"/>
|
<input type="text" ng-model="newUsername" class="name username" autocorrect="off" autocapitalize="off"/>
|
||||||
<button class="add-user" ng-click="newUser()">{{'SETTINGS_USERS.ACTION_NEW_USER' | translate}}</button>
|
<button class="add-user" ng-click="newUser()">{{'SETTINGS_USERS.ACTION_NEW_USER' | translate}}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- List of users this user has access to -->
|
<!-- List of users this user has access to -->
|
||||||
<div class="user-list">
|
<div class="user-list">
|
||||||
<div ng-repeat="user in userPage" class="user list-item">
|
<div ng-repeat="manageableUser in manageableUserPage" class="user list-item">
|
||||||
<a ng-href="#/manage/users/{{user.username}}">
|
<a ng-href="#/manage/{{manageableUser.dataSource}}/users/{{manageableUser.user.username}}">
|
||||||
<div class="caption">
|
<div class="caption">
|
||||||
<div class="icon user"></div>
|
<div class="icon user"></div>
|
||||||
<span class="name">{{user.username}}</span>
|
<span class="name">{{manageableUser.user.username}}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pager controls for user list -->
|
<!-- Pager controls for user list -->
|
||||||
<guac-pager page="userPage" page-size="25" items="users | orderBy : 'username'"></guac-pager>
|
<guac-pager page="manageableUserPage" page-size="25"
|
||||||
|
items="manageableUsers | orderBy : 'user.username'"></guac-pager>
|
||||||
|
|
||||||
</div>
|
</div>
|
@@ -31,44 +31,47 @@ angular.module('settings').factory('ActiveConnectionWrapper', [
|
|||||||
* properties, such as a checked option.
|
* properties, such as a checked option.
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
* @param {String} name
|
* @param {ActiveConnectionWrapper|Object} template
|
||||||
* The display name of the active connection.
|
* The object whose properties should be copied within the new
|
||||||
*
|
* ActiveConnectionWrapper.
|
||||||
* @param {String} startDate
|
|
||||||
* The date and time this session began, pre-formatted for display.
|
|
||||||
*
|
|
||||||
* @param {ActiveConnection} activeConnection
|
|
||||||
* The ActiveConnection to wrap.
|
|
||||||
*/
|
*/
|
||||||
var ActiveConnectionWrapper = function ActiveConnectionWrapper(name, startDate, activeConnection) {
|
var ActiveConnectionWrapper = function ActiveConnectionWrapper(template) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier of the data source associated with the
|
||||||
|
* ActiveConnection wrapped by this ActiveConnectionWrapper.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.dataSource = template.dataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The display name of this connection.
|
* The display name of this connection.
|
||||||
*
|
*
|
||||||
* @type String
|
* @type String
|
||||||
*/
|
*/
|
||||||
this.name = name;
|
this.name = template.name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The date and time this session began, pre-formatted for display.
|
* The date and time this session began, pre-formatted for display.
|
||||||
*
|
*
|
||||||
* @type String
|
* @type String
|
||||||
*/
|
*/
|
||||||
this.startDate = startDate;
|
this.startDate = template.startDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The wrapped ActiveConnection.
|
* The wrapped ActiveConnection.
|
||||||
*
|
*
|
||||||
* @type ActiveConnection
|
* @type ActiveConnection
|
||||||
*/
|
*/
|
||||||
this.activeConnection = activeConnection;
|
this.activeConnection = template.activeConnection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A flag indicating that the active connection has been selected.
|
* A flag indicating that the active connection has been selected.
|
||||||
*
|
*
|
||||||
* @type Boolean
|
* @type Boolean
|
||||||
*/
|
*/
|
||||||
this.checked = false;
|
this.checked = template.checked || false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BIN
guacamole/src/main/webapp/images/checkmark.png
Normal file
BIN
guacamole/src/main/webapp/images/checkmark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 569 B |
BIN
guacamole/src/main/webapp/images/plus.png
Normal file
BIN
guacamole/src/main/webapp/images/plus.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 299 B |
@@ -125,6 +125,10 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"DATA_SOURCE_DEFAULT" : {
|
||||||
|
"NAME" : "Default (XML)"
|
||||||
|
},
|
||||||
|
|
||||||
"FORM" : {
|
"FORM" : {
|
||||||
|
|
||||||
"FIELD_PLACEHOLDER_DATE" : "YYYY-MM-DD",
|
"FIELD_PLACEHOLDER_DATE" : "YYYY-MM-DD",
|
||||||
@@ -240,7 +244,9 @@
|
|||||||
"FIELD_HEADER_PASSWORD" : "@:APP.FIELD_HEADER_PASSWORD",
|
"FIELD_HEADER_PASSWORD" : "@:APP.FIELD_HEADER_PASSWORD",
|
||||||
"FIELD_HEADER_PASSWORD_AGAIN" : "@:APP.FIELD_HEADER_PASSWORD_AGAIN",
|
"FIELD_HEADER_PASSWORD_AGAIN" : "@:APP.FIELD_HEADER_PASSWORD_AGAIN",
|
||||||
"FIELD_HEADER_USERNAME" : "Username:",
|
"FIELD_HEADER_USERNAME" : "Username:",
|
||||||
|
|
||||||
|
"INFO_READ_ONLY" : "Sorry, but this user account cannot be edited.",
|
||||||
|
|
||||||
"SECTION_HEADER_CONNECTIONS" : "Connections",
|
"SECTION_HEADER_CONNECTIONS" : "Connections",
|
||||||
"SECTION_HEADER_EDIT_USER" : "Edit User",
|
"SECTION_HEADER_EDIT_USER" : "Edit User",
|
||||||
"SECTION_HEADER_PERMISSIONS" : "Permissions",
|
"SECTION_HEADER_PERMISSIONS" : "Permissions",
|
||||||
|
Reference in New Issue
Block a user