mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
Merge pull request #153 from glyptodon/challenge-responses
GUAC-1161: Implement challenge-style responses
This commit is contained in:
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.form;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Represents an arbitrary parameter, such as an HTTP parameter, or the
|
||||
* parameter of a remote desktop protocol.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class Parameter {
|
||||
|
||||
/**
|
||||
* All possible types of parameter.
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
* A text parameter, accepting arbitrary values.
|
||||
*/
|
||||
TEXT,
|
||||
|
||||
/**
|
||||
* A username parameter. This parameter type generally behaves
|
||||
* identically to arbitrary text parameters, but has semantic
|
||||
* differences. If credential pass-through is in use, the value for this
|
||||
* parameter may be automatically provided using the credentials
|
||||
* originally used by the user to authenticate.
|
||||
*/
|
||||
USERNAME,
|
||||
|
||||
/**
|
||||
* A password parameter, whose value is sensitive and must be hidden. If
|
||||
* credential pass-through is in use, the value for this parameter may
|
||||
* be automatically provided using the credentials originally used by
|
||||
* the user to authenticate.
|
||||
*/
|
||||
PASSWORD,
|
||||
|
||||
/**
|
||||
* A numeric parameter, whose value must contain only digits.
|
||||
*/
|
||||
NUMERIC,
|
||||
|
||||
/**
|
||||
* A boolean parameter, whose value is either blank or "true".
|
||||
*/
|
||||
BOOLEAN,
|
||||
|
||||
/**
|
||||
* An enumerated parameter, whose legal values are fully enumerated
|
||||
* by a provided, finite list.
|
||||
*/
|
||||
ENUM,
|
||||
|
||||
/**
|
||||
* A text parameter that can span more than one line.
|
||||
*/
|
||||
MULTILINE
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The unique name that identifies this parameter.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* A human-readable name to be presented to the user.
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* The type of this parameter.
|
||||
*/
|
||||
private Type type;
|
||||
|
||||
/**
|
||||
* The value of this parameter, when checked. This is only applicable to
|
||||
* BOOLEAN parameters.
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* A collection of all associated parameter options.
|
||||
*/
|
||||
private Collection<ParameterOption> options;
|
||||
|
||||
/**
|
||||
* Creates a new Parameter with no associated name, title, or type.
|
||||
*/
|
||||
public Parameter() {
|
||||
this.options = new ArrayList<ParameterOption>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Parameter with the given name, title, and type.
|
||||
*
|
||||
* @param name
|
||||
* The unique name to associate with this parameter.
|
||||
*
|
||||
* @param title
|
||||
* The human-readable title to associate with this parameter.
|
||||
*
|
||||
* @param type
|
||||
* The type of this parameter.
|
||||
*/
|
||||
public Parameter(String name, String title, Type type) {
|
||||
this.name = name;
|
||||
this.title = title;
|
||||
this.type = type;
|
||||
this.options = new ArrayList<ParameterOption>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new BOOLEAN Parameter with the given name, title, and value.
|
||||
*
|
||||
* @param name
|
||||
* The unique name to associate with this parameter.
|
||||
*
|
||||
* @param title
|
||||
* The human-readable title to associate with this parameter.
|
||||
*
|
||||
* @param value
|
||||
* The value that should be assigned to this parameter if enabled.
|
||||
*/
|
||||
public Parameter(String name, String title, String value) {
|
||||
this.name = name;
|
||||
this.title = title;
|
||||
this.type = Type.BOOLEAN;
|
||||
this.value = value;
|
||||
this.options = new ArrayList<ParameterOption>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ENUM Parameter with the given name, title, and options.
|
||||
*
|
||||
* @param name
|
||||
* The unique name to associate with this parameter.
|
||||
*
|
||||
* @param title
|
||||
* The human-readable title to associate with this parameter.
|
||||
*
|
||||
* @param options
|
||||
* A collection of all possible valid options for this parameter.
|
||||
*/
|
||||
public Parameter(String name, String title, Collection<ParameterOption> options) {
|
||||
this.name = name;
|
||||
this.title = title;
|
||||
this.type = Type.ENUM;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique name associated with this parameter.
|
||||
*
|
||||
* @return
|
||||
* The unique name associated with this parameter.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unique name associated with this parameter.
|
||||
*
|
||||
* @param name
|
||||
* The unique name to assign to this parameter.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human-readable title associated with this parameter.
|
||||
*
|
||||
* @return
|
||||
* The human-readable title associated with this parameter.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title associated with this parameter. The title must be a
|
||||
* human-readable string which describes accurately this parameter.
|
||||
*
|
||||
* @param title
|
||||
* A human-readable string describing this parameter.
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that should be assigned to this parameter if enabled.
|
||||
* This is only applicable to BOOLEAN parameters.
|
||||
*
|
||||
* @return
|
||||
* The value that should be assigned to this parameter if enabled.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value that should be assigned to this parameter if enabled.
|
||||
* This is only applicable to BOOLEAN parameters.
|
||||
*
|
||||
* @param value
|
||||
* The value that should be assigned to this parameter if enabled.
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this parameter.
|
||||
*
|
||||
* @return
|
||||
* The type of this parameter.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of this parameter.
|
||||
*
|
||||
* @param type
|
||||
* The type of this parameter.
|
||||
*/
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable collection of parameter options. Changes to this
|
||||
* collection directly affect the available options. This is only
|
||||
* applicable to ENUM parameters.
|
||||
*
|
||||
* @return
|
||||
* A mutable collection of parameter options.
|
||||
*/
|
||||
public Collection<ParameterOption> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the options available as possible values of this parameter. This
|
||||
* is only applicable to ENUM parameters.
|
||||
*
|
||||
* @param options
|
||||
* The options to associate with this parameter.
|
||||
*/
|
||||
public void setOptions(Collection<ParameterOption> options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
}
|
@@ -20,18 +20,17 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.protocols;
|
||||
package org.glyptodon.guacamole.form;
|
||||
|
||||
/**
|
||||
* Describes an available legal value for an enumerated protocol parameter.
|
||||
* Describes an available legal value for an enumerated parameter.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class ProtocolParameterOption {
|
||||
public class ParameterOption {
|
||||
|
||||
/**
|
||||
* The value that will be sent to the client plugin if this option is
|
||||
* chosen.
|
||||
* The value that will be assigned if this option is chosen.
|
||||
*/
|
||||
private String value;
|
||||
|
||||
@@ -41,20 +40,40 @@ public class ProtocolParameterOption {
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* Returns the value that will be sent to the client plugin if this option
|
||||
* is chosen.
|
||||
* Creates a new ParameterOption with no associated value or title.
|
||||
*/
|
||||
public ParameterOption() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ParameterOption having the given value and title.
|
||||
*
|
||||
* @return The value that will be sent if this option is chosen.
|
||||
* @param value
|
||||
* The value to assign if this option is chosen.
|
||||
*
|
||||
* @param title
|
||||
* The human-readable title to associate with this option.
|
||||
*/
|
||||
public ParameterOption(String value, String title) {
|
||||
this.value = value;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that will be assigned if this option is chosen.
|
||||
*
|
||||
* @return
|
||||
* The value that will be assigned if this option is chosen.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value that will be sent to the client plugin if this option is
|
||||
* chosen.
|
||||
* Sets the value that will be assigned if this option is chosen.
|
||||
*
|
||||
* @param value The value to send if this option is chosen.
|
||||
* @param value
|
||||
* The value to assign if this option is chosen.
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
@@ -62,7 +81,9 @@ public class ProtocolParameterOption {
|
||||
|
||||
/**
|
||||
* Returns the human-readable title describing the effect of this option.
|
||||
* @return The human-readable title describing the effect of this option.
|
||||
*
|
||||
* @return
|
||||
* The human-readable title describing the effect of this option.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
@@ -70,7 +91,9 @@ public class ProtocolParameterOption {
|
||||
|
||||
/**
|
||||
* Sets the human-readable title describing the effect of this option.
|
||||
* @param title A human-readable title describing the effect of this option.
|
||||
*
|
||||
* @param title
|
||||
* A human-readable title describing the effect of this option.
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.auth.credentials;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import org.glyptodon.guacamole.form.Parameter;
|
||||
|
||||
/**
|
||||
* Information which describes a set of valid credentials.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class CredentialsInfo {
|
||||
|
||||
/**
|
||||
* All parameters required for valid credentials.
|
||||
*/
|
||||
private final Collection<Parameter> parameters;
|
||||
|
||||
/**
|
||||
* Creates a new CredentialsInfo object which requires the given parameters
|
||||
* for any conforming credentials.
|
||||
*
|
||||
* @param parameters
|
||||
* The parameters to require.
|
||||
*/
|
||||
public CredentialsInfo(Collection<Parameter> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all parameters required for valid credentials as described by
|
||||
* this object.
|
||||
*
|
||||
* @return
|
||||
* All parameters required for valid credentials.
|
||||
*/
|
||||
public Collection<Parameter> getParameters() {
|
||||
return Collections.unmodifiableCollection(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* CredentialsInfo object which describes empty credentials. No parameters
|
||||
* are required.
|
||||
*/
|
||||
public static final CredentialsInfo EMPTY = new CredentialsInfo(Collections.EMPTY_LIST);
|
||||
|
||||
/**
|
||||
* CredentialsInfo object which describes standard username/password
|
||||
* credentials.
|
||||
*/
|
||||
public static final CredentialsInfo USERNAME_PASSWORD = new CredentialsInfo(Arrays.asList(
|
||||
new Parameter("username", "username", Parameter.Type.USERNAME),
|
||||
new Parameter("password", "password", Parameter.Type.PASSWORD)
|
||||
));
|
||||
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.auth.credentials;
|
||||
|
||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||
|
||||
/**
|
||||
* A security-related exception thrown when access is denied to a user because
|
||||
* of a problem related to the provided credentials. Additional information
|
||||
* describing the form of valid credentials is provided.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class GuacamoleCredentialsException extends GuacamoleSecurityException {
|
||||
|
||||
/**
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
private final CredentialsInfo credentialsInfo;
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleInvalidCredentialsException with the given
|
||||
* message, cause, and associated credential information.
|
||||
*
|
||||
* @param message
|
||||
* A human readable description of the exception that occurred.
|
||||
*
|
||||
* @param cause
|
||||
* The cause of this exception.
|
||||
*
|
||||
* @param credentialsInfo
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public GuacamoleCredentialsException(String message, Throwable cause,
|
||||
CredentialsInfo credentialsInfo) {
|
||||
super(message, cause);
|
||||
this.credentialsInfo = credentialsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleInvalidCredentialsException with the given
|
||||
* message and associated credential information.
|
||||
*
|
||||
* @param message
|
||||
* A human readable description of the exception that occurred.
|
||||
*
|
||||
* @param credentialsInfo
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public GuacamoleCredentialsException(String message, CredentialsInfo credentialsInfo) {
|
||||
super(message);
|
||||
this.credentialsInfo = credentialsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleInvalidCredentialsException with the given cause
|
||||
* and associated credential information.
|
||||
*
|
||||
* @param cause
|
||||
* The cause of this exception.
|
||||
*
|
||||
* @param credentialsInfo
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public GuacamoleCredentialsException(Throwable cause, CredentialsInfo credentialsInfo) {
|
||||
super(cause);
|
||||
this.credentialsInfo = credentialsInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information describing the form of valid credentials.
|
||||
*
|
||||
* @return
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public CredentialsInfo getCredentialsInfo() {
|
||||
return credentialsInfo;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.auth.credentials;
|
||||
|
||||
/**
|
||||
* A security-related exception thrown when access is denied to a user because
|
||||
* the provided credentials are not sufficient for authentication to succeed.
|
||||
* The validity or invalidity of the given credentials is not specified, and
|
||||
* more information is needed before a decision can be made. Additional
|
||||
* information describing the form of valid credentials is provided.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class GuacamoleInsufficientCredentialsException extends GuacamoleCredentialsException {
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleInsufficientCredentialsException with the given
|
||||
* message, cause, and associated credential information.
|
||||
*
|
||||
* @param message
|
||||
* A human readable description of the exception that occurred.
|
||||
*
|
||||
* @param cause
|
||||
* The cause of this exception.
|
||||
*
|
||||
* @param credentialsInfo
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public GuacamoleInsufficientCredentialsException(String message, Throwable cause,
|
||||
CredentialsInfo credentialsInfo) {
|
||||
super(message, cause, credentialsInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleInsufficientCredentialsException with the given
|
||||
* message and associated credential information.
|
||||
*
|
||||
* @param message
|
||||
* A human readable description of the exception that occurred.
|
||||
*
|
||||
* @param credentialsInfo
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public GuacamoleInsufficientCredentialsException(String message, CredentialsInfo credentialsInfo) {
|
||||
super(message, credentialsInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleInsufficientCredentialsException with the given
|
||||
* cause and associated credential information.
|
||||
*
|
||||
* @param cause
|
||||
* The cause of this exception.
|
||||
*
|
||||
* @param credentialsInfo
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public GuacamoleInsufficientCredentialsException(Throwable cause, CredentialsInfo credentialsInfo) {
|
||||
super(cause, credentialsInfo);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.auth.credentials;
|
||||
|
||||
/**
|
||||
* A security-related exception thrown when access is denied to a user because
|
||||
* the provided credentials are invalid. Additional information describing
|
||||
* the form of valid credentials is provided.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class GuacamoleInvalidCredentialsException extends GuacamoleCredentialsException {
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleInvalidCredentialsException with the given
|
||||
* message, cause, and associated credential information.
|
||||
*
|
||||
* @param message
|
||||
* A human readable description of the exception that occurred.
|
||||
*
|
||||
* @param cause
|
||||
* The cause of this exception.
|
||||
*
|
||||
* @param credentialsInfo
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public GuacamoleInvalidCredentialsException(String message, Throwable cause,
|
||||
CredentialsInfo credentialsInfo) {
|
||||
super(message, cause, credentialsInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleInvalidCredentialsException with the given
|
||||
* message and associated credential information.
|
||||
*
|
||||
* @param message
|
||||
* A human readable description of the exception that occurred.
|
||||
*
|
||||
* @param credentialsInfo
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public GuacamoleInvalidCredentialsException(String message, CredentialsInfo credentialsInfo) {
|
||||
super(message, credentialsInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GuacamoleInvalidCredentialsException with the given cause
|
||||
* and associated credential information.
|
||||
*
|
||||
* @param cause
|
||||
* The cause of this exception.
|
||||
*
|
||||
* @param credentialsInfo
|
||||
* Information describing the form of valid credentials.
|
||||
*/
|
||||
public GuacamoleInvalidCredentialsException(Throwable cause, CredentialsInfo credentialsInfo) {
|
||||
super(cause, credentialsInfo);
|
||||
}
|
||||
|
||||
}
|
@@ -24,6 +24,7 @@ package org.glyptodon.guacamole.protocols;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import org.glyptodon.guacamole.form.Parameter;
|
||||
|
||||
/**
|
||||
* Describes a protocol and all parameters associated with it, as required by
|
||||
@@ -47,8 +48,49 @@ public class ProtocolInfo {
|
||||
/**
|
||||
* A collection of all associated protocol parameters.
|
||||
*/
|
||||
private Collection<ProtocolParameter> parameters =
|
||||
new ArrayList<ProtocolParameter>();
|
||||
private Collection<Parameter> parameters;
|
||||
|
||||
/**
|
||||
* Creates a new ProtocolInfo with no associated name, title, or
|
||||
* parameters.
|
||||
*/
|
||||
public ProtocolInfo() {
|
||||
this.parameters = new ArrayList<Parameter>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ProtocolInfo having the given name and title, but without
|
||||
* any parameters.
|
||||
*
|
||||
* @param name
|
||||
* The unique name associated with the protocol.
|
||||
*
|
||||
* @param title
|
||||
* The human-readable title to associate with the protocol.
|
||||
*/
|
||||
public ProtocolInfo(String name, String title) {
|
||||
this.name = name;
|
||||
this.title = title;
|
||||
this.parameters = new ArrayList<Parameter>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ProtocolInfo having the given name, title, and parameters.
|
||||
*
|
||||
* @param name
|
||||
* The unique name associated with the protocol.
|
||||
*
|
||||
* @param title
|
||||
* The human-readable title to associate with the protocol.
|
||||
*
|
||||
* @param parameters
|
||||
* The parameters to associate with the protocol.
|
||||
*/
|
||||
public ProtocolInfo(String name, String title, Collection<Parameter> parameters) {
|
||||
this.name = name;
|
||||
this.title = title;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human-readable title associated with this protocol.
|
||||
@@ -95,8 +137,19 @@ public class ProtocolInfo {
|
||||
*
|
||||
* @return A mutable collection of protocol parameters.
|
||||
*/
|
||||
public Collection<ProtocolParameter> getParameters() {
|
||||
public Collection<Parameter> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the collection of protocol parameters associated with this
|
||||
* protocol.
|
||||
*
|
||||
* @param parameters
|
||||
* The collection of parameters to associate with this protocol.
|
||||
*/
|
||||
public void setParameters(Collection<Parameter> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.protocols;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Represents a parameter of a protocol.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class ProtocolParameter {
|
||||
|
||||
/**
|
||||
* All possible types of protocol parameter.
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
* A text parameter, accepting arbitrary values.
|
||||
*/
|
||||
TEXT,
|
||||
|
||||
/**
|
||||
* A username parameter. This parameter type generally behaves
|
||||
* identically to arbitrary text parameters, but has semantic
|
||||
* differences. If credential pass-through is in use, the value for this
|
||||
* parameter may be automatically provided using the credentials
|
||||
* originally used by the user to authenticate.
|
||||
*/
|
||||
USERNAME,
|
||||
|
||||
/**
|
||||
* A password parameter, whose value is sensitive and must be hidden. If
|
||||
* credential pass-through is in use, the value for this parameter may
|
||||
* be automatically provided using the credentials originally used by
|
||||
* the user to authenticate.
|
||||
*/
|
||||
PASSWORD,
|
||||
|
||||
/**
|
||||
* A numeric parameter, whose value must contain only digits.
|
||||
*/
|
||||
NUMERIC,
|
||||
|
||||
/**
|
||||
* A boolean parameter, whose value is either blank or "true".
|
||||
*/
|
||||
BOOLEAN,
|
||||
|
||||
/**
|
||||
* An enumerated parameter, whose legal values are fully enumerated
|
||||
* by a provided, finite list.
|
||||
*/
|
||||
ENUM,
|
||||
|
||||
/**
|
||||
* A text parameter that can span more than one line.
|
||||
*/
|
||||
MULTILINE
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The unique name that identifies this parameter to the protocol plugin.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* A human-readable name to be presented to the user.
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* The type of this field.
|
||||
*/
|
||||
private Type type;
|
||||
|
||||
/**
|
||||
* The value of this parameter, for boolean parameters.
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* A collection of all associated parameter options.
|
||||
*/
|
||||
private Collection<ProtocolParameterOption> options =
|
||||
new ArrayList<ProtocolParameterOption>();
|
||||
|
||||
/**
|
||||
* Returns the name associated with this protocol parameter.
|
||||
* @return The name associated with this protocol parameter.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name associated with this protocol parameter. This name must
|
||||
* uniquely identify this parameter among the others accepted by the
|
||||
* corresponding protocol.
|
||||
*
|
||||
* @param name The name to assign to this protocol parameter.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title associated with this protocol parameter.
|
||||
* @return The title associated with this protocol parameter.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title associated with this protocol parameter. The title must
|
||||
* be a human-readable string which describes accurately this parameter.
|
||||
*
|
||||
* @param title A human-readable string describing this parameter.
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value associated with this protocol parameter.
|
||||
* @return The value associated with this protocol parameter.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value associated with this protocol parameter. The value must
|
||||
* be a human-readable string which describes accurately this parameter.
|
||||
*
|
||||
* @param value A human-readable string describing this parameter.
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this parameter.
|
||||
* @return The type of this parameter.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of this parameter.
|
||||
* @param type The type of this parameter.
|
||||
*/
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable collection of protocol parameter options. Changes to
|
||||
* this collection directly affect the available options.
|
||||
*
|
||||
* @return A mutable collection of parameter options.
|
||||
*/
|
||||
public Collection<ProtocolParameterOption> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
@@ -22,7 +22,7 @@
|
||||
|
||||
package org.glyptodon.guacamole.xml.protocol;
|
||||
|
||||
import org.glyptodon.guacamole.protocols.ProtocolParameterOption;
|
||||
import org.glyptodon.guacamole.form.ParameterOption;
|
||||
import org.glyptodon.guacamole.xml.TagHandler;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
@@ -37,7 +37,7 @@ public class OptionTagHandler implements TagHandler {
|
||||
/**
|
||||
* The option backing this option tag.
|
||||
*/
|
||||
private ProtocolParameterOption option = new ProtocolParameterOption();
|
||||
private ParameterOption option = new ParameterOption();
|
||||
|
||||
@Override
|
||||
public void init(Attributes attributes) throws SAXException {
|
||||
@@ -55,10 +55,10 @@ public class OptionTagHandler implements TagHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ProtocolParameterOption backing this tag.
|
||||
* @return The ProtocolParameterOption backing this tag.
|
||||
* Returns the ParameterOption backing this tag.
|
||||
* @return The ParameterOption backing this tag.
|
||||
*/
|
||||
public ProtocolParameterOption asProtocolParameterOption() {
|
||||
public ParameterOption asParameterOption() {
|
||||
return option;
|
||||
}
|
||||
|
||||
|
@@ -22,7 +22,7 @@
|
||||
|
||||
package org.glyptodon.guacamole.xml.protocol;
|
||||
|
||||
import org.glyptodon.guacamole.protocols.ProtocolParameter;
|
||||
import org.glyptodon.guacamole.form.Parameter;
|
||||
import org.glyptodon.guacamole.xml.TagHandler;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
@@ -35,9 +35,9 @@ import org.xml.sax.SAXException;
|
||||
public class ParamTagHandler implements TagHandler {
|
||||
|
||||
/**
|
||||
* The ProtocolParameter backing this tag handler.
|
||||
* The Parameter backing this tag handler.
|
||||
*/
|
||||
private ProtocolParameter protocolParameter = new ProtocolParameter();
|
||||
private Parameter protocolParameter = new Parameter();
|
||||
|
||||
@Override
|
||||
public void init(Attributes attributes) throws SAXException {
|
||||
@@ -51,31 +51,31 @@ public class ParamTagHandler implements TagHandler {
|
||||
|
||||
// Text field
|
||||
if ("text".equals(type))
|
||||
protocolParameter.setType(ProtocolParameter.Type.TEXT);
|
||||
protocolParameter.setType(Parameter.Type.TEXT);
|
||||
|
||||
// Numeric field
|
||||
else if ("numeric".equals(type))
|
||||
protocolParameter.setType(ProtocolParameter.Type.NUMERIC);
|
||||
protocolParameter.setType(Parameter.Type.NUMERIC);
|
||||
|
||||
// Username field
|
||||
else if ("username".equals(type))
|
||||
protocolParameter.setType(ProtocolParameter.Type.USERNAME);
|
||||
protocolParameter.setType(Parameter.Type.USERNAME);
|
||||
|
||||
// Password field
|
||||
else if ("password".equals(type))
|
||||
protocolParameter.setType(ProtocolParameter.Type.PASSWORD);
|
||||
protocolParameter.setType(Parameter.Type.PASSWORD);
|
||||
|
||||
// Enumerated field
|
||||
else if ("enum".equals(type))
|
||||
protocolParameter.setType(ProtocolParameter.Type.ENUM);
|
||||
protocolParameter.setType(Parameter.Type.ENUM);
|
||||
|
||||
// Multiline field
|
||||
else if ("multiline".equals(type))
|
||||
protocolParameter.setType(ProtocolParameter.Type.MULTILINE);
|
||||
protocolParameter.setType(Parameter.Type.MULTILINE);
|
||||
|
||||
// Boolean field
|
||||
else if ("boolean".equals(type)) {
|
||||
protocolParameter.setType(ProtocolParameter.Type.BOOLEAN);
|
||||
protocolParameter.setType(Parameter.Type.BOOLEAN);
|
||||
|
||||
if(protocolParameter.getValue() == null)
|
||||
throw new SAXException
|
||||
@@ -99,7 +99,7 @@ public class ParamTagHandler implements TagHandler {
|
||||
|
||||
// Store stub in options collection
|
||||
protocolParameter.getOptions().add(
|
||||
tagHandler.asProtocolParameterOption());
|
||||
tagHandler.asParameterOption());
|
||||
return tagHandler;
|
||||
|
||||
}
|
||||
@@ -114,10 +114,10 @@ public class ParamTagHandler implements TagHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ProtocolParameter backing this tag.
|
||||
* @return The ProtocolParameter backing this tag.
|
||||
* Returns the Parameter backing this tag.
|
||||
* @return The Parameter backing this tag.
|
||||
*/
|
||||
public ProtocolParameter asProtocolParameter() {
|
||||
public Parameter asParameter() {
|
||||
return protocolParameter;
|
||||
}
|
||||
|
||||
|
@@ -56,7 +56,7 @@ public class ProtocolTagHandler implements TagHandler {
|
||||
ParamTagHandler tagHandler = new ParamTagHandler();
|
||||
|
||||
// Store stub in parameters collection
|
||||
info.getParameters().add(tagHandler.asProtocolParameter());
|
||||
info.getParameters().add(tagHandler.asParameter());
|
||||
return tagHandler;
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
* Copyright (C) 2015 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -22,9 +22,15 @@
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.rest;
|
||||
|
||||
import java.util.Collection;
|
||||
import javax.ws.rs.core.Response;
|
||||
import org.glyptodon.guacamole.form.Parameter;
|
||||
|
||||
/**
|
||||
* A simple object to represent an error to be sent from the REST API.
|
||||
* Describes an error that occurred within a REST endpoint.
|
||||
*
|
||||
* @author James Muehlner
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class APIError {
|
||||
|
||||
@@ -34,19 +40,143 @@ public class APIError {
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* Get the error message.
|
||||
* @return The error message.
|
||||
* All expected request parameters, if any.
|
||||
*/
|
||||
private final Collection<Parameter> expected;
|
||||
|
||||
/**
|
||||
* The type of error that occurred.
|
||||
*/
|
||||
private final Type type;
|
||||
|
||||
/**
|
||||
* All possible types of REST API errors.
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
* The requested operation could not be performed because the request
|
||||
* itself was malformed.
|
||||
*/
|
||||
BAD_REQUEST(Response.Status.BAD_REQUEST),
|
||||
|
||||
/**
|
||||
* The credentials provided were invalid.
|
||||
*/
|
||||
INVALID_CREDENTIALS(Response.Status.FORBIDDEN),
|
||||
|
||||
/**
|
||||
* The credentials provided were not necessarily invalid, but were not
|
||||
* sufficient to determine validity.
|
||||
*/
|
||||
INSUFFICIENT_CREDENTIALS(Response.Status.FORBIDDEN),
|
||||
|
||||
/**
|
||||
* An internal server error has occurred.
|
||||
*/
|
||||
INTERNAL_ERROR(Response.Status.INTERNAL_SERVER_ERROR),
|
||||
|
||||
/**
|
||||
* An object related to the request does not exist.
|
||||
*/
|
||||
NOT_FOUND(Response.Status.NOT_FOUND),
|
||||
|
||||
/**
|
||||
* Permission was denied to perform the requested operation.
|
||||
*/
|
||||
PERMISSION_DENIED(Response.Status.FORBIDDEN);
|
||||
|
||||
/**
|
||||
* The HTTP status associated with this error type.
|
||||
*/
|
||||
private final Response.Status status;
|
||||
|
||||
/**
|
||||
* Defines a new error type associated with the given HTTP status.
|
||||
*
|
||||
* @param status
|
||||
* The HTTP status to associate with the error type.
|
||||
*/
|
||||
Type(Response.Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP status associated with this error type.
|
||||
*
|
||||
* @return
|
||||
* The HTTP status associated with this error type.
|
||||
*/
|
||||
public Response.Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new APIError with the specified error message.
|
||||
*
|
||||
* @param type
|
||||
* The type of error that occurred.
|
||||
*
|
||||
* @param message
|
||||
* The error message.
|
||||
*/
|
||||
public APIError(Type type, String message) {
|
||||
this.type = type;
|
||||
this.message = message;
|
||||
this.expected = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new APIError with the specified error message and parameter
|
||||
* information.
|
||||
*
|
||||
* @param type
|
||||
* The type of error that occurred.
|
||||
*
|
||||
* @param message
|
||||
* The error message.
|
||||
*
|
||||
* @param expected
|
||||
* All parameters expected in the original request, or now required as
|
||||
* a result of the original request.
|
||||
*/
|
||||
public APIError(Type type, String message, Collection<Parameter> expected) {
|
||||
this.type = type;
|
||||
this.message = message;
|
||||
this.expected = expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of error that occurred.
|
||||
*
|
||||
* @return
|
||||
* The type of error that occurred.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object which describes the required credentials.
|
||||
*
|
||||
* @return
|
||||
* An object which describes the required credentials.
|
||||
*/
|
||||
public Collection<Parameter> getExpected() {
|
||||
return expected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable error message describing the error that
|
||||
* occurred.
|
||||
*
|
||||
* @return
|
||||
* A human-readable error message.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new APIError with the specified error message.
|
||||
* @param message The error message.
|
||||
*/
|
||||
public APIError(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.rest;
|
||||
|
||||
import java.util.Collection;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import org.glyptodon.guacamole.form.Parameter;
|
||||
|
||||
/**
|
||||
* An exception that will result in the given error error information being
|
||||
* returned from the API layer. All error messages have the same format which
|
||||
* is defined by APIError.
|
||||
*
|
||||
* @author James Muehlner
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class APIException extends WebApplicationException {
|
||||
|
||||
/**
|
||||
* Construct a new APIException with the given error. All information
|
||||
* associated with this new exception will be extracted from the given
|
||||
* APIError.
|
||||
*
|
||||
* @param error
|
||||
* The error that occurred.
|
||||
*/
|
||||
public APIException(APIError error) {
|
||||
super(Response.status(error.getType().getStatus()).entity(error).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new APIException with the given type and message. The
|
||||
* corresponding APIError will be created from the provided information.
|
||||
*
|
||||
* @param type
|
||||
* The type of error that occurred.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the error.
|
||||
*/
|
||||
public APIException(APIError.Type type, String message) {
|
||||
this(new APIError(type, message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new APIException with the given type, message, and parameter
|
||||
* information. The corresponding APIError will be created from the
|
||||
* provided information.
|
||||
*
|
||||
* @param type
|
||||
* The type of error that occurred.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the error.
|
||||
*
|
||||
* @param expected
|
||||
* All parameters expected in the original request, or now required as
|
||||
* a result of the original request.
|
||||
*/
|
||||
public APIException(APIError.Type type, String message, Collection<Parameter> expected) {
|
||||
this(new APIError(type, message, expected));
|
||||
}
|
||||
|
||||
}
|
@@ -27,7 +27,11 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
|
||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -49,15 +53,96 @@ public class AuthProviderRESTExceptionWrapper implements MethodInterceptor {
|
||||
try {
|
||||
return invocation.proceed();
|
||||
}
|
||||
catch(GuacamoleSecurityException e) {
|
||||
throw new HTTPException(Response.Status.FORBIDDEN, e.getMessage() != null ? e.getMessage() : "Permission denied.");
|
||||
|
||||
// Additional credentials are needed
|
||||
catch (GuacamoleInsufficientCredentialsException e) {
|
||||
|
||||
// Generate default message
|
||||
String message = e.getMessage();
|
||||
if (message == null)
|
||||
message = "Permission denied.";
|
||||
|
||||
throw new APIException(
|
||||
APIError.Type.INSUFFICIENT_CREDENTIALS,
|
||||
message,
|
||||
e.getCredentialsInfo().getParameters()
|
||||
);
|
||||
}
|
||||
catch(GuacamoleClientException e) {
|
||||
throw new HTTPException(Response.Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
|
||||
|
||||
// The provided credentials are wrong
|
||||
catch (GuacamoleInvalidCredentialsException e) {
|
||||
|
||||
// Generate default message
|
||||
String message = e.getMessage();
|
||||
if (message == null)
|
||||
message = "Permission denied.";
|
||||
|
||||
throw new APIException(
|
||||
APIError.Type.INVALID_CREDENTIALS,
|
||||
message,
|
||||
e.getCredentialsInfo().getParameters()
|
||||
);
|
||||
}
|
||||
catch(GuacamoleException e) {
|
||||
logger.error("Unexpected GuacamoleException caught while executing " + invocation.getMethod().getName() + ".", e);
|
||||
throw new HTTPException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
|
||||
|
||||
// Generic permission denied
|
||||
catch (GuacamoleSecurityException e) {
|
||||
|
||||
// Generate default message
|
||||
String message = e.getMessage();
|
||||
if (message == null)
|
||||
message = "Permission denied.";
|
||||
|
||||
throw new APIException(
|
||||
APIError.Type.PERMISSION_DENIED,
|
||||
message
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Arbitrary resource not found
|
||||
catch (GuacamoleResourceNotFoundException e) {
|
||||
|
||||
// Generate default message
|
||||
String message = e.getMessage();
|
||||
if (message == null)
|
||||
message = "Not found.";
|
||||
|
||||
throw new APIException(
|
||||
APIError.Type.NOT_FOUND,
|
||||
message
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Arbitrary bad requests
|
||||
catch (GuacamoleClientException e) {
|
||||
|
||||
// Generate default message
|
||||
String message = e.getMessage();
|
||||
if (message == null)
|
||||
message = "Invalid request.";
|
||||
|
||||
throw new APIException(
|
||||
APIError.Type.BAD_REQUEST,
|
||||
message
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// All other errors
|
||||
catch (GuacamoleException e) {
|
||||
|
||||
// Generate default message
|
||||
String message = e.getMessage();
|
||||
if (message == null)
|
||||
message = "Unexpected server error.";
|
||||
|
||||
logger.debug("Unexpected exception in REST endpoint.", e);
|
||||
throw new APIException(
|
||||
APIError.Type.INTERNAL_ERROR,
|
||||
message
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.glyptodon.guacamole.net.basic.rest;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
/**
|
||||
* An exception that will result in the given HTTP Status and message or entity
|
||||
* being returned from the API layer.
|
||||
*
|
||||
* @author James Muehlner
|
||||
*/
|
||||
public class HTTPException extends WebApplicationException {
|
||||
|
||||
/**
|
||||
* Construct a new HTTPException with the given HTTP status and entity.
|
||||
*
|
||||
* @param status The HTTP Status to use for the response.
|
||||
* @param entity The entity to use as the body of the response.
|
||||
*/
|
||||
public HTTPException(Status status, Object entity) {
|
||||
super(Response.status(status).entity(entity).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new HTTPException with the given HTTP status and message. The
|
||||
* message will be wrapped in an APIError container.
|
||||
*
|
||||
* @param status The HTTP Status to use for the response.
|
||||
* @param message The message to build the response entity with.
|
||||
*/
|
||||
public HTTPException(Status status, String message) {
|
||||
super(Response.status(status).entity(new APIError(message)).build());
|
||||
}
|
||||
|
||||
}
|
@@ -35,16 +35,18 @@ import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||
import org.glyptodon.guacamole.net.basic.GuacamoleSession;
|
||||
import org.glyptodon.guacamole.net.basic.rest.APIError;
|
||||
import org.glyptodon.guacamole.net.basic.rest.APIRequest;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
|
||||
import org.glyptodon.guacamole.net.basic.rest.APIException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -233,15 +235,13 @@ public class TokenRESTService {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch(GuacamoleException e) {
|
||||
logger.error("Exception caught while authenticating user.", e);
|
||||
throw new HTTPException(Status.INTERNAL_SERVER_ERROR,
|
||||
"Unexpected server error.");
|
||||
}
|
||||
// Request standard username/password if no user context was produced
|
||||
if (userContext == null)
|
||||
throw new GuacamoleInvalidCredentialsException("Permission Denied.",
|
||||
CredentialsInfo.USERNAME_PASSWORD);
|
||||
|
||||
// Authentication failed.
|
||||
if (userContext == null) {
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
|
||||
// Log authentication failures with associated usernames
|
||||
if (username != null) {
|
||||
@@ -255,8 +255,7 @@ public class TokenRESTService {
|
||||
logger.debug("Anonymous authentication attempt from {} failed.",
|
||||
getLoggableAddress(request), username);
|
||||
|
||||
throw new HTTPException(Status.UNAUTHORIZED, "Permission Denied.");
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Update existing session, if it exists
|
||||
@@ -291,7 +290,7 @@ public class TokenRESTService {
|
||||
|
||||
GuacamoleSession session = tokenSessionMap.remove(authToken);
|
||||
if (session == null)
|
||||
throw new HTTPException(Status.NOT_FOUND, "No such token.");
|
||||
throw new APIException(APIError.Type.NOT_FOUND, "No such token.");
|
||||
|
||||
session.invalidate();
|
||||
|
||||
|
@@ -39,8 +39,6 @@ import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleResourceNotFoundException;
|
||||
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
||||
@@ -53,11 +51,12 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.glyptodon.guacamole.net.auth.permission.Permission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
||||
import org.glyptodon.guacamole.net.basic.rest.APIError;
|
||||
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.remove;
|
||||
import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure;
|
||||
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
|
||||
import org.glyptodon.guacamole.net.basic.rest.APIException;
|
||||
import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService;
|
||||
import org.glyptodon.guacamole.net.basic.rest.PATCH;
|
||||
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
|
||||
@@ -276,12 +275,12 @@ public class UserRESTService {
|
||||
|
||||
// Validate data and path are sane
|
||||
if (!user.getUsername().equals(username))
|
||||
throw new HTTPException(Response.Status.BAD_REQUEST,
|
||||
throw new APIException(APIError.Type.BAD_REQUEST,
|
||||
"Username in path does not match username provided JSON data.");
|
||||
|
||||
// A user may not use this endpoint to modify himself
|
||||
if (userContext.self().getIdentifier().equals(user.getUsername())) {
|
||||
throw new HTTPException(Response.Status.FORBIDDEN,
|
||||
throw new APIException(APIError.Type.PERMISSION_DENIED,
|
||||
"Permission denied.");
|
||||
}
|
||||
|
||||
@@ -336,7 +335,7 @@ public class UserRESTService {
|
||||
|
||||
// Verify that the old password was correct
|
||||
if (authProvider.getUserContext(credentials) == null) {
|
||||
throw new HTTPException(Response.Status.FORBIDDEN,
|
||||
throw new APIException(APIError.Type.PERMISSION_DENIED,
|
||||
"Permission denied.");
|
||||
}
|
||||
|
||||
@@ -467,7 +466,7 @@ public class UserRESTService {
|
||||
|
||||
// Unsupported patch operation
|
||||
default:
|
||||
throw new HTTPException(Status.BAD_REQUEST,
|
||||
throw new APIException(APIError.Type.BAD_REQUEST,
|
||||
"Unsupported patch operation: \"" + operation + "\"");
|
||||
|
||||
}
|
||||
@@ -586,7 +585,7 @@ public class UserRESTService {
|
||||
|
||||
// Otherwise, the path is not supported
|
||||
else
|
||||
throw new HTTPException(Status.BAD_REQUEST, "Unsupported patch path: \"" + path + "\"");
|
||||
throw new APIException(APIError.Type.BAD_REQUEST, "Unsupported patch path: \"" + path + "\"");
|
||||
|
||||
} // end for each patch operation
|
||||
|
||||
|
@@ -32,10 +32,20 @@
|
||||
* If a login attempt results in an existing token being replaced, 'guacLogout'
|
||||
* will be broadcast first for the token being replaced, followed by
|
||||
* 'guacLogin' for the new token.
|
||||
*
|
||||
* Failed logins may also result in guacInsufficientCredentials or
|
||||
* guacInvalidCredentials events, if the provided credentials were rejected for
|
||||
* being insufficient or invalid respectively. Both events will be provided
|
||||
* the set of parameters originally given to authenticate() and the set of
|
||||
* expected credentials returned by the REST endpoint. This set of credentials
|
||||
* will be in the form of a Field array.
|
||||
*/
|
||||
angular.module('auth').factory('authenticationService', ['$injector',
|
||||
function authenticationService($injector) {
|
||||
|
||||
// Required types
|
||||
var Error = $injector.get('Error');
|
||||
|
||||
// Required services
|
||||
var $cookieStore = $injector.get('$cookieStore');
|
||||
var $http = $injector.get('$http');
|
||||
@@ -140,7 +150,16 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
||||
})
|
||||
|
||||
// If authentication fails, propogate failure to returned promise
|
||||
.error(function authenticationFailed() {
|
||||
.error(function authenticationFailed(error) {
|
||||
|
||||
// Request credentials if provided credentials were invalid
|
||||
if (error.type === Error.Type.INVALID_CREDENTIALS)
|
||||
$rootScope.$broadcast('guacInvalidCredentials', parameters, error.expected);
|
||||
|
||||
// Request more credentials if provided credentials were not enough
|
||||
else if (error.type === Error.Type.INSUFFICIENT_CREDENTIALS)
|
||||
$rootScope.$broadcast('guacInsufficientCredentials', parameters, error.expected);
|
||||
|
||||
authenticationProcess.reject();
|
||||
});
|
||||
|
||||
|
@@ -113,34 +113,6 @@ angular.module('form').directive('guacForm', [function form() {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Produces the translation string for the header of the given
|
||||
* field. The translation string will be of the form:
|
||||
*
|
||||
* <code>NAMESPACE.FIELD_HEADER_NAME<code>
|
||||
*
|
||||
* where <code>NAMESPACE</code> is the namespace provided to the
|
||||
* directive and <code>NAME</code> is the field name transformed
|
||||
* via translationStringService.canonicalize().
|
||||
*
|
||||
* @param {Field} field
|
||||
* The field for which to produce the translation string.
|
||||
*
|
||||
* @returns {String}
|
||||
* The translation string which produces the translated header
|
||||
* of the field.
|
||||
*/
|
||||
$scope.getFieldHeader = function getFieldHeader(field) {
|
||||
|
||||
// If no field, or no name, then no header
|
||||
if (!field || !field.name)
|
||||
return '';
|
||||
|
||||
return translationStringService.canonicalize($scope.namespace || 'MISSING_NAMESPACE')
|
||||
+ '.FIELD_HEADER_' + translationStringService.canonicalize(field.name);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines whether the given object is a form, under the
|
||||
* assumption that the object is either a form or a field.
|
||||
|
@@ -110,6 +110,31 @@ angular.module('form').directive('guacFormField', [function formField() {
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Produces the translation string for the header of the current
|
||||
* field. The translation string will be of the form:
|
||||
*
|
||||
* <code>NAMESPACE.FIELD_HEADER_NAME<code>
|
||||
*
|
||||
* where <code>NAMESPACE</code> is the namespace provided to the
|
||||
* directive and <code>NAME</code> is the field name transformed
|
||||
* via translationStringService.canonicalize().
|
||||
*
|
||||
* @returns {String}
|
||||
* The translation string which produces the translated header
|
||||
* of the field.
|
||||
*/
|
||||
$scope.getFieldHeader = function getFieldHeader() {
|
||||
|
||||
// If no field, or no name, then no header
|
||||
if (!$scope.field || !$scope.field.name)
|
||||
return '';
|
||||
|
||||
return translationStringService.canonicalize($scope.namespace || 'MISSING_NAMESPACE')
|
||||
+ '.FIELD_HEADER_' + translationStringService.canonicalize($scope.field.name);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Produces the translation string for the given field option
|
||||
* value. The translation string will be of the form:
|
||||
|
@@ -25,13 +25,9 @@
|
||||
<h3 ng-show="form.name">{{getSectionHeader(form) | translate}}</h3>
|
||||
|
||||
<!-- All fields in form -->
|
||||
<table class="fields">
|
||||
<tr ng-repeat="field in form.fields">
|
||||
<th>{{getFieldHeader(field) | translate}}</th>
|
||||
<td>
|
||||
<guac-form-field namespace="namespace" field="field" model="values[field.name]"></guac-form-field>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="fields">
|
||||
<guac-form-field ng-repeat="field in form.fields" namespace="namespace"
|
||||
field="field" model="values[field.name]"></guac-form-field>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<div class="form-field">
|
||||
<label class="labeled-field" ng-class="{empty: !model}">
|
||||
<!--
|
||||
Copyright 2014 Glyptodon LLC.
|
||||
|
||||
@@ -21,7 +21,11 @@
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- Field header -->
|
||||
<span class="field-header">{{getFieldHeader() | translate}}</span>
|
||||
|
||||
<!-- Generic input types -->
|
||||
<div class="form-field">
|
||||
<input ng-show="field.type === 'TEXT'" type="text" ng-model="typedValue" autocorrect="off" autocapitalize="off"/>
|
||||
<input ng-show="field.type === 'NUMERIC'" type="number" ng-model="typedValue" autocorrect="off" autocapitalize="off"/>
|
||||
<input ng-show="field.type === 'USERNAME'" type="text" ng-model="typedValue" autocorrect="off" autocapitalize="off"/>
|
||||
@@ -38,5 +42,6 @@
|
||||
|
||||
<!-- Enumerated field -->
|
||||
<select ng-show="field.type === 'ENUM'" ng-model="typedValue" ng-options="option.value as getFieldOption(option.value) | translate for option in field.options | orderBy: value"></select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</label>
|
||||
|
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The config block for setting up the authentication interceptor.
|
||||
*/
|
||||
angular.module('index').config(['$httpProvider',
|
||||
function indexInterceptorConfig($httpProvider) {
|
||||
$httpProvider.interceptors.push('authenticationInterceptor');
|
||||
}]);
|
||||
|
||||
|
@@ -39,26 +39,17 @@ angular.module('index').config(['$routeProvider', '$locationProvider',
|
||||
*
|
||||
* @returns {Promise}
|
||||
* A promise which resolves successfully only after an attempt to
|
||||
* re-authenticate has been made.
|
||||
* re-authenticate has been made. If the authentication attempt fails,
|
||||
* the promise will be rejected.
|
||||
*/
|
||||
var updateCurrentToken = ['$injector', function updateCurrentToken($injector) {
|
||||
|
||||
// Required services
|
||||
var $location = $injector.get('$location');
|
||||
var $q = $injector.get('$q');
|
||||
var authenticationService = $injector.get('authenticationService');
|
||||
|
||||
// Promise for authentication attempt
|
||||
var authAttempt = $q.defer();
|
||||
|
||||
// Re-authenticate including any parameters in URL
|
||||
authenticationService.updateCurrentToken($location.search())
|
||||
['finally'](function authenticationAttemptComplete() {
|
||||
authAttempt.resolve();
|
||||
});
|
||||
|
||||
// Return promise that will resolve regardless of success/failure
|
||||
return authAttempt.promise;
|
||||
return authenticationService.updateCurrentToken($location.search());
|
||||
|
||||
}];
|
||||
|
||||
@@ -161,15 +152,6 @@ angular.module('index').config(['$routeProvider', '$locationProvider',
|
||||
resolve : { updateCurrentToken: updateCurrentToken }
|
||||
})
|
||||
|
||||
// Login screen
|
||||
.when('/login/', {
|
||||
title : 'APP.NAME',
|
||||
bodyClassName : 'login',
|
||||
templateUrl : 'app/login/templates/login.html',
|
||||
controller : 'loginController'
|
||||
// No need to update token here - the login screen ignores all auth
|
||||
})
|
||||
|
||||
// Client view
|
||||
.when('/client/:type/:id/:params?', {
|
||||
bodyClassName : 'client',
|
||||
|
@@ -36,6 +36,14 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
||||
*/
|
||||
$scope.guacNotification = guacNotification;
|
||||
|
||||
/**
|
||||
* The credentials that the authentication service is currently expecting,
|
||||
* if any. If the user is logged in, this will be null.
|
||||
*
|
||||
* @type Form[]|Form|Field[]|Field
|
||||
*/
|
||||
$scope.expectedCredentials = null;
|
||||
|
||||
/**
|
||||
* Basic page-level information.
|
||||
*/
|
||||
@@ -63,6 +71,10 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
||||
// Broadcast keydown events
|
||||
keyboard.onkeydown = function onkeydown(keysym) {
|
||||
|
||||
// Do not handle key events if not logged in
|
||||
if ($scope.expectedCredentials)
|
||||
return true;
|
||||
|
||||
// Warn of pending keydown
|
||||
var guacBeforeKeydownEvent = $scope.$broadcast('guacBeforeKeydown', keysym, keyboard);
|
||||
if (guacBeforeKeydownEvent.defaultPrevented)
|
||||
@@ -77,6 +89,10 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
||||
// Broadcast keyup events
|
||||
keyboard.onkeyup = function onkeyup(keysym) {
|
||||
|
||||
// Do not handle key events if not logged in
|
||||
if ($scope.expectedCredentials)
|
||||
return;
|
||||
|
||||
// Warn of pending keyup
|
||||
var guacBeforeKeydownEvent = $scope.$broadcast('guacBeforeKeyup', keysym, keyboard);
|
||||
if (guacBeforeKeydownEvent.defaultPrevented)
|
||||
@@ -92,6 +108,25 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
||||
keyboard.reset();
|
||||
};
|
||||
|
||||
// Display login screen if a whole new set of credentials is needed
|
||||
$scope.$on('guacInvalidCredentials', function loginInvalid(event, parameters, expected) {
|
||||
$scope.page.title = 'APP.NAME';
|
||||
$scope.page.bodyClassName = '';
|
||||
$scope.expectedCredentials = expected;
|
||||
});
|
||||
|
||||
// Prompt for remaining credentials if provided credentials were not enough
|
||||
$scope.$on('guacInsufficientCredentials', function loginInsufficient(event, parameters, expected) {
|
||||
$scope.page.title = 'APP.NAME';
|
||||
$scope.page.bodyClassName = '';
|
||||
$scope.expectedCredentials = expected;
|
||||
});
|
||||
|
||||
// Clear login screen if login was successful
|
||||
$scope.$on('guacLogin', function loginSuccessful() {
|
||||
$scope.expectedCredentials = null;
|
||||
});
|
||||
|
||||
// Update title and CSS class upon navigation
|
||||
$scope.$on('$routeChangeSuccess', function(event, current, previous) {
|
||||
|
||||
|
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
angular.module('index').factory('authenticationInterceptor', ['$location', '$q',
|
||||
function authenticationInterceptor($location, $q) {
|
||||
|
||||
return {
|
||||
|
||||
// Redirect users to login if authorization fails
|
||||
responseError: function handleErrorResponse(rejection) {
|
||||
|
||||
// Only redirect failed authentication requests
|
||||
if ((rejection.status === 401 || rejection.status === 403)
|
||||
&& rejection.config.url === 'api/tokens') {
|
||||
|
||||
// Only redirect if not already on login page
|
||||
if ($location.path() !== '/login/')
|
||||
$location.path('/login/');
|
||||
|
||||
}
|
||||
|
||||
return $q.reject(rejection);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}]);
|
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
angular.module('login').controller('loginController', ['$scope', '$injector',
|
||||
function loginController($scope, $injector) {
|
||||
|
||||
// Required services
|
||||
var $location = $injector.get('$location');
|
||||
var authenticationService = $injector.get('authenticationService');
|
||||
var userPageService = $injector.get('userPageService');
|
||||
|
||||
/**
|
||||
* Whether an error occurred during login.
|
||||
*
|
||||
* @type Boolean
|
||||
*/
|
||||
$scope.loginError = false;
|
||||
|
||||
/**
|
||||
* Whether the password field has focus.
|
||||
*
|
||||
* @type Boolean
|
||||
*/
|
||||
$scope.passwordFocused = false;
|
||||
|
||||
/**
|
||||
* Submits the currently-specified username and password to the
|
||||
* authentication service, redirecting to the main view if successful.
|
||||
*/
|
||||
$scope.login = function login() {
|
||||
|
||||
// Attempt login once existing session is destroyed
|
||||
authenticationService.login($scope.username, $scope.password)
|
||||
|
||||
// Redirect to main view upon success
|
||||
.then(function loginSuccessful() {
|
||||
userPageService.getHomePage()
|
||||
.then(function homePageRetrieved(homePage) {
|
||||
$location.url(homePage.url);
|
||||
});
|
||||
})
|
||||
|
||||
// Reset and focus password upon failure
|
||||
['catch'](function loginFailed() {
|
||||
$scope.loginError = true;
|
||||
$scope.passwordFocused = true;
|
||||
$scope.password = '';
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
}]);
|
96
guacamole/src/main/webapp/app/login/directives/login.js
Normal file
96
guacamole/src/main/webapp/app/login/directives/login.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Glyptodon LLC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A directive for displaying an arbitrary login form.
|
||||
*/
|
||||
angular.module('login').directive('guacLogin', [function guacLogin() {
|
||||
|
||||
// Login directive
|
||||
var directive = {
|
||||
restrict : 'E',
|
||||
replace : true,
|
||||
templateUrl : 'app/login/templates/login.html'
|
||||
};
|
||||
|
||||
// Login directive scope
|
||||
directive.scope = {
|
||||
|
||||
/**
|
||||
* The login form or set of fields. This will be displayed to the user
|
||||
* to capture their credentials.
|
||||
*
|
||||
* @type Form[]|Form|Field[]|Field
|
||||
*/
|
||||
form : '='
|
||||
|
||||
};
|
||||
|
||||
// Controller for login directive
|
||||
directive.controller = ['$scope', '$injector',
|
||||
function loginController($scope, $injector) {
|
||||
|
||||
// Required services
|
||||
var $route = $injector.get('$route');
|
||||
var authenticationService = $injector.get('authenticationService');
|
||||
|
||||
/**
|
||||
* Whether an error occurred during login.
|
||||
*
|
||||
* @type Boolean
|
||||
*/
|
||||
$scope.loginError = false;
|
||||
|
||||
/**
|
||||
* All form values entered by the user.
|
||||
*/
|
||||
$scope.values = {};
|
||||
|
||||
/**
|
||||
* Submits the currently-specified username and password to the
|
||||
* authentication service, redirecting to the main view if successful.
|
||||
*/
|
||||
$scope.login = function login() {
|
||||
|
||||
// Attempt login once existing session is destroyed
|
||||
authenticationService.authenticate($scope.values)
|
||||
|
||||
// Clear and reload upon success
|
||||
.then(function loginSuccessful() {
|
||||
$scope.loginError = false;
|
||||
$scope.values = {};
|
||||
$route.reload();
|
||||
})
|
||||
|
||||
// Reset upon failure
|
||||
['catch'](function loginFailed() {
|
||||
$scope.loginError = true;
|
||||
$scope.values.password = '';
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
}];
|
||||
|
||||
return directive;
|
||||
|
||||
}]);
|
@@ -23,4 +23,8 @@
|
||||
/**
|
||||
* The module for the login functionality.
|
||||
*/
|
||||
angular.module('login', ['element', 'navigation']);
|
||||
angular.module('login', [
|
||||
'element',
|
||||
'form',
|
||||
'navigation'
|
||||
]);
|
||||
|
@@ -27,6 +27,8 @@ div.login-ui {
|
||||
left: 0;
|
||||
top: 0;
|
||||
display: table;
|
||||
background: white;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
p.login-error {
|
||||
@@ -52,3 +54,35 @@ p.login-error {
|
||||
text-align: center;
|
||||
color: #964040;
|
||||
}
|
||||
|
||||
.login-fields .form-field .password-field .toggle-password {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.login-fields .labeled-field {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.login-fields .labeled-field .field-header {
|
||||
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: hidden;
|
||||
|
||||
z-index: -1;
|
||||
margin: 0.5em;
|
||||
font-size: 0.9em;
|
||||
opacity: 0.5;
|
||||
|
||||
}
|
||||
|
||||
.login-fields .labeled-field.empty input {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.login-fields .labeled-field input:focus {
|
||||
background: white;
|
||||
}
|
||||
|
@@ -1,26 +1,25 @@
|
||||
<!--
|
||||
Copyright 2014 Glyptodon LLC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<div class="login-ui" ng-class="{error: loginError}" >
|
||||
<!--
|
||||
Copyright 2014 Glyptodon LLC.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- Login error message -->
|
||||
<p class="login-error">{{'LOGIN.ERROR_INVALID_LOGIN' | translate}}</p>
|
||||
@@ -35,10 +34,9 @@ THE SOFTWARE.
|
||||
<img class="logo" src="images/guac-tricolor.png" alt=""/>
|
||||
<div class="version">{{'APP.NAME' | translate}}</div>
|
||||
|
||||
<!-- Login fields (username + password) -->
|
||||
<!-- Login fields -->
|
||||
<div class="login-fields">
|
||||
<input ng-model="username" placeholder="{{'LOGIN.FIELD_PLACEHOLDER_USERNAME' | translate}}" type="text" name="username" autofocus="autofocus" autocorrect="off" autocapitalize="off" class="username"/>
|
||||
<input ng-model="password" placeholder="{{'LOGIN.FIELD_PLACEHOLDER_PASSWORD' | translate}}" type="password" name="password" class="password" guac-focus="passwordFocused"/>
|
||||
<guac-form namespace="'LOGIN'" content="form" model="values"></guac-form>
|
||||
</div>
|
||||
|
||||
<!-- Submit button -->
|
||||
|
@@ -26,3 +26,18 @@
|
||||
.connection-parameters input[type=number] {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.connection-parameters .form .fields {
|
||||
display: table;
|
||||
}
|
||||
|
||||
.connection-parameters .form .fields .labeled-field {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
.connection-parameters .form .fields .field-header,
|
||||
.connection-parameters .form .fields .form-field {
|
||||
display: table-cell;
|
||||
padding: 0.125em;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
@@ -48,6 +48,7 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu()
|
||||
// Get required services
|
||||
var $document = $injector.get('$document');
|
||||
var $location = $injector.get('$location');
|
||||
var $route = $injector.get('$route');
|
||||
var authenticationService = $injector.get('authenticationService');
|
||||
var userPageService = $injector.get('userPageService');
|
||||
|
||||
@@ -100,12 +101,15 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu()
|
||||
};
|
||||
|
||||
/**
|
||||
* Logs out the current user, redirecting them to back to the login
|
||||
* screen after logout completes.
|
||||
* Logs out the current user, redirecting them to back to the root
|
||||
* after logout completes.
|
||||
*/
|
||||
$scope.logout = function logout() {
|
||||
authenticationService.logout()['finally'](function logoutComplete() {
|
||||
$location.path('/login/');
|
||||
if ($location.path() !== '/')
|
||||
$location.url('/');
|
||||
else
|
||||
$route.reload();
|
||||
});
|
||||
};
|
||||
|
||||
|
122
guacamole/src/main/webapp/app/rest/types/Error.js
Normal file
122
guacamole/src/main/webapp/app/rest/types/Error.js
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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 defines the Error class.
|
||||
*/
|
||||
angular.module('rest').factory('Error', [function defineError() {
|
||||
|
||||
/**
|
||||
* The object returned by REST API calls when an error occurs.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Error|Object} [template={}]
|
||||
* The object whose properties should be copied within the new
|
||||
* Error.
|
||||
*/
|
||||
var Error = function Error(template) {
|
||||
|
||||
// Use empty object by default
|
||||
template = template || {};
|
||||
|
||||
/**
|
||||
* A human-readable message describing the error that occurred.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
this.message = template.message;
|
||||
|
||||
/**
|
||||
* The type string defining which values this parameter may contain,
|
||||
* as well as what properties are applicable. Valid types are listed
|
||||
* within Error.Type.
|
||||
*
|
||||
* @type String
|
||||
* @default Error.Type.INTERNAL_ERROR
|
||||
*/
|
||||
this.type = template.type || Error.Type.INTERNAL_ERROR;
|
||||
|
||||
/**
|
||||
* Any parameters which were expected in the original request, or are
|
||||
* now expected as a result of the original request, if any. If no
|
||||
* such information is available, this will be null.
|
||||
*
|
||||
* @type Field[]
|
||||
*/
|
||||
this.expected = template.expected;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* All valid field types.
|
||||
*/
|
||||
Error.Type = {
|
||||
|
||||
/**
|
||||
* The requested operation could not be performed because the request
|
||||
* itself was malformed.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
BAD_REQUEST : 'BAD_REQUEST',
|
||||
|
||||
/**
|
||||
* The credentials provided were invalid.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
INVALID_CREDENTIALS : 'INVALID_CREDENTIALS',
|
||||
|
||||
/**
|
||||
* The credentials provided were not necessarily invalid, but were not
|
||||
* sufficient to determine validity.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
INSUFFICIENT_CREDENTIALS : 'INSUFFICIENT_CREDENTIALS',
|
||||
|
||||
/**
|
||||
* An internal server error has occurred.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
INTERNAL_ERROR : 'INTERNAL_ERROR',
|
||||
|
||||
/**
|
||||
* An object related to the request does not exist.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
NOT_FOUND : 'NOT_FOUND',
|
||||
|
||||
/**
|
||||
* Permission was denied to perform the requested operation.
|
||||
*
|
||||
* @type String
|
||||
*/
|
||||
PERMISSION_DENIED : 'PERMISSION_DENIED'
|
||||
|
||||
};
|
||||
|
||||
return Error;
|
||||
|
||||
}]);
|
@@ -34,6 +34,9 @@ THE SOFTWARE.
|
||||
</head>
|
||||
<body ng-class="page.bodyClassName">
|
||||
|
||||
<!-- Content for logged-in users -->
|
||||
<div ng-if="!expectedCredentials">
|
||||
|
||||
<!-- Global status/error dialog -->
|
||||
<div ng-class="{shown: guacNotification.status}" class="status-outer">
|
||||
<div class="status-middle">
|
||||
@@ -51,6 +54,11 @@ THE SOFTWARE.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Login screen for logged-out users -->
|
||||
<guac-login ng-show="expectedCredentials" form="expectedCredentials"></guac-login>
|
||||
|
||||
<script type="text/javascript" src="guacamole.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
@@ -145,8 +145,8 @@
|
||||
|
||||
"ERROR_INVALID_LOGIN" : "Invalid Login",
|
||||
|
||||
"FIELD_PLACEHOLDER_USERNAME" : "Username",
|
||||
"FIELD_PLACEHOLDER_PASSWORD" : "Password"
|
||||
"FIELD_HEADER_USERNAME" : "Username",
|
||||
"FIELD_HEADER_PASSWORD" : "Password"
|
||||
|
||||
},
|
||||
|
||||
|
Reference in New Issue
Block a user