diff --git a/doc/guacamole-example/pom.xml b/doc/guacamole-example/pom.xml index ec12bfbbb..e4a4f1c12 100644 --- a/doc/guacamole-example/pom.xml +++ b/doc/guacamole-example/pom.xml @@ -26,7 +26,7 @@ org.apache.guacamole guacamole-example war - 1.5.5 + 1.6.0 guacamole-example http://guacamole.apache.org/ @@ -106,7 +106,7 @@ org.apache.guacamole guacamole-common - 1.5.5 + 1.6.0 compile @@ -114,7 +114,7 @@ org.apache.guacamole guacamole-common-js - 1.5.5 + 1.6.0 zip runtime diff --git a/doc/guacamole-playback-example/pom.xml b/doc/guacamole-playback-example/pom.xml index 90d455bc2..8563e078c 100644 --- a/doc/guacamole-playback-example/pom.xml +++ b/doc/guacamole-playback-example/pom.xml @@ -26,7 +26,7 @@ org.apache.guacamole guacamole-playback-example war - 1.5.5 + 1.6.0 guacamole-playback-example http://guacamole.apache.org/ @@ -88,7 +88,7 @@ org.apache.guacamole guacamole-common-js - 1.5.5 + 1.6.0 zip runtime diff --git a/extensions/guacamole-auth-ban/pom.xml b/extensions/guacamole-auth-ban/pom.xml index 8b7e90f4e..a9e8dfe3d 100644 --- a/extensions/guacamole-auth-ban/pom.xml +++ b/extensions/guacamole-auth-ban/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-ban jar - 1.5.5 + 1.6.0 guacamole-auth-ban http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -51,7 +51,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided + + com.github.seancfoley + ipaddress + 5.5.0 + provided + + diff --git a/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/UserVerificationService.java b/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/UserVerificationService.java index 2333e21ef..d2a6fa74d 100644 --- a/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/UserVerificationService.java +++ b/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/UserVerificationService.java @@ -23,10 +23,13 @@ import com.duosecurity.Client; import com.duosecurity.exception.DuoException; import com.duosecurity.model.Token; import com.google.inject.Inject; +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; import java.net.URI; import java.net.URISyntaxException; import java.util.Collections; import java.util.concurrent.TimeUnit; +import java.util.List; import javax.servlet.http.HttpServletRequest; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; @@ -37,6 +40,7 @@ import org.apache.guacamole.language.TranslatableMessage; import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.credentials.CredentialsInfo; +import org.apache.guacamole.properties.IPAddressListProperty; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -107,9 +111,41 @@ public class UserVerificationService { public void verifyAuthenticatedUser(AuthenticatedUser authenticatedUser) throws GuacamoleException { - // Ignore anonymous users (unverifiable) + // Pull the original HTTP request used to authenticate + Credentials credentials = authenticatedUser.getCredentials(); + HttpServletRequest request = credentials.getRequest(); + IPAddress clientAddr = new IPAddressString(request.getRemoteAddr()).getAddress(); + + // Ignore anonymous users String username = authenticatedUser.getIdentifier(); - if (username.equals(AuthenticatedUser.ANONYMOUS_IDENTIFIER)) + if (username == null || username.equals(AuthenticatedUser.ANONYMOUS_IDENTIFIER)) + return; + + // Pull address lists to check from configuration. Note that the enforce + // list will override the bypass list, which means that, if the client + // address happens to be in both lists, Duo MFA will be enforced. + List bypassAddresses = confService.getBypassHosts(); + List enforceAddresses = confService.getEnforceHosts(); + + // Check if the bypass list contains the client address, and set the + // enforce flag to the opposite. + boolean enforceHost = !(IPAddressListProperty.addressListContains(bypassAddresses, clientAddr)); + + // Only continue processing if the list is not empty + if (!enforceAddresses.isEmpty()) { + + // If client address is not available or invalid, MFA will + // be enforced. + if (clientAddr == null || !clientAddr.isIPAddress()) + enforceHost = true; + + // Check the enforce list for the client address and set enforcement flag. + else + enforceHost = IPAddressListProperty.addressListContains(enforceAddresses, clientAddr); + } + + // If the enforce flag is not true, bypass Duo MFA. + if (!enforceHost) return; // Obtain a Duo client for redirecting the user to the Duo service and @@ -137,11 +173,6 @@ public class UserVerificationService { + "not currently available (failed health check).", e); } - // Pull the original HTTP request used to authenticate, as well as any - // associated credentials - Credentials credentials = authenticatedUser.getCredentials(); - HttpServletRequest request = credentials.getRequest(); - // Retrieve signed Duo authentication code and session state from the // request (these will be absent if this is an initial authentication // attempt and not a redirect back from Duo) diff --git a/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/conf/ConfigurationService.java b/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/conf/ConfigurationService.java index 5ed7d7a21..43a2d98ed 100644 --- a/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/conf/ConfigurationService.java @@ -20,10 +20,14 @@ package org.apache.guacamole.auth.duo.conf; import com.google.inject.Inject; +import inet.ipaddr.IPAddress; import java.net.URI; +import java.util.Collections; +import java.util.List; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.properties.IntegerGuacamoleProperty; +import org.apache.guacamole.properties.IPAddressListProperty; import org.apache.guacamole.properties.StringGuacamoleProperty; import org.apache.guacamole.properties.URIGuacamoleProperty; @@ -105,6 +109,40 @@ public class ConfigurationService { public String getName() { return "duo-auth-timeout"; } }; + + /** + * The optional property that contains a comma-separated list of IP addresses + * or CIDRs for which the MFA requirement should be bypassed. If the Duo + * extension is installed, any/all users authenticating from clients that + * match this list will be able to successfully log in without fulfilling + * the MFA requirement. If this option is omitted or is empty, and the + * Duo module is installed, all users from all hosts will have Duo MFA + * enforced. + */ + private static final IPAddressListProperty DUO_BYPASS_HOSTS = + new IPAddressListProperty() { + + @Override + public String getName() { return "duo-bypass-hosts"; } + + }; + + /** + * The optional property that contains a comma-separated list of IP addresses + * or CIDRs for which the MFA requirement should be explicitly enforced. If + * the Duo module is enabled and this property is specified, users that log + * in from hosts that match the items in this list will have Duo MFA required, + * and all users from hosts that do not match this list will be able to log + * in without the MFA requirement. If this option is missing or empty and + * the Duo module is installed, MFA will be enforced for all users. + */ + private static final IPAddressListProperty DUO_ENFORCE_HOSTS = + new IPAddressListProperty() { + + @Override + public String getName() { return "duo-enforce-hosts"; } + + }; /** * Returns the hostname of the Duo API endpoint to be used to verify user @@ -188,5 +226,43 @@ public class ConfigurationService { public int getAuthenticationTimeout() throws GuacamoleException { return environment.getProperty(DUO_AUTH_TIMEOUT, 5); } + + /** + * Returns the list of IP addresses and subnets defined in guacamole.properties + * for which Duo MFA should _not_ be enforced. Users logging in from hosts + * contained in this list will be logged in without the MFA requirement. + * + * @return + * A list of IP addresses and subnets for which Duo MFA should not be + * enforced. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed, or if an invalid IP address + * or subnet is specified. + */ + public List getBypassHosts() throws GuacamoleException { + return environment.getProperty(DUO_BYPASS_HOSTS, Collections.emptyList()); + } + + /** + * Returns the list of IP addresses and subnets defined in guacamole.properties + * for which Duo MFA should explicitly be enforced, while logins from all + * other hosts should not enforce MFA. Users logging in from hosts + * contained in this list will be required to complete the Duo MFA authentication, + * while users from all other hosts will be logged in without the MFA requirement. + * + * @return + * A list of IP addresses and subnets for which Duo MFA should be + * explicitly enforced. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed, or if an invalid IP address + * or subnet is specified. + */ + public List getEnforceHosts() throws GuacamoleException { + return environment.getProperty(DUO_ENFORCE_HOSTS, Collections.emptyList()); + } + + } diff --git a/extensions/guacamole-auth-duo/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-duo/src/main/resources/guac-manifest.json index 2a9d727a9..5c305ed97 100644 --- a/extensions/guacamole-auth-duo/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-duo/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "Duo TFA Authentication Backend", "namespace" : "duo", diff --git a/extensions/guacamole-auth-header/pom.xml b/extensions/guacamole-auth-header/pom.xml index b28a535bb..017ea64a5 100644 --- a/extensions/guacamole-auth-header/pom.xml +++ b/extensions/guacamole-auth-header/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-header jar - 1.5.5 + 1.6.0 guacamole-auth-header http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -43,7 +43,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided diff --git a/extensions/guacamole-auth-header/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-header/src/main/resources/guac-manifest.json index 39a2bac43..49015dec9 100644 --- a/extensions/guacamole-auth-header/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-header/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "HTTP Header Authentication Extension", "namespace" : "header", diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml index ae0eacce1..956feacb8 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml @@ -32,7 +32,7 @@ org.apache.guacamole guacamole-auth-jdbc - 1.5.5 + 1.6.0 ../../ diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java index f7c1203f5..31f4df49c 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java @@ -483,8 +483,8 @@ public class ConnectionService extends ModeledChildDirectoryObjectService searchResults; - // Bypass permission checks if the user is privileged - if (user.isPrivileged()) + // Bypass permission checks if the user is privileged or has System-level audit permissions + if (user.isPrivileged() || user.getUser().getEffectivePermissions().getSystemPermissions().hasPermission(SystemPermission.Type.AUDIT)) searchResults = connectionRecordMapper.search(identifier, recordIdentifier, requiredContents, sortPredicates, limit); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java index 8c16363a6..d9323f4b4 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java @@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.tunnel; import com.google.inject.Inject; import com.google.inject.Provider; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -81,6 +82,56 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS */ private final Logger logger = LoggerFactory.getLogger(AbstractGuacamoleTunnelService.class); + /** + * The prefix that will be used to generate JDBC tokens. + */ + private final String JDBC_TOKEN_PREFIX = "JDBC_"; + + /** + * The token that contains the date the connection was started. + */ + private final String JDBC_DATE_TOKEN = JDBC_TOKEN_PREFIX + "STARTDATE"; + + /** + * The format of the date in the date token. + */ + private final String JDBC_DATE_TOKEN_FORMAT = "yyyyMMdd"; + + /** + * The token that contains the start time of the connection. + */ + private final String JDBC_TIME_TOKEN = JDBC_TOKEN_PREFIX + "STARTTIME"; + + /** + * The format of the time in the time token. + */ + private final String JDBC_TIME_TOKEN_FORMAT = "HHmmss"; + + /** + * The token that contains the connection name. + */ + private final String JDBC_CONNECTION_NAME_TOKEN = JDBC_TOKEN_PREFIX + "CONNECTION_NAME"; + + /** + * The token that contains the connection identifier. + */ + private final String JDBC_CONNECTION_ID_TOKEN = JDBC_TOKEN_PREFIX + "CONNECTION_ID"; + + /** + * The token that contains the hostname configured in the connection parameters. + */ + private final String JDBC_CONNECTION_HOSTNAME_TOKEN = JDBC_TOKEN_PREFIX + "HOSTNAME"; + + /** + * The name of the parameter containing the hostname in the configuration. + */ + private final String JDBC_CONNECTION_HOSTNAME_TOKEN_PARAMETER = "hostname"; + + /** + * The token containing the protocol configured in the connection. + */ + private final String JDBC_CONNECTION_PROTOCOL_TOKEN = JDBC_TOKEN_PREFIX + "PROTOCOL"; + /** * Mapper for accessing connections. */ @@ -121,7 +172,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS * All active connections through the tunnel having a given UUID. */ private final Map activeTunnels = - new ConcurrentHashMap(); + new ConcurrentHashMap<>(); /** * All active connections to a connection having a given identifier. @@ -415,7 +466,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS private GuacamoleTunnel assignGuacamoleTunnel(ActiveConnectionRecord activeConnection, GuacamoleClientInformation info, Map tokens, boolean interceptErrors) throws GuacamoleException { - + // Record new active connection Runnable cleanupTask = new ConnectionCleanupTask(activeConnection); try { @@ -459,9 +510,25 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS config = getGuacamoleConfiguration(connection, connectionID, activeConnection.getSharingProfile()); } - - // Include history record UUID as token + + // Make a copy of the tokens tokens = new HashMap<>(tokens); + + // Set up JDBC-specific tokens + tokens.put(JDBC_DATE_TOKEN, + new SimpleDateFormat(JDBC_DATE_TOKEN_FORMAT) + .format(activeConnection.getStartDate())); + tokens.put(JDBC_TIME_TOKEN, + new SimpleDateFormat(JDBC_TIME_TOKEN_FORMAT) + .format(activeConnection.getStartDate())); + tokens.put(JDBC_CONNECTION_NAME_TOKEN, activeConnection.getConnectionName()); + tokens.put(JDBC_CONNECTION_ID_TOKEN, activeConnection.getConnectionIdentifier()); + tokens.put(JDBC_CONNECTION_HOSTNAME_TOKEN, + activeConnection.getConnection().getConfiguration().getParameter(JDBC_CONNECTION_HOSTNAME_TOKEN_PARAMETER)); + tokens.put(JDBC_CONNECTION_PROTOCOL_TOKEN, + activeConnection.getConnection().getConfiguration().getProtocol()); + + // Include history record UUID as token tokens.put("HISTORY_UUID", activeConnection.getUUID().toString()); // Build token filter containing credential tokens diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java index 161976ce4..08acff2a6 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java @@ -611,8 +611,8 @@ public class UserService extends ModeledDirectoryObjectService searchResults; - // Bypass permission checks if the user is privileged - if (user.isPrivileged()) + // Bypass permission checks if the user is privileged or has System-level audit permissions + if (user.isPrivileged() || user.getUser().getEffectivePermissions().getSystemPermissions().hasPermission(SystemPermission.Type.AUDIT)) searchResults = userRecordMapper.search(username, recordIdentifier, requiredContents, sortPredicates, limit); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-dist/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-dist/pom.xml index 9d04a8f7c..93a4e752f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-dist/pom.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-dist/pom.xml @@ -32,7 +32,7 @@ org.apache.guacamole guacamole-auth-jdbc - 1.5.5 + 1.6.0 ../../ @@ -42,21 +42,21 @@ org.apache.guacamole guacamole-auth-jdbc-mysql - 1.5.5 + 1.6.0 org.apache.guacamole guacamole-auth-jdbc-postgresql - 1.5.5 + 1.6.0 org.apache.guacamole guacamole-auth-jdbc-sqlserver - 1.5.5 + 1.6.0 diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml index 1cb7e20c9..0818ac3c2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/pom.xml @@ -32,7 +32,7 @@ org.apache.guacamole guacamole-auth-jdbc - 1.5.5 + 1.6.0 ../../ @@ -49,7 +49,7 @@ org.apache.guacamole guacamole-auth-jdbc-base - 1.5.5 + 1.6.0 diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql index 1606af1f3..8241961f4 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql @@ -459,6 +459,7 @@ CREATE TABLE `guacamole_system_permission` ( 'CREATE_SHARING_PROFILE', 'CREATE_USER', 'CREATE_USER_GROUP', + 'AUDIT', 'ADMINISTER') NOT NULL, PRIMARY KEY (`entity_id`,`permission`), @@ -611,3 +612,4 @@ CREATE TABLE guacamole_user_password_history ( REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql index f62d6d1d2..2b7cc0250 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql @@ -51,3 +51,4 @@ FROM ( JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER' JOIN guacamole_entity affected ON permissions.affected_username = affected.name AND guacamole_entity.type = 'USER' JOIN guacamole_user ON guacamole_user.entity_id = affected.entity_id; + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.6.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.6.0.sql new file mode 100644 index 000000000..3533e48e5 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.6.0.sql @@ -0,0 +1,32 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +-- +-- Add new system-level permission +-- + +ALTER TABLE `guacamole_system_permission` + MODIFY `permission` enum('CREATE_CONNECTION', + 'CREATE_CONNECTION_GROUP', + 'CREATE_SHARING_PROFILE', + 'CREATE_USER', + 'CREATE_USER_GROUP', + 'AUDIT', + 'ADMINISTER') NOT NULL; + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json index 6711a36df..1cd1ddfeb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "MySQL Authentication", "namespace" : "mysql", diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml index 986e4ac0b..5d3129bd4 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml @@ -32,7 +32,7 @@ org.apache.guacamole guacamole-auth-jdbc - 1.5.5 + 1.6.0 ../../ @@ -49,7 +49,7 @@ org.apache.guacamole guacamole-auth-jdbc-base - 1.5.5 + 1.6.0 diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql index 9bcf1c51f..134215d29 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql @@ -56,6 +56,7 @@ CREATE TYPE guacamole_system_permission_type AS ENUM( 'CREATE_SHARING_PROFILE', 'CREATE_USER', 'CREATE_USER_GROUP', + 'AUDIT', 'ADMINISTER' ); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql index c7cd7c910..3a58771f1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql @@ -53,3 +53,4 @@ FROM ( JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER' JOIN guacamole_entity affected ON permissions.affected_username = affected.name AND guacamole_entity.type = 'USER' JOIN guacamole_user ON guacamole_user.entity_id = affected.entity_id; + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.6.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.6.0.sql new file mode 100644 index 000000000..9a4536e25 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.6.0.sql @@ -0,0 +1,27 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +-- +-- Add new system-level audit permission +-- + +ALTER TYPE guacamole_system_permission_type + ADD VALUE 'AUDIT' + BEFORE 'ADMINISTER'; + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json index 5fe5ec183..0f7d160fc 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "PostgreSQL Authentication", "namespace" : "postgresql", diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/pom.xml index aab232d39..8ceee87df 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/pom.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/pom.xml @@ -32,7 +32,7 @@ org.apache.guacamole guacamole-auth-jdbc - 1.5.5 + 1.6.0 ../../ @@ -49,7 +49,7 @@ org.apache.guacamole guacamole-auth-jdbc-base - 1.5.5 + 1.6.0 diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql index 54be792ba..44346538b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql @@ -77,6 +77,7 @@ CREATE RULE [guacamole_system_permission_list] AS @list IN ( 'CREATE_SHARING_PROFILE', 'CREATE_USER', 'CREATE_USER_GROUP', + 'AUDIT', 'ADMINISTER' ); GO diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql index dcb4257d6..70cf520a1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql @@ -61,3 +61,4 @@ JOIN [guacamole_entity] ON [permissions].[username] = [guacamole_enti JOIN [guacamole_entity] [affected] ON [permissions].[affected_username] = [affected].[name] AND [guacamole_entity].[type] = 'USER' JOIN [guacamole_user] ON [guacamole_user].[entity_id] = [affected].[entity_id]; GO + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.6.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.6.0.sql new file mode 100644 index 000000000..e56f7ee12 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.6.0.sql @@ -0,0 +1,43 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- + +-- +-- Add new system-level audit permission +-- + +EXEC sp_unbindrule 'guacamole_system_permission'; +DROP RULE [guacamole_system_permission_list]; +GO + +CREATE RULE [guacamole_system_permission_list] AS @list IN ( + 'CREATE_CONNECTION', + 'CREATE_CONNECTION_GROUP', + 'CREATE_SHARING_PROFILE', + 'CREATE_USER', + 'CREATE_USER_GROUP', + 'AUDIT', + 'ADMINISTER' +); +GO + +EXEC sp_bindrule + 'guacamole_system_permission_list', + 'guacamole_system_permission'; +GO + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/guac-manifest.json index eded5ff3f..8ee7ac176 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "SQLServer Authentication", "namespace" : "sqlserver", diff --git a/extensions/guacamole-auth-jdbc/pom.xml b/extensions/guacamole-auth-jdbc/pom.xml index 126df3cc4..e9ac71f58 100644 --- a/extensions/guacamole-auth-jdbc/pom.xml +++ b/extensions/guacamole-auth-jdbc/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-jdbc pom - 1.5.5 + 1.6.0 guacamole-auth-jdbc http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -59,7 +59,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided diff --git a/extensions/guacamole-auth-json/pom.xml b/extensions/guacamole-auth-json/pom.xml index a986b627f..5fc38b011 100644 --- a/extensions/guacamole-auth-json/pom.xml +++ b/extensions/guacamole-auth-json/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-json jar - 1.5.5 + 1.6.0 guacamole-auth-json http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -43,7 +43,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided @@ -78,6 +78,7 @@ com.github.seancfoley ipaddress 5.5.0 + provided diff --git a/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/ConfigurationService.java b/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/ConfigurationService.java index 1483f6fcb..2705e61ed 100644 --- a/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/ConfigurationService.java +++ b/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/ConfigurationService.java @@ -25,7 +25,7 @@ import java.util.Collections; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.properties.ByteArrayProperty; -import org.apache.guacamole.properties.StringListProperty; +import org.apache.guacamole.properties.StringGuacamoleProperty; /** * Service for retrieving configuration information regarding the JSON @@ -56,7 +56,7 @@ public class ConfigurationService { * be allowed to perform authentication. If not specified, ALL address will * be allowed. */ - private static final StringListProperty JSON_TRUSTED_NETWORKS = new StringListProperty() { + private static final StringGuacamoleProperty JSON_TRUSTED_NETWORKS = new StringGuacamoleProperty() { @Override public String getName() { @@ -95,7 +95,7 @@ public class ConfigurationService { * If guacamole.properties cannot be parsed. */ public Collection getTrustedNetworks() throws GuacamoleException { - return environment.getProperty(JSON_TRUSTED_NETWORKS, Collections.emptyList()); + return environment.getPropertyCollection(JSON_TRUSTED_NETWORKS, Collections.emptyList()); } } diff --git a/extensions/guacamole-auth-json/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-json/src/main/resources/guac-manifest.json index cd5d61709..7d8efd5c7 100644 --- a/extensions/guacamole-auth-json/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-json/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "Encrypted JSON Authentication", "namespace" : "json", diff --git a/extensions/guacamole-auth-ldap/pom.xml b/extensions/guacamole-auth-ldap/pom.xml index 8cb4209f1..05be82421 100644 --- a/extensions/guacamole-auth-ldap/pom.xml +++ b/extensions/guacamole-auth-ldap/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-ldap jar - 1.5.5 + 1.6.0 guacamole-auth-ldap http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -43,7 +43,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided diff --git a/extensions/guacamole-auth-ldap/schema/guacConfigGroup.ldif b/extensions/guacamole-auth-ldap/schema/guacConfigGroup.ldif index 6e3f60b25..36622e280 100644 --- a/extensions/guacamole-auth-ldap/schema/guacConfigGroup.ldif +++ b/extensions/guacamole-auth-ldap/schema/guacConfigGroup.ldif @@ -20,9 +20,24 @@ dn: cn=guacConfigGroup,cn=schema,cn=config objectClass: olcSchemaConfig cn: guacConfigGroup -olcAttributeTypes: {0}( 1.3.6.1.4.1.38971.1.1.1 NAME 'guacConfigProtocol' SYNTAX 1.3.6.1.4.1.1466 - .115.121.1.15 ) -olcAttributeTypes: {1}( 1.3.6.1.4.1.38971.1.1.2 NAME 'guacConfigParameter' SYNTAX 1.3.6.1.4.1.146 - 6.115.121.1.15 ) -olcObjectClasses: {0}( 1.3.6.1.4.1.38971.1.2.1 NAME 'guacConfigGroup' DESC 'Guacamole config - uration group' SUP groupOfNames MUST guacConfigProtocol MAY guacConfigParameter ) + +olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.1 NAME 'guacConfigProtocol' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.2 NAME 'guacConfigParameter' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.3 NAME 'guacConfigProxyHostname' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.4 NAME 'guacConfigProxyPort' + SINGLE-VALUE + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) +olcAttributeTypes: ( 1.3.6.1.4.1.38971.1.1.5 NAME 'guacConfigProxyEncryption' + SINGLE-VALUE + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +olcObjectClasses: ( 1.3.6.1.4.1.38971.1.2.1 NAME 'guacConfigGroup' + DESC 'Guacamole configuration group' + SUP groupOfNames + MUST guacConfigProtocol + MAY ( guacConfigParameter $ + guacConfigProxyHostname $ + guacConfigProxyPort $ + guacConfigProxyEncryption ) ) diff --git a/extensions/guacamole-auth-ldap/schema/guacConfigGroup.schema b/extensions/guacamole-auth-ldap/schema/guacConfigGroup.schema index 129a41b77..fb7ec433e 100644 --- a/extensions/guacamole-auth-ldap/schema/guacConfigGroup.schema +++ b/extensions/guacamole-auth-ldap/schema/guacConfigGroup.schema @@ -18,14 +18,28 @@ # attributetype ( 1.3.6.1.4.1.38971.1.1.1 NAME 'guacConfigProtocol' - SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) attributetype ( 1.3.6.1.4.1.38971.1.1.2 NAME 'guacConfigParameter' - SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + +attributetype ( 1.3.6.1.4.1.38971.1.1.3 NAME 'guacConfigProxyHostname' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + +attributetype ( 1.3.6.1.4.1.38971.1.1.4 NAME 'guacConfigProxyPort' + SINGLE-VALUE + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +attributetype ( 1.3.6.1.4.1.38971.1.1.5 NAME 'guacConfigProxyEncryption' + SINGLE-VALUE + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) objectClass ( 1.3.6.1.4.1.38971.1.2.1 NAME 'guacConfigGroup' DESC 'Guacamole configuration group' SUP groupOfNames MUST guacConfigProtocol - MAY guacConfigParameter ) + MAY ( guacConfigParameter $ + guacConfigProxyHostname $ + guacConfigProxyPort $ + guacConfigProxyEncryption ) ) diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java index 66adb49e9..33b811e88 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java @@ -401,7 +401,7 @@ public class AuthenticationProviderService { throws GuacamoleException { // Get attributes from configuration information - List attrList = config.getAttributes(); + Collection attrList = config.getAttributes(); // If there are no attributes there is no reason to search LDAP if (attrList.isEmpty()) diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java index 493cafcb7..c41114c02 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java @@ -19,6 +19,7 @@ package org.apache.guacamole.auth.ldap; +import java.util.Collection; import java.util.List; import org.apache.directory.api.ldap.model.filter.ExprNode; import org.apache.directory.api.ldap.model.message.AliasDerefMode; @@ -124,7 +125,7 @@ public class ConnectedLDAPConfiguration implements LDAPConfiguration, AutoClosea } @Override - public List getUsernameAttributes() throws GuacamoleException { + public Collection getUsernameAttributes() throws GuacamoleException { return config.getUsernameAttributes(); } @@ -139,7 +140,7 @@ public class ConnectedLDAPConfiguration implements LDAPConfiguration, AutoClosea } @Override - public List getGroupNameAttributes() throws GuacamoleException { + public Collection getGroupNameAttributes() throws GuacamoleException { return config.getGroupNameAttributes(); } @@ -209,7 +210,7 @@ public class ConnectedLDAPConfiguration implements LDAPConfiguration, AutoClosea } @Override - public List getAttributes() throws GuacamoleException { + public Collection getAttributes() throws GuacamoleException { return config.getAttributes(); } diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/EnvironmentLDAPConfiguration.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/EnvironmentLDAPConfiguration.java index 9fb44a1fa..5ffeb203b 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/EnvironmentLDAPConfiguration.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/EnvironmentLDAPConfiguration.java @@ -19,7 +19,7 @@ package org.apache.guacamole.auth.ldap.conf; -import java.util.List; +import java.util.Collection; import org.apache.directory.api.ldap.model.filter.ExprNode; import org.apache.directory.api.ldap.model.message.AliasDerefMode; import org.apache.directory.api.ldap.model.name.Dn; @@ -75,8 +75,8 @@ public class EnvironmentLDAPConfiguration implements LDAPConfiguration { } @Override - public List getUsernameAttributes() throws GuacamoleException { - return environment.getProperty( + public Collection getUsernameAttributes() throws GuacamoleException { + return environment.getPropertyCollection( LDAPGuacamoleProperties.LDAP_USERNAME_ATTRIBUTE, DEFAULT.getUsernameAttributes() ); @@ -98,8 +98,8 @@ public class EnvironmentLDAPConfiguration implements LDAPConfiguration { } @Override - public List getGroupNameAttributes() throws GuacamoleException { - return environment.getProperty( + public Collection getGroupNameAttributes() throws GuacamoleException { + return environment.getPropertyCollection( LDAPGuacamoleProperties.LDAP_GROUP_NAME_ATTRIBUTE, DEFAULT.getGroupNameAttributes() ); @@ -210,8 +210,8 @@ public class EnvironmentLDAPConfiguration implements LDAPConfiguration { } @Override - public List getAttributes() throws GuacamoleException { - return environment.getProperty( + public Collection getAttributes() throws GuacamoleException { + return environment.getPropertyCollection( LDAPGuacamoleProperties.LDAP_USER_ATTRIBUTES, DEFAULT.getAttributes() ); diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/JacksonLDAPConfiguration.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/JacksonLDAPConfiguration.java index 01d58a3e4..bddccd871 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/JacksonLDAPConfiguration.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/JacksonLDAPConfiguration.java @@ -22,6 +22,7 @@ package org.apache.guacamole.auth.ldap.conf; import com.fasterxml.jackson.annotation.JsonFormat; import static com.fasterxml.jackson.annotation.JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Collection; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -331,7 +332,7 @@ public class JacksonLDAPConfiguration implements LDAPConfiguration { } @Override - public List getUsernameAttributes() throws GuacamoleException { + public Collection getUsernameAttributes() throws GuacamoleException { return withDefault(usernameAttributes, defaultConfig::getUsernameAttributes); } @@ -348,7 +349,7 @@ public class JacksonLDAPConfiguration implements LDAPConfiguration { } @Override - public List getGroupNameAttributes() throws GuacamoleException { + public Collection getGroupNameAttributes() throws GuacamoleException { return withDefault(groupNameAttributes, defaultConfig::getGroupNameAttributes); } @@ -424,7 +425,7 @@ public class JacksonLDAPConfiguration implements LDAPConfiguration { } @Override - public List getAttributes() throws GuacamoleException { + public Collection getAttributes() throws GuacamoleException { return withDefault(userAttributes, defaultConfig::getAttributes); } diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPConfiguration.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPConfiguration.java index 975631d02..e57049b26 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPConfiguration.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPConfiguration.java @@ -19,6 +19,7 @@ package org.apache.guacamole.auth.ldap.conf; +import java.util.Collection; import java.util.List; import org.apache.directory.api.ldap.model.filter.ExprNode; import org.apache.directory.api.ldap.model.message.AliasDerefMode; @@ -84,7 +85,7 @@ public interface LDAPConfiguration { * @throws GuacamoleException * If the username attributes cannot be retrieved. */ - List getUsernameAttributes() throws GuacamoleException; + Collection getUsernameAttributes() throws GuacamoleException; /** * Returns the base DN under which all Guacamole users will be stored @@ -125,7 +126,7 @@ public interface LDAPConfiguration { * @throws GuacamoleException * If the group name attributes cannot be retrieved. */ - List getGroupNameAttributes() throws GuacamoleException; + Collection getGroupNameAttributes() throws GuacamoleException; /** * Returns the base DN under which all Guacamole role based access control @@ -305,7 +306,7 @@ public interface LDAPConfiguration { * If the names of the LDAP user attributes to be exposed as parameter * tokens cannot be retrieved. */ - List getAttributes() throws GuacamoleException; + Collection getAttributes() throws GuacamoleException; /** * Returns the name of the LDAP attribute used to enumerate members in a diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPGuacamoleProperties.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPGuacamoleProperties.java index cd0b724c0..7349356b9 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPGuacamoleProperties.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/LDAPGuacamoleProperties.java @@ -84,8 +84,8 @@ public class LDAPGuacamoleProperties { * one attribute, and the concatenation of that attribute and the value of * LDAP_USER_BASE_DN must equal the user's full DN. */ - public static final StringListProperty LDAP_USERNAME_ATTRIBUTE = - new StringListProperty() { + public static final StringGuacamoleProperty LDAP_USERNAME_ATTRIBUTE = + new StringGuacamoleProperty() { @Override public String getName() { return "ldap-username-attribute"; } @@ -97,8 +97,8 @@ public class LDAPGuacamoleProperties { * attributes must be present within each Guacamole user group's record in * the LDAP directory for that group to be visible. */ - public static final StringListProperty LDAP_GROUP_NAME_ATTRIBUTE = - new StringListProperty() { + public static final StringGuacamoleProperty LDAP_GROUP_NAME_ATTRIBUTE = + new StringGuacamoleProperty() { @Override public String getName() { return "ldap-group-name-attribute"; } @@ -277,8 +277,8 @@ public class LDAPGuacamoleProperties { * Custom attribute or attributes to query from Guacamole user's record in * the LDAP directory. */ - public static final StringListProperty LDAP_USER_ATTRIBUTES = - new StringListProperty() { + public static final StringGuacamoleProperty LDAP_USER_ATTRIBUTES = + new StringGuacamoleProperty() { @Override public String getName() { return "ldap-user-attributes"; } diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/StringListProperty.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/StringListProperty.java deleted file mode 100644 index f7057e9f6..000000000 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/StringListProperty.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.guacamole.auth.ldap.conf; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; -import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.properties.GuacamoleProperty; - -/** - * A GuacamoleProperty whose value is a List of Strings. The string value - * parsed to produce this list is a comma-delimited list. Duplicate values are - * ignored, as is any whitespace following delimiters. To maintain - * compatibility with the behavior of Java properties in general, only - * whitespace at the beginning of each value is ignored; trailing whitespace - * becomes part of the value. - */ -public abstract class StringListProperty implements GuacamoleProperty> { - - /** - * A pattern which matches against the delimiters between values. This is - * currently simply a comma and any following whitespace. Parts of the - * input string which match this pattern will not be included in the parsed - * result. - */ - private static final Pattern DELIMITER_PATTERN = Pattern.compile(",\\s*"); - - @Override - public List parseValue(String values) throws GuacamoleException { - - // If no property provided, return null. - if (values == null) - return null; - - // Split string into a list of individual values - List stringValues = Arrays.asList(DELIMITER_PATTERN.split(values)); - if (stringValues.isEmpty()) - return null; - - return stringValues; - - } - -} diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java index 9da1547ba..629b10131 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java @@ -42,7 +42,11 @@ import org.apache.guacamole.auth.ldap.ConnectedLDAPConfiguration; import org.apache.guacamole.auth.ldap.ObjectQueryService; import org.apache.guacamole.auth.ldap.group.UserGroupService; import org.apache.guacamole.auth.ldap.user.LDAPAuthenticatedUser; +import org.apache.guacamole.environment.LocalEnvironment; +import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Connection; +import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; +import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration.EncryptionMethod; import org.apache.guacamole.net.auth.TokenInjectingConnection; import org.apache.guacamole.net.auth.simple.SimpleConnection; import org.apache.guacamole.protocol.GuacamoleConfiguration; @@ -59,6 +63,33 @@ public class ConnectionService { * Logger for this class. */ private static final Logger logger = LoggerFactory.getLogger(ConnectionService.class); + + /** + * The name of the LDAP attribute that stores connection configuration + * parameters for Guacamole. + */ + public static final String LDAP_ATTRIBUTE_PARAMETER = "guacConfigParameter"; + + /** + * The name of the LDAP attribute that stores the protocol for a Guacamole + * connection. + */ + public static final String LDAP_ATTRIBUTE_PROTOCOL = "guacConfigProtocol"; + + /** + * The name of the LDAP attribute that stores guacd proxy hostname. + */ + public static final String LDAP_ATTRIBUTE_PROXY_HOSTNAME = "guacConfigProxyHostname"; + + /** + * The name of the LDAP attribute that stores guacd proxy port. + */ + public static final String LDAP_ATTRIBUTE_PROXY_PORT = "guacConfigProxyPort"; + + /** + * The name of the LDAP attribute that stores guacd proxy hostname. + */ + public static final String LDAP_ATTRIBUTE_PROXY_ENCRYPTION = "guacConfigProxyEncryption"; /** * Service for executing LDAP queries. @@ -192,11 +223,21 @@ public class ConnectionService { config.setProtocol(protocol.getString()); } catch (LdapInvalidAttributeValueException e) { - logger.error("Invalid value of the protocol entry: {}", - e.getMessage()); + logger.error("Invalid value of the protocol entry: {}", e.getMessage()); logger.debug("LDAP exception when getting protocol value.", e); return null; } + + // Get proxy configuration, if any + GuacamoleProxyConfiguration proxyConfig; + try { + proxyConfig = getProxyConfiguration(entry); + } + catch (GuacamoleException e) { + logger.error("Failed to retrieve proxy configuration.", e.getMessage()); + logger.debug("Guacamole Exception when retrieving proxy configuration.", e); + return null; + } // Get parameters, if any Attribute parameterAttribute = entry.get(LDAP_ATTRIBUTE_NAME_PARAMETER); @@ -209,10 +250,8 @@ public class ConnectionService { parameter = parameterAttribute.getString(); } catch (LdapInvalidAttributeValueException e) { - logger.warn("Parameter value not valid for {}: {}", - cnName, e.getMessage()); - logger.debug("LDAP exception when getting parameter value.", - e); + logger.warn("Parameter value not valid for {}: {}", cnName, e.getMessage()); + logger.debug("LDAP exception when getting parameter value.", e); return null; } parameterAttribute.remove(parameter); @@ -234,7 +273,7 @@ public class ConnectionService { } // Store connection using cn for both identifier and name - Connection connection = new SimpleConnection(cnName, cnName, config, true); + Connection connection = new SimpleConnection(cnName, cnName, proxyConfig, config, true); connection.setParentIdentifier(LDAPAuthenticationProvider.ROOT_CONNECTION_GROUP); // Inject LDAP-specific tokens only if LDAP handled user @@ -301,5 +340,64 @@ public class ConnectionService { return searchFilter; } + + /** + * Given an LDAP entry that stores a GuacamoleConfiguration, generate a + * GuacamoleProxyConfiguration that tells the client how to connect to guacd. + * If the proxy configuration values are not found in the LDAP entry the + * defaults from the environment are used. If errors occur while trying to + * ready or parse values from the LDAP entry a GuacamoleException is thrown. + * + * @param connectionEntry + * The LDAP entry that should be checked for proxy configuration values. + * + * @return + * The GuacamoleProxyConfiguration that contains information on how + * to contact guacd for the given Guacamole connection configuration. + * + * @throws GuacamoleException + * If errors occur trying to parse LDAP values from the entry. + */ + private GuacamoleProxyConfiguration getProxyConfiguration(Entry connectionEntry) + throws GuacamoleException { + + try { + + // Get default proxy configuration values + GuacamoleProxyConfiguration proxyConfig = LocalEnvironment.getInstance().getDefaultGuacamoleProxyConfiguration(); + String proxyHostname = proxyConfig.getHostname(); + int proxyPort = proxyConfig.getPort(); + EncryptionMethod proxyEncryption = proxyConfig.getEncryptionMethod(); + + // Get the proxy hostname + Attribute proxyHostAttr = connectionEntry.get(LDAP_ATTRIBUTE_PROXY_HOSTNAME); + if (proxyHostAttr != null && proxyHostAttr.size() > 0) + proxyHostname = proxyHostAttr.getString(); + + // Get the proxy port + Attribute proxyPortAttr = connectionEntry.get(LDAP_ATTRIBUTE_PROXY_PORT); + if (proxyPortAttr != null && proxyPortAttr.size() > 0) + proxyPort = Integer.parseInt(proxyPortAttr.getString()); + + // Get the proxy encryption method + Attribute proxyEncryptionAttr = connectionEntry.get(LDAP_ATTRIBUTE_PROXY_ENCRYPTION); + if (proxyEncryptionAttr != null && proxyEncryptionAttr.size() > 0) { + try { + proxyEncryption = EncryptionMethod.valueOf(proxyEncryptionAttr.getString()); + } + catch (IllegalArgumentException e) { + throw new GuacamoleServerException("Unknown encryption method specified, value must be either \"NONE\" or \"SSL\".", e); + } + } + + // Return a new proxy configuration + return new GuacamoleProxyConfiguration(proxyHostname, proxyPort, proxyEncryption); + } + catch (LdapInvalidAttributeValueException e) { + logger.error("Invalid value in proxy configuration: {}", e.getMessage()); + logger.debug("LDAP exception fetching proxy attribute value.", e); + throw new GuacamoleServerException("Invalid LDAP value in proxy configuration.", e); + } + } } diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserService.java index fa9fe1522..38fa33e7e 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserService.java @@ -183,7 +183,7 @@ public class UserService { throws GuacamoleException { // Pull username attributes from properties - List usernameAttributes = config.getUsernameAttributes(); + List usernameAttributes = new ArrayList<>(config.getUsernameAttributes()); // We need exactly one base DN to derive the user DN if (usernameAttributes.size() != 1) { diff --git a/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json index d0c02721a..dc812d399 100644 --- a/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "LDAP Authentication", "namespace" : "ldap", diff --git a/extensions/guacamole-auth-quickconnect/pom.xml b/extensions/guacamole-auth-quickconnect/pom.xml index e72776f72..28e62310a 100644 --- a/extensions/guacamole-auth-quickconnect/pom.xml +++ b/extensions/guacamole-auth-quickconnect/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-quickconnect jar - 1.5.5 + 1.6.0 guacamole-auth-quickconnect http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -98,7 +98,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/conf/ConfigurationService.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/conf/ConfigurationService.java index 11f11f3f8..e8e8fd34d 100644 --- a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/conf/ConfigurationService.java @@ -20,10 +20,11 @@ package org.apache.guacamole.auth.quickconnect.conf; import com.google.inject.Inject; +import java.util.Collection; import java.util.List; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.environment.Environment; -import org.apache.guacamole.properties.StringListProperty; +import org.apache.guacamole.properties.StringGuacamoleProperty; /** * Configuration options to control the QuickConnect module. @@ -42,7 +43,7 @@ public class ConfigurationService { * the parameters defined in this list. Defaults to null (all parameters * are allowed). */ - public static final StringListProperty QUICKCONNECT_ALLOWED_PARAMETERS = new StringListProperty() { + public static final StringGuacamoleProperty QUICKCONNECT_ALLOWED_PARAMETERS = new StringGuacamoleProperty() { @Override public String getName() { return "quickconnect-allowed-parameters"; } @@ -55,7 +56,7 @@ public class ConfigurationService { * except the ones defined in this list. Defaults to null (all parameters * are allowed). */ - public static final StringListProperty QUICKCONNECT_DENIED_PARAMETERS = new StringListProperty() { + public static final StringGuacamoleProperty QUICKCONNECT_DENIED_PARAMETERS = new StringGuacamoleProperty() { @Override public String getName() { return "quickconnect-denied-parameters"; } @@ -74,8 +75,8 @@ public class ConfigurationService { * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ - public List getAllowedParameters() throws GuacamoleException { - return environment.getProperty(QUICKCONNECT_ALLOWED_PARAMETERS); + public Collection getAllowedParameters() throws GuacamoleException { + return environment.getPropertyCollection(QUICKCONNECT_ALLOWED_PARAMETERS); } /** @@ -90,8 +91,8 @@ public class ConfigurationService { * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ - public List getDeniedParameters() throws GuacamoleException { - return environment.getProperty(QUICKCONNECT_DENIED_PARAMETERS); + public Collection getDeniedParameters() throws GuacamoleException { + return environment.getPropertyCollection(QUICKCONNECT_DENIED_PARAMETERS); } } diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/utility/QCParser.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/utility/QCParser.java index 32df74297..e71988e63 100644 --- a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/utility/QCParser.java +++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/utility/QCParser.java @@ -25,6 +25,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; @@ -60,13 +61,13 @@ public class QCParser { * by this parser. If not defined, all parameters will be allowed unless * explicitly denied. */ - private final List allowedParams; + private final Collection allowedParams; /** * The list of parameters that are explicitly denied from being placed into * a configuration by this parser. */ - private final List deniedParams; + private final Collection deniedParams; /** * Create a new instance of the QCParser class, with the provided allowed @@ -81,7 +82,7 @@ public class QCParser { * A list of parameters, if any, that should be explicitly denied from * being placed into a connection configuration. */ - public QCParser(List allowedParams, List deniedParams) { + public QCParser(Collection allowedParams, Collection deniedParams) { this.allowedParams = allowedParams; this.deniedParams = deniedParams; } diff --git a/extensions/guacamole-auth-quickconnect/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-quickconnect/src/main/resources/guac-manifest.json index 889197ca2..2225adba6 100644 --- a/extensions/guacamole-auth-quickconnect/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-quickconnect/src/main/resources/guac-manifest.json @@ -1,5 +1,5 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "Adhoc Guacamole Connections", "namespace" : "quickconnect", diff --git a/extensions/guacamole-auth-radius/pom.xml b/extensions/guacamole-auth-radius/pom.xml index d7e86fffc..b518981f1 100644 --- a/extensions/guacamole-auth-radius/pom.xml +++ b/extensions/guacamole-auth-radius/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-radius jar - 1.5.5 + 1.6.0 guacamole-auth-radius http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -115,7 +115,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided diff --git a/extensions/guacamole-auth-radius/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-radius/src/main/resources/guac-manifest.json index 6b549699b..0f70eb09e 100644 --- a/extensions/guacamole-auth-radius/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-radius/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "RADIUS Authentication Backend", "namespace" : "radius", diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/pom.xml b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/pom.xml index d6b9a9061..1cfb1815d 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/pom.xml +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/pom.xml @@ -32,7 +32,7 @@ org.apache.guacamole guacamole-auth-sso - 1.5.5 + 1.6.0 ../../ diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/pom.xml b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/pom.xml index 7d46635f5..fc11fe6c0 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/pom.xml +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-sso-cas jar - 1.5.5 + 1.6.0 guacamole-auth-sso-cas http://guacamole.apache.org/ org.apache.guacamole guacamole-auth-sso - 1.5.5 + 1.6.0 ../../ diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/guac-manifest.json index db0af2c81..ed21da1b7 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-cas/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "CAS Authentication Extension", "namespace" : "cas", diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-dist/pom.xml b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-dist/pom.xml index 4ceb3810d..2c59c5614 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-dist/pom.xml +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-dist/pom.xml @@ -32,7 +32,7 @@ org.apache.guacamole guacamole-auth-sso - 1.5.5 + 1.6.0 ../../ @@ -42,28 +42,28 @@ org.apache.guacamole guacamole-auth-sso-cas - 1.5.5 + 1.6.0 org.apache.guacamole guacamole-auth-sso-openid - 1.5.5 + 1.6.0 org.apache.guacamole guacamole-auth-sso-saml - 1.5.5 + 1.6.0 org.apache.guacamole guacamole-auth-sso-ssl - 1.5.5 + 1.6.0 diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/pom.xml b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/pom.xml index f2e0c34cb..e53143485 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/pom.xml +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-sso-openid jar - 1.5.5 + 1.6.0 guacamole-auth-sso-openid http://guacamole.apache.org/ org.apache.guacamole guacamole-auth-sso - 1.5.5 + 1.6.0 ../../ diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java index bbfdea17e..444bd7706 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java @@ -21,13 +21,13 @@ package org.apache.guacamole.auth.openid.conf; import com.google.inject.Inject; import java.net.URI; +import java.util.Collection; import java.util.Collections; import java.util.List; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.properties.IntegerGuacamoleProperty; import org.apache.guacamole.properties.StringGuacamoleProperty; -import org.apache.guacamole.properties.StringListProperty; import org.apache.guacamole.properties.URIGuacamoleProperty; /** @@ -138,8 +138,8 @@ public class ConfigurationService { * The claims within any valid JWT that should be mapped to * the authenticated user's tokens, as configured with guacamole.properties. */ - private static final StringListProperty OPENID_ATTRIBUTES_CLAIM_TYPE = - new StringListProperty() { + private static final StringGuacamoleProperty OPENID_ATTRIBUTES_CLAIM_TYPE = + new StringGuacamoleProperty() { @Override public String getName() { return "openid-attributes-claim-type"; } }; @@ -356,8 +356,8 @@ public class ConfigurationService { * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ - public List getAttributesClaimType() throws GuacamoleException { - return environment.getProperty(OPENID_ATTRIBUTES_CLAIM_TYPE, DEFAULT_ATTRIBUTES_CLAIM_TYPE); + public Collection getAttributesClaimType() throws GuacamoleException { + return environment.getPropertyCollection(OPENID_ATTRIBUTES_CLAIM_TYPE, DEFAULT_ATTRIBUTES_CLAIM_TYPE); } /** diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java index 2fad48ce4..139ab2021 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java @@ -20,6 +20,7 @@ package org.apache.guacamole.auth.openid.token; import com.google.inject.Inject; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -229,7 +230,7 @@ public class TokenValidationService { * If guacamole.properties could not be parsed. */ public Map processAttributes(JwtClaims claims) throws GuacamoleException { - List attributesClaim = confService.getAttributesClaimType(); + Collection attributesClaim = confService.getAttributesClaimType(); if (claims != null && !attributesClaim.isEmpty()) { try { diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/guac-manifest.json index 0f0efa95f..2bd7e2938 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-openid/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "OpenID Authentication Extension", "namespace" : "openid", diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/pom.xml b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/pom.xml index 2a3bc75ff..28b975aee 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/pom.xml +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-sso-saml jar - 1.5.5 + 1.6.0 guacamole-auth-sso-saml http://guacamole.apache.org/ org.apache.guacamole guacamole-auth-sso - 1.5.5 + 1.6.0 ../../ diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resources/guac-manifest.json index 2a7f452e6..593fd44c9 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-saml/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "SAML Authentication Extension", "namespace" : "saml", diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/pom.xml b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/pom.xml index acc40c185..479bfdfbd 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/pom.xml +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-sso-ssl jar - 1.5.5 + 1.6.0 guacamole-auth-sso-ssl http://guacamole.apache.org/ org.apache.guacamole guacamole-auth-sso - 1.5.5 + 1.6.0 ../../ diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/java/org/apache/guacamole/auth/ssl/SSLClientAuthenticationResource.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/java/org/apache/guacamole/auth/ssl/SSLClientAuthenticationResource.java index 984a68f34..fd3230b7d 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/java/org/apache/guacamole/auth/ssl/SSLClientAuthenticationResource.java +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/java/org/apache/guacamole/auth/ssl/SSLClientAuthenticationResource.java @@ -26,6 +26,7 @@ import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; @@ -214,7 +215,7 @@ public class SSLClientAuthenticationResource extends SSOResource { // Verify that the username is specified with one of the allowed // attributes - List usernameAttributes = confService.getSubjectUsernameAttributes(); + Collection usernameAttributes = confService.getSubjectUsernameAttributes(); if (usernameAttributes != null && !usernameAttributes.stream().anyMatch(nameRdn.getType()::equalsIgnoreCase)) throw new GuacamoleClientException("Subject DN \"" + dn + "\" " + "does not contain an acceptable username attribute."); diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/java/org/apache/guacamole/auth/ssl/conf/ConfigurationService.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/java/org/apache/guacamole/auth/ssl/conf/ConfigurationService.java index 48fc86b65..7931c0dad 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/java/org/apache/guacamole/auth/ssl/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/java/org/apache/guacamole/auth/ssl/conf/ConfigurationService.java @@ -22,7 +22,7 @@ package org.apache.guacamole.auth.ssl.conf; import com.google.inject.Inject; import java.net.URI; import java.net.URISyntaxException; -import java.util.List; +import java.util.Collection; import javax.naming.ldap.LdapName; import javax.ws.rs.core.UriBuilder; import org.apache.guacamole.GuacamoleException; @@ -30,7 +30,6 @@ import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.properties.IntegerGuacamoleProperty; import org.apache.guacamole.properties.StringGuacamoleProperty; -import org.apache.guacamole.properties.StringListProperty; import org.apache.guacamole.properties.URIGuacamoleProperty; /** @@ -146,8 +145,8 @@ public class ConfigurationService { * one of these attributes, the certificate will be rejected. By default, * any attribute is accepted. */ - private static final StringListProperty SSL_SUBJECT_USERNAME_ATTRIBUTE = - new StringListProperty () { + private static final StringGuacamoleProperty SSL_SUBJECT_USERNAME_ATTRIBUTE = + new StringGuacamoleProperty () { @Override public String getName() { return "ssl-subject-username-attribute"; } @@ -433,8 +432,8 @@ public class ConfigurationService { * @throws GuacamoleException * If the configured set of username attributes cannot be read. */ - public List getSubjectUsernameAttributes() throws GuacamoleException { - return environment.getProperty(SSL_SUBJECT_USERNAME_ATTRIBUTE); + public Collection getSubjectUsernameAttributes() throws GuacamoleException { + return environment.getPropertyCollection(SSL_SUBJECT_USERNAME_ATTRIBUTE); } } diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/resources/guac-manifest.json index 7f67fc5ba..2e23e67ef 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-ssl/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "SSL Authentication Extension", "namespace" : "ssl", diff --git a/extensions/guacamole-auth-sso/pom.xml b/extensions/guacamole-auth-sso/pom.xml index 5c76f3d37..f95ecd6e1 100644 --- a/extensions/guacamole-auth-sso/pom.xml +++ b/extensions/guacamole-auth-sso/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-sso pom - 1.5.5 + 1.6.0 guacamole-auth-sso http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -60,7 +60,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided @@ -68,7 +68,7 @@ org.apache.guacamole guacamole-auth-sso-base - 1.5.5 + 1.6.0 diff --git a/extensions/guacamole-auth-totp/pom.xml b/extensions/guacamole-auth-totp/pom.xml index 36279940f..765667ba1 100644 --- a/extensions/guacamole-auth-totp/pom.xml +++ b/extensions/guacamole-auth-totp/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-auth-totp jar - 1.5.5 + 1.6.0 guacamole-auth-totp http://guacamole.incubator.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -127,7 +127,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided @@ -177,6 +177,14 @@ 2.1.1 provided + + + + com.github.seancfoley + ipaddress + 5.5.0 + provided + diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/ConfigurationService.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/ConfigurationService.java index 06984ce40..311291484 100644 --- a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/ConfigurationService.java @@ -20,10 +20,14 @@ package org.apache.guacamole.auth.totp.conf; import com.google.inject.Inject; +import inet.ipaddr.IPAddress; +import java.util.Collections; +import java.util.List; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.properties.EnumGuacamoleProperty; +import org.apache.guacamole.properties.IPAddressListProperty; import org.apache.guacamole.properties.IntegerGuacamoleProperty; import org.apache.guacamole.properties.StringGuacamoleProperty; import org.apache.guacamole.totp.TOTPGenerator; @@ -88,6 +92,36 @@ public class ConfigurationService { public String getName() { return "totp-mode"; } }; + + /** + * A property that contains a list of IP addresses and/or subnets for which + * MFA via the TOTP module should be bypassed. Users logging in from addresses + * contained in this list will not be prompted for a second authentication + * factor. If this property is empty or not defined, and the TOTP module + * is installed, all users will be prompted for MFA. + */ + private static final IPAddressListProperty TOTP_BYPASS_HOSTS = + new IPAddressListProperty() { + + @Override + public String getName() { return "totp-bypass-hosts"; } + + }; + + /** + * A property that contains a list of IP addresses and/or subnets for which + * MFA via the TOTP module should explicitly be enabled. If this property is defined, + * and the TOTP module is installed, users logging in from hosts contained + * in this list will be prompted for MFA, and users logging in from all + * other hosts will not be prompted for MFA. + */ + private static final IPAddressListProperty TOTP_ENFORCE_HOSTS = + new IPAddressListProperty() { + + @Override + public String getName() { return "totp-enforce-hosts"; } + + }; /** * Returns the human-readable name of the entity issuing user accounts. If @@ -158,5 +192,39 @@ public class ConfigurationService { public TOTPGenerator.Mode getMode() throws GuacamoleException { return environment.getProperty(TOTP_MODE, TOTPGenerator.Mode.SHA1); } + + /** + * Return the list of IP addresses and/or subnets for which MFA authentication via the + * TOTP module should be bypassed, allowing users from those addresses to log in + * without the MFA requirement. + * + * @return + * A list of IP addresses and/or subnets for which MFA authentication + * should be bypassed. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed, or an invalid IP address + * or subnet is specified. + */ + public List getBypassHosts() throws GuacamoleException { + return environment.getProperty(TOTP_BYPASS_HOSTS, Collections.emptyList()); + } + + /** + * Return the list of IP addresses and/or subnets for which MFA authentication via the TOTP + * module should be explicitly enabled, requiring users logging in from hosts specified in + * the list to complete MFA. + * + * @return + * A list of IP addresses and/or subnets for which MFA authentication + * should be explicitly enabled. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed, or an invalid IP address + * or subnet is specified. + */ + public List getEnforceHosts() throws GuacamoleException { + return environment.getProperty(TOTP_ENFORCE_HOSTS, Collections.emptyList()); + } } diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserVerificationService.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserVerificationService.java index 30573fcbf..e08042551 100644 --- a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserVerificationService.java +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserVerificationService.java @@ -22,9 +22,12 @@ package org.apache.guacamole.auth.totp.user; import com.google.common.io.BaseEncoding; import com.google.inject.Inject; import com.google.inject.Provider; +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; import java.security.InvalidKeyException; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; @@ -44,6 +47,7 @@ import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserGroup; import org.apache.guacamole.net.auth.credentials.CredentialsInfo; +import org.apache.guacamole.properties.IPAddressListProperty; import org.apache.guacamole.totp.TOTPGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -311,6 +315,45 @@ public class UserVerificationService { public void verifyIdentity(UserContext context, AuthenticatedUser authenticatedUser) throws GuacamoleException { + // Pull the original HTTP request used to authenticate + Credentials credentials = authenticatedUser.getCredentials(); + HttpServletRequest request = credentials.getRequest(); + + // Get the current client address + IPAddress clientAddr = new IPAddressString(request.getRemoteAddr()).getAddress(); + + // Ignore anonymous users + if (authenticatedUser.getIdentifier().equals(AuthenticatedUser.ANONYMOUS_IDENTIFIER)) + return; + + // Pull address lists to check from configuration. Note that the enforce + // list will override the bypass list, which means that, if the client + // address happens to be in both lists, Duo MFA will be enforced. + List bypassAddresses = confService.getBypassHosts(); + List enforceAddresses = confService.getEnforceHosts(); + + // Check the bypass list for the client address, and set the enforce + // flag to the opposite. + boolean enforceHost = !(IPAddressListProperty.addressListContains(bypassAddresses, clientAddr)); + + // Only continue processing if the list is not empty + if (!enforceAddresses.isEmpty()) { + + // If client address is not available or invalid, MFA will + // be enforced. + if (clientAddr == null || !clientAddr.isIPAddress()) + enforceHost = true; + + // Check the enforce list and set the flag if the client address + // is found in the list. + else + enforceHost = IPAddressListProperty.addressListContains(enforceAddresses, clientAddr); + } + + // If the enforce flag is not true, bypass TOTP MFA. + if (!enforceHost) + return; + // Ignore anonymous users String username = authenticatedUser.getIdentifier(); if (username.equals(AuthenticatedUser.ANONYMOUS_IDENTIFIER)) @@ -325,10 +368,6 @@ public class UserVerificationService { if (key == null) return; - // Pull the original HTTP request used to authenticate - Credentials credentials = authenticatedUser.getCredentials(); - HttpServletRequest request = credentials.getRequest(); - // Retrieve TOTP from request String code = request.getParameter(AuthenticationCodeField.PARAMETER_NAME); diff --git a/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json index d0cbf15bf..8c145c4df 100644 --- a/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "TOTP TFA Authentication Backend", "namespace" : "totp", diff --git a/extensions/guacamole-display-statistics/pom.xml b/extensions/guacamole-display-statistics/pom.xml index 5c250f69c..de4995256 100644 --- a/extensions/guacamole-display-statistics/pom.xml +++ b/extensions/guacamole-display-statistics/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-display-statistics jar - 1.5.5 + 1.6.0 guacamole-display-statistics http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ diff --git a/extensions/guacamole-display-statistics/src/main/resources/guac-manifest.json b/extensions/guacamole-display-statistics/src/main/resources/guac-manifest.json index 4823dbf77..ca398dc89 100644 --- a/extensions/guacamole-display-statistics/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-display-statistics/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "Display Statistic Toolbar", "namespace" : "display-stats", diff --git a/extensions/guacamole-history-recording-storage/pom.xml b/extensions/guacamole-history-recording-storage/pom.xml index a65190f06..1d4fbf421 100644 --- a/extensions/guacamole-history-recording-storage/pom.xml +++ b/extensions/guacamole-history-recording-storage/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-history-recording-storage jar - 1.5.5 + 1.6.0 guacamole-history-recording-storage http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -43,7 +43,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided diff --git a/extensions/guacamole-history-recording-storage/src/main/resources/guac-manifest.json b/extensions/guacamole-history-recording-storage/src/main/resources/guac-manifest.json index 7b3fe622e..097b344e0 100644 --- a/extensions/guacamole-history-recording-storage/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-history-recording-storage/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "Session Recording Storage", "namespace" : "recording-storage", diff --git a/extensions/guacamole-vault/modules/guacamole-vault-base/pom.xml b/extensions/guacamole-vault/modules/guacamole-vault-base/pom.xml index bdc503562..6928f5791 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-base/pom.xml +++ b/extensions/guacamole-vault/modules/guacamole-vault-base/pom.xml @@ -36,7 +36,7 @@ org.apache.guacamole guacamole-vault - 1.5.5 + 1.6.0 ../../ diff --git a/extensions/guacamole-vault/modules/guacamole-vault-dist/pom.xml b/extensions/guacamole-vault/modules/guacamole-vault-dist/pom.xml index 6ce906c00..4c4a5184b 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-dist/pom.xml +++ b/extensions/guacamole-vault/modules/guacamole-vault-dist/pom.xml @@ -36,7 +36,7 @@ org.apache.guacamole guacamole-vault - 1.5.5 + 1.6.0 ../../ @@ -46,7 +46,7 @@ org.apache.guacamole guacamole-vault-ksm - 1.5.5 + 1.6.0 diff --git a/extensions/guacamole-vault/modules/guacamole-vault-ksm/pom.xml b/extensions/guacamole-vault/modules/guacamole-vault-ksm/pom.xml index d1828b86c..cd2ade991 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-ksm/pom.xml +++ b/extensions/guacamole-vault/modules/guacamole-vault-ksm/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-vault-ksm jar - 1.5.5 + 1.6.0 guacamole-vault-ksm http://guacamole.apache.org/ org.apache.guacamole guacamole-vault - 1.5.5 + 1.6.0 ../../ @@ -54,7 +54,7 @@ org.apache.guacamole guacamole-vault-base - 1.5.5 + 1.6.0 diff --git a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/resources/guac-manifest.json b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/resources/guac-manifest.json index aadd43a5b..af4e4f3cd 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/resources/guac-manifest.json @@ -1,6 +1,6 @@ { - "guacamoleVersion" : "1.5.5", + "guacamoleVersion" : "1.6.0", "name" : "Keeper Secrets Manager", "namespace" : "keeper-secrets-manager", diff --git a/extensions/guacamole-vault/pom.xml b/extensions/guacamole-vault/pom.xml index 05e1b8837..a8ea92c68 100644 --- a/extensions/guacamole-vault/pom.xml +++ b/extensions/guacamole-vault/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-vault pom - 1.5.5 + 1.6.0 guacamole-vault http://guacamole.apache.org/ org.apache.guacamole extensions - 1.5.5 + 1.6.0 ../ @@ -57,7 +57,7 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 provided diff --git a/extensions/pom.xml b/extensions/pom.xml index 2e8fca026..760c845b0 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole extensions pom - 1.5.5 + 1.6.0 extensions http://guacamole.apache.org/ org.apache.guacamole guacamole-client - 1.5.5 + 1.6.0 ../ diff --git a/guacamole-common-js/pom.xml b/guacamole-common-js/pom.xml index ff1b20188..8a34eec0c 100644 --- a/guacamole-common-js/pom.xml +++ b/guacamole-common-js/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-common-js pom - 1.5.5 + 1.6.0 guacamole-common-js http://guacamole.apache.org/ org.apache.guacamole guacamole-client - 1.5.5 + 1.6.0 ../ diff --git a/guacamole-common-js/src/main/webapp/modules/Version.js b/guacamole-common-js/src/main/webapp/modules/Version.js index 8a0736347..3dfb5378b 100644 --- a/guacamole-common-js/src/main/webapp/modules/Version.js +++ b/guacamole-common-js/src/main/webapp/modules/Version.js @@ -27,4 +27,4 @@ var Guacamole = Guacamole || {}; * * @type {!string} */ -Guacamole.API_VERSION = "1.5.4"; +Guacamole.API_VERSION = "1.6.0"; diff --git a/guacamole-common/pom.xml b/guacamole-common/pom.xml index 492960567..6f42bcc34 100644 --- a/guacamole-common/pom.xml +++ b/guacamole-common/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-common jar - 1.5.5 + 1.6.0 guacamole-common http://guacamole.apache.org/ org.apache.guacamole guacamole-client - 1.5.5 + 1.6.0 ../ diff --git a/guacamole-ext/pom.xml b/guacamole-ext/pom.xml index 161fbe648..d903a9b49 100644 --- a/guacamole-ext/pom.xml +++ b/guacamole-ext/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole-ext jar - 1.5.5 + 1.6.0 guacamole-ext http://guacamole.apache.org/ org.apache.guacamole guacamole-client - 1.5.5 + 1.6.0 ../ @@ -87,7 +87,7 @@ org.apache.guacamole guacamole-common - 1.5.5 + 1.6.0 compile @@ -110,6 +110,13 @@ jackson-databind + + + com.github.seancfoley + ipaddress + 5.5.0 + + diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/environment/DelegatingEnvironment.java b/guacamole-ext/src/main/java/org/apache/guacamole/environment/DelegatingEnvironment.java index cdaa924ea..936612a21 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/environment/DelegatingEnvironment.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/environment/DelegatingEnvironment.java @@ -20,6 +20,7 @@ package org.apache.guacamole.environment; import java.io.File; +import java.util.Collection; import java.util.Map; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; @@ -73,11 +74,35 @@ public class DelegatingEnvironment implements Environment { public Type getProperty(GuacamoleProperty property, Type defaultValue) throws GuacamoleException { return environment.getProperty(property, defaultValue); } + + @Override + public Collection getPropertyCollection(GuacamoleProperty property) + throws GuacamoleException { + return environment.getPropertyCollection(property); + } + + @Override + public Collection getPropertyCollection(GuacamoleProperty property, + Type defaultValue) throws GuacamoleException { + return environment.getPropertyCollection(property, defaultValue); + } + + @Override + public Collection getPropertyCollection(GuacamoleProperty property, + Collection defaultValue) throws GuacamoleException { + return environment.getPropertyCollection(property, defaultValue); + } @Override public Type getRequiredProperty(GuacamoleProperty property) throws GuacamoleException { return environment.getRequiredProperty(property); } + + @Override + public Collection getRequiredPropertyCollection(GuacamoleProperty property) + throws GuacamoleException { + return environment.getRequiredPropertyCollection(property); + } @Override public GuacamoleProxyConfiguration getDefaultGuacamoleProxyConfiguration() throws GuacamoleException { diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/environment/Environment.java b/guacamole-ext/src/main/java/org/apache/guacamole/environment/Environment.java index c36b953ac..22b95149b 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/environment/Environment.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/environment/Environment.java @@ -21,6 +21,8 @@ package org.apache.guacamole.environment; import org.apache.guacamole.properties.GuacamoleProperties; import java.io.File; +import java.util.Collection; +import java.util.Collections; import java.util.Map; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleUnsupportedException; @@ -102,13 +104,18 @@ public interface Environment { * Given a GuacamoleProperty, parses and returns the value set for that * property in guacamole.properties, if any. * - * @param The type that the given property is parsed into. - * @param property The property to read from guacamole.properties. - * @return The parsed value of the property as read from - * guacamole.properties. - * @throws GuacamoleException If an error occurs while parsing the value - * for the given property in - * guacamole.properties. + * @param + * The type that the given property is parsed into. + * + * @param property + * The property to read from guacamole.properties. + * + * @return + * The parsed value of the property as read from guacamole.properties. + * + * @throws GuacamoleException + * If an error occurs while parsing the value for the given property in + * guacamole.properties. */ public Type getProperty(GuacamoleProperty property) throws GuacamoleException; @@ -118,20 +125,161 @@ public interface Environment { * property in guacamole.properties, if any. If no value is found, the * provided default value is returned. * - * @param The type that the given property is parsed into. - * @param property The property to read from guacamole.properties. - * @param defaultValue The value to return if no value was given in - * guacamole.properties. - * @return The parsed value of the property as read from - * guacamole.properties, or the provided default value if no value - * was found. - * @throws GuacamoleException If an error occurs while parsing the value - * for the given property in - * guacamole.properties. + * @param + * The type that the given property is parsed into. + * + * @param property + * The property to read from guacamole.properties. + * + * @param defaultValue + * The value to return if no value was given in guacamole.properties. + * + * @return + * The parsed value of the property as read from guacamole.properties, + * or the provided default value if no value was found. + * + * @throws GuacamoleException + * If an error occurs while parsing the value for the given property in + * guacamole.properties. */ public Type getProperty(GuacamoleProperty property, Type defaultValue) throws GuacamoleException; + /** + * Given a GuacamoleProperty, parses and returns a sorted Collection of the + * value set for that property in guacamole.properties, if any. The + * implementation of parsing and returning a collection of multiple + * values is up to the individual property implementations, and not all + * implementations will support reading and returning multiple values. + * + * @param + * The type that the given property is parsed into. + * + * @param property + * The property to read from guacamole.properties. + * + * @return + * A sorted collection of the the parsed values of the property as read + * from guacamole.properties. + * + * @throws GuacamoleException + * If an error occurs while parsing the value for the given property in + * guacamole.properties. + */ + public default Collection getPropertyCollection( + GuacamoleProperty property) throws GuacamoleException { + + /* Pull the given property as a string. */ + StringGuacamoleProperty stringProperty = new StringGuacamoleProperty() { + + @Override + public String getName() { return property.getName(); } + + }; + + /* Parse the string to a Collection of the desired type. */ + return property.parseValueCollection(getProperty(stringProperty)); + + } + + /** + * Given a GuacamoleProperty, parses and returns the value set for that + * property in guacamole.properties, if any. If no value is found, a + * Collection is returned with the provided default value. The + * implementation of parsing and returning a collection of multiple + * values is up to the individual property implementations, and not all + * implementations will support reading and returning multiple values. + * + * @param + * The type that the given property is parsed into. + * + * @param property + * The property to read from guacamole.properties. + * + * @param defaultValue + * The single value to return in the Collection if no value was given + * in guacamole.properties. + * + * @return + * A sorted collection of the the parsed values of the property as read + * from guacamole.properties, or a Collection with the single default + * value provided. + * + * @throws GuacamoleException + * If an error occurs while parsing the value for the given property in + * guacamole.properties. + */ + public default Collection getPropertyCollection( + GuacamoleProperty property, Type defaultValue) + throws GuacamoleException { + + /* Pull the given property as a string. */ + StringGuacamoleProperty stringProperty = new StringGuacamoleProperty() { + + @Override + public String getName() { return property.getName(); } + + }; + + /* Check the value and return the default if null. */ + String stringValue = getProperty(stringProperty); + if (stringValue == null) + return Collections.singletonList(defaultValue); + + /* Parse the string and return the collection. */ + return property.parseValueCollection(stringValue); + + } + + /** + * Given a GuacamoleProperty, parses and returns the value set for that + * property in guacamole.properties, if any. If no value is found, the + * provided Collection of default values is returned. The + * implementation of parsing and returning a collection of multiple + * values is up to the individual property implementations, and not all + * implementations will support reading and returning multiple values. + * + * @param + * The type that the given property is parsed into. + * + * @param property + * The property to read from guacamole.properties. + * + * @param defaultValue + * The Collection of values to return in the Collection if no value was + * given in guacamole.properties. + * + * @return + * A sorted collection of the the parsed values of the property as read + * from guacamole.properties, or a Collection with the single default + * value provided. + * + * @throws GuacamoleException + * If an error occurs while parsing the value for the given property in + * guacamole.properties. + */ + public default Collection getPropertyCollection( + GuacamoleProperty property, Collection defaultValue) + throws GuacamoleException { + + /* Pull the given property as a string. */ + StringGuacamoleProperty stringProperty = new StringGuacamoleProperty() { + + @Override + public String getName() { return property.getName(); } + + }; + + /* Check the value and return the default if null. */ + String stringValue = getProperty(stringProperty); + if (stringValue == null) + return defaultValue; + + /* Parse the string and return the collection. */ + return property.parseValueCollection(stringValue); + + } + /** * Given a GuacamoleProperty, parses and returns the value set for that * property in guacamole.properties. An exception is thrown if the value @@ -148,6 +296,43 @@ public interface Environment { */ public Type getRequiredProperty(GuacamoleProperty property) throws GuacamoleException; + + /** + * Given a GuacamoleProperty, parses and returns a sorted Collection of + * values for that property in guacamole.properties. An exception is thrown + * if the value is not provided. The implementation of parsing and returning + * a collection of multiple values is up to the individual property + * implementations, and not all implementations will support reading and + * returning multiple values. + * + * @param + * The type that the given property is parsed into. + * + * @param property + * The property to read from guacamole.properties. + * + * @return + * A sorted Collection of the property as read from guacamole.properties. + * + * @throws GuacamoleException + * If an error occurs while parsing the value for the given property in + * guacamole.properties, or if the property is not specified. + */ + public default Collection getRequiredPropertyCollection( + GuacamoleProperty property) throws GuacamoleException { + + /* Pull the given property as a string. */ + StringGuacamoleProperty stringProperty = new StringGuacamoleProperty() { + + @Override + public String getName() { return property.getName(); } + + }; + + /* Parse the string to a Collection of the desired type. */ + return property.parseValueCollection(getRequiredProperty(stringProperty)); + + } /** * Returns the connection information which should be used, by default, to diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/environment/LocalEnvironment.java b/guacamole-ext/src/main/java/org/apache/guacamole/environment/LocalEnvironment.java index caf1c418e..bd0f3f152 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/environment/LocalEnvironment.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/environment/LocalEnvironment.java @@ -25,6 +25,8 @@ import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -353,6 +355,38 @@ public class LocalEnvironment implements Environment { return value; } + + @Override + public Collection getPropertyCollection(GuacamoleProperty property) + throws GuacamoleException { + + return property.parseValueCollection(getPropertyValue(property.getName())); + + } + + @Override + public Collection getPropertyCollection(GuacamoleProperty property, + Type defaultValue) throws GuacamoleException { + + Collection value = getPropertyCollection(property); + if (value == null) + return Collections.singletonList(defaultValue); + + return value; + + } + + @Override + public Collection getPropertyCollection(GuacamoleProperty property, + Collection defaultValue) throws GuacamoleException { + + Collection value = getPropertyCollection(property); + if (value == null) + return defaultValue; + + return value; + + } @Override public Type getRequiredProperty(GuacamoleProperty property) @@ -365,6 +399,18 @@ public class LocalEnvironment implements Environment { return value; } + + @Override + public Collection getRequiredPropertyCollection(GuacamoleProperty property) + throws GuacamoleException { + + Collection value = getPropertyCollection(property); + if (value == null) + throw new GuacamoleServerException("Property " + property.getName() + " is required."); + + return value; + + } @Override public Map getProtocols() { diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/permission/SystemPermission.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/permission/SystemPermission.java index 054caf066..c0c17345f 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/permission/SystemPermission.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/permission/SystemPermission.java @@ -56,6 +56,14 @@ public class SystemPermission implements Permission { * Create sharing profiles. */ CREATE_SHARING_PROFILE, + + /** + * Audit the system in general, which involves the ability to view + * active and historical connection records, user logon records, etc., + * but lacks permission to change any of these details (interact with + * active connections, update user accounts, etc). + */ + AUDIT, /** * Administer the system in general, including adding permissions diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java index aa7e74853..8e59c3c59 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java @@ -24,7 +24,6 @@ import java.util.Date; import java.util.Map; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; -import org.apache.guacamole.environment.Environment; import org.apache.guacamole.environment.LocalEnvironment; import org.apache.guacamole.net.GuacamoleSocket; import org.apache.guacamole.net.GuacamoleTunnel; @@ -53,6 +52,11 @@ public class SimpleConnection extends AbstractConnection { * Backing configuration, containing all sensitive information. */ private GuacamoleConfiguration fullConfig; + + /** + * The proxy configuration describing how to connect to guacd. + */ + private GuacamoleProxyConfiguration proxyConfig; /** * Whether parameter tokens in the underlying GuacamoleConfiguration should @@ -158,6 +162,39 @@ public class SimpleConnection extends AbstractConnection { this.interpretTokens = interpretTokens; } + + /** + * Creates a new SimpleConnection having the given identifier, + * GuacamoleConfiguration, and GuacamoleProxyConfiguration. Parameter tokens + * will be interpreted if explicitly requested. + * + * @param name + * The name to associate with this connection. + * + * @param identifier + * The identifier to associate with this connection. + * + * @param proxyConfig + * The Guacamole proxy configuration describing how the connection to + * guacd should be established, or null if the default settings will be + * used. + * + * @param config + * The configuration describing how to connect to this connection. + * + * @param interpretTokens + * Whether parameter tokens in the underlying GuacamoleConfiguration + * should be automatically applied upon connecting. If false, parameter + * tokens will not be interpreted at all. + */ + public SimpleConnection(String name, String identifier, + GuacamoleProxyConfiguration proxyConfig, + GuacamoleConfiguration config, boolean interpretTokens) { + + this(name, identifier, config, interpretTokens); + this.proxyConfig = proxyConfig; + + } /** * Returns the GuacamoleConfiguration describing how to connect to this @@ -201,9 +238,9 @@ public class SimpleConnection extends AbstractConnection { public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { - // Retrieve proxy configuration from environment - Environment environment = LocalEnvironment.getInstance(); - GuacamoleProxyConfiguration proxyConfig = environment.getDefaultGuacamoleProxyConfiguration(); + // Retrieve proxy configuration from environment if we don't have one + if (proxyConfig == null) + proxyConfig = LocalEnvironment.getInstance().getDefaultGuacamoleProxyConfiguration(); // Get guacd connection parameters String hostname = proxyConfig.getHostname(); diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/FileGuacamoleProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/FileGuacamoleProperty.java index ec380defb..38e1dac99 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/properties/FileGuacamoleProperty.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/FileGuacamoleProperty.java @@ -20,6 +20,9 @@ package org.apache.guacamole.properties; import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.guacamole.GuacamoleException; /** @@ -37,5 +40,27 @@ public abstract class FileGuacamoleProperty implements GuacamoleProperty { return new File(value); } + + @Override + public List parseValueCollection(String value) throws GuacamoleException { + + // If no property is provided, return null. + if (value == null) + return null; + + // Split string into a list of individual values + List stringValues = Arrays.asList(DELIMITER_PATTERN.split(value)); + if (stringValues.isEmpty()) + return null; + + // Translate values to Files and add to result array. + List fileValues = new ArrayList<>(); + for (String stringFile : stringValues) { + fileValues.add(new File(stringFile)); + } + + return fileValues; + + } } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/GuacamoleProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/GuacamoleProperty.java index ed0c9f1a1..bcbea055b 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/properties/GuacamoleProperty.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/GuacamoleProperty.java @@ -19,6 +19,9 @@ package org.apache.guacamole.properties; +import java.util.Collection; +import java.util.Collections; +import java.util.regex.Pattern; import org.apache.guacamole.GuacamoleException; /** @@ -30,12 +33,21 @@ import org.apache.guacamole.GuacamoleException; */ public interface GuacamoleProperty { + /** + * A pattern which matches against the delimiters between values. This is + * currently simply a semicolon and any following whitespace. Parts of the + * input string which match this pattern will not be included in the parsed + * result. + */ + static final Pattern DELIMITER_PATTERN = Pattern.compile(";\\s*"); + /** * Returns the name of the property in guacamole.properties that this * GuacamoleProperty will parse. * - * @return The name of the property in guacamole.properties that this - * GuacamoleProperty will parse. + * @return + * The name of the property in guacamole.properties that this + * GuacamoleProperty will parse. */ public String getName(); @@ -43,11 +55,37 @@ public interface GuacamoleProperty { * Parses the given string value into the type associated with this * GuacamoleProperty. * - * @param value The string value to parse. - * @return The parsed value. - * @throws GuacamoleException If an error occurs while parsing the - * provided value. + * @param value + * The string value to parse. + * + * @return + * The parsed value. + * + * @throws GuacamoleException + * If an error occurs while parsing the provided value. */ public Type parseValue(String value) throws GuacamoleException; + + /** + * Parses the given string value into a Collection of values of the type + * associated with this GuacamoleProperty. The default implementation + * simply returns a list containing a single item as parsed by the + * parseValue method. + * + * @param value + * The string value to parse. + * + * @return + * A sorted Collection of the parsed values. + * + * @throws GuacamoleException + * If an error occurs while parsing the provided value. + */ + default public Collection parseValueCollection(String value) + throws GuacamoleException { + + return Collections.singletonList(parseValue(value)); + + } } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/IPAddressListProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/IPAddressListProperty.java new file mode 100644 index 000000000..1e0f6edfa --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/IPAddressListProperty.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.properties; + +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleServerException; + +/** + * A GuacamoleProperty implementation that parses a String for a comma-separated + * list of IP addresses and/or IP subnets, both IPv4 and IPv6, and returns the + * list of those valid IP addresses/subnets. + */ +public abstract class IPAddressListProperty implements GuacamoleProperty> { + + /** + * A pattern which matches against the delimiters between values. This is + * currently simply a comma and any following whitespace. Parts of the + * input string which match this pattern will not be included in the parsed + * result. + */ + private static final Pattern DELIMITER_PATTERN = Pattern.compile(",\\s*"); + + @Override + public List parseValue(String values) throws GuacamoleException { + + // Null for null + if (values == null) + return null; + + // Not null, just empty + if (values.isEmpty()) + return Collections.emptyList(); + + // Split the string into an array + List addrStrings = Arrays.asList(DELIMITER_PATTERN.split(values)); + List ipAddresses = new ArrayList<>(); + + // Loop through each string + for (String addrString : addrStrings) { + + // Convert the string to an IPAddressString for validation + IPAddressString ipString = new IPAddressString(addrString); + + // If this isn't a valid address, subnet, etc., throw an exception + if (!ipString.isIPAddress()) + throw new GuacamoleServerException("Invalid IP address specified: " + addrString); + + // Add the address to the list. + ipAddresses.add(ipString.getAddress()); + } + + // Return our list of valid IP addresses and/or subnets + return ipAddresses; + + } + + /** + * Return true if the provided address list contains the client address, + * or false if no match is found. + * + * @param addrList + * The address list to check for matches. + * + * @param ipAddr + * The client address to look for in the list. + * + * @return + * True if the client address is in the provided list, otherwise + * false. + */ + public static boolean addressListContains(List addrList, IPAddress ipAddr) { + + // If either is null, return false + if (ipAddr == null || addrList == null) + return false; + + for (IPAddress ipEntry : addrList) + + // If version matches and entry contains it, return true + if (ipEntry.getIPVersion().equals(ipAddr.getIPVersion()) + && ipEntry.contains(ipAddr)) + return true; + + // No match, so return false + return false; + + } + +} diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/IntegerGuacamoleProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/IntegerGuacamoleProperty.java index 2228e2ea2..8746f2774 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/properties/IntegerGuacamoleProperty.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/IntegerGuacamoleProperty.java @@ -19,6 +19,9 @@ package org.apache.guacamole.properties; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; @@ -42,5 +45,26 @@ public abstract class IntegerGuacamoleProperty implements GuacamoleProperty parseValueCollection(String value) throws GuacamoleException { + + if (value == null) + return null; + + // Split string into a list of individual values + List stringValues = Arrays.asList(DELIMITER_PATTERN.split(value)); + if (stringValues.isEmpty()) + return null; + + // Translate values to Integers, validating along the way. + List intValues = new ArrayList<>(); + for (String stringInt : stringValues) { + intValues.add(parseValue(stringInt)); + } + + return intValues; + + } } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/LongGuacamoleProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/LongGuacamoleProperty.java index 9c25d6f50..b118a6140 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/properties/LongGuacamoleProperty.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/LongGuacamoleProperty.java @@ -19,6 +19,9 @@ package org.apache.guacamole.properties; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; @@ -42,5 +45,26 @@ public abstract class LongGuacamoleProperty implements GuacamoleProperty { } } + + @Override + public List parseValueCollection(String value) throws GuacamoleException { + + if (value == null) + return null; + + // Split string into a list of individual values + List stringValues = Arrays.asList(DELIMITER_PATTERN.split(value)); + if (stringValues.isEmpty()) + return null; + + // Translate values to Longs, validating along the way. + List longValues = new ArrayList<>(); + for (String stringLong : stringValues) { + longValues.add(parseValue(stringLong)); + } + + return longValues; + + } } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/StringGuacamoleProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/StringGuacamoleProperty.java index 0d3756ab1..abc2b15cb 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/properties/StringGuacamoleProperty.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/StringGuacamoleProperty.java @@ -19,6 +19,8 @@ package org.apache.guacamole.properties; +import java.util.Arrays; +import java.util.List; import org.apache.guacamole.GuacamoleException; /** @@ -30,5 +32,20 @@ public abstract class StringGuacamoleProperty implements GuacamoleProperty parseValueCollection(String value) throws GuacamoleException { + + if (value == null) + return null; + + // Split string into a list of individual values + List stringValues = Arrays.asList(DELIMITER_PATTERN.split(value)); + if (stringValues.isEmpty()) + return null; + + return stringValues; + + } } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/StringListProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/StringListProperty.java index 0bb81423c..574a3d8ca 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/properties/StringListProperty.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/StringListProperty.java @@ -31,17 +31,14 @@ import org.apache.guacamole.GuacamoleException; * compatibility with the behavior of Java properties in general, only * whitespace at the beginning of each value is ignored; trailing whitespace * becomes part of the value. + * + * @deprecated + * This class is now deprecated in favor of using the StringGuacamoleProperty + * class with the parseValueCollection method. */ +@Deprecated public abstract class StringListProperty implements GuacamoleProperty> { - /** - * A pattern which matches against the delimiters between values. This is - * currently simply a comma and any following whitespace. Parts of the - * input string which match this pattern will not be included in the parsed - * result. - */ - private static final Pattern DELIMITER_PATTERN = Pattern.compile(",\\s*"); - @Override public List parseValue(String values) throws GuacamoleException { diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java index a294bda67..d4a15f977 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/TimeZoneGuacamoleProperty.java @@ -19,6 +19,9 @@ package org.apache.guacamole.properties; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.TimeZone; import java.util.regex.Pattern; import org.apache.guacamole.GuacamoleException; @@ -57,4 +60,25 @@ public abstract class TimeZoneGuacamoleProperty } + @Override + public List parseValueCollection(String value) throws GuacamoleException { + + if (value == null) + return null; + + // Split string into a list of individual values + List stringValues = Arrays.asList(DELIMITER_PATTERN.split(value)); + if (stringValues.isEmpty()) + return null; + + // Translate values to Integers, validating along the way. + List tzValues = new ArrayList<>(); + for (String stringTz : stringValues) { + tzValues.add(parseValue(stringTz)); + } + + return tzValues; + + } + } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/URIGuacamoleProperty.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/URIGuacamoleProperty.java index 7f53bf834..ae6077c7b 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/properties/URIGuacamoleProperty.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/URIGuacamoleProperty.java @@ -21,6 +21,9 @@ package org.apache.guacamole.properties; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; @@ -46,4 +49,26 @@ public abstract class URIGuacamoleProperty implements GuacamoleProperty { } + @Override + public List parseValueCollection(String value) throws GuacamoleException { + + // Nothing provided, return nothing. + if (value == null) + return null; + + // Split string into a list of individual values + List stringValues = Arrays.asList(DELIMITER_PATTERN.split(value)); + if (stringValues.isEmpty()) + return null; + + // Translate values to URIs, validating along the way. + List uriValues = new ArrayList<>(); + for (String stringUri : stringValues) { + uriValues.add(parseValue(stringUri)); + } + + return uriValues; + + } + } diff --git a/guacamole/pom.xml b/guacamole/pom.xml index 6cae5dc10..b0743b0fd 100644 --- a/guacamole/pom.xml +++ b/guacamole/pom.xml @@ -26,14 +26,14 @@ org.apache.guacamole guacamole war - 1.5.5 + 1.6.0 guacamole http://guacamole.apache.org/ org.apache.guacamole guacamole-client - 1.5.5 + 1.6.0 ../ @@ -254,14 +254,14 @@ org.apache.guacamole guacamole-ext - 1.5.5 + 1.6.0 org.apache.guacamole guacamole-common-js - 1.5.5 + 1.6.0 zip runtime diff --git a/guacamole/src/main/frontend/src/app/manage/directives/systemPermissionEditor.js b/guacamole/src/main/frontend/src/app/manage/directives/systemPermissionEditor.js index 78377a7d5..079c0d03f 100644 --- a/guacamole/src/main/frontend/src/app/manage/directives/systemPermissionEditor.js +++ b/guacamole/src/main/frontend/src/app/manage/directives/systemPermissionEditor.js @@ -121,6 +121,10 @@ angular.module('manage').directive('systemPermissionEditor', ['$injector', label: "MANAGE_USER.FIELD_HEADER_ADMINISTER_SYSTEM", value: PermissionSet.SystemPermissionType.ADMINISTER }, + { + label: "MANAGE_USER.FIELD_HEADER_AUDIT_SYSTEM", + value: PermissionSet.SystemPermissionType.AUDIT + }, { label: "MANAGE_USER.FIELD_HEADER_CREATE_NEW_USERS", value: PermissionSet.SystemPermissionType.CREATE_USER diff --git a/guacamole/src/main/frontend/src/app/navigation/services/userPageService.js b/guacamole/src/main/frontend/src/app/navigation/services/userPageService.js index aeb701a33..9a9f693f6 100644 --- a/guacamole/src/main/frontend/src/app/navigation/services/userPageService.js +++ b/guacamole/src/main/frontend/src/app/navigation/services/userPageService.js @@ -298,8 +298,9 @@ angular.module('navigation').factory('userPageService', ['$injector', // Determine whether the current user needs access to view connection history if ( - // A user must be a system administrator to view connection records - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + // A user must be a system administrator or auditor to view connection records + PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.AUDIT) ) { canViewConnectionRecords.push(dataSource); } @@ -312,7 +313,7 @@ angular.module('navigation').factory('userPageService', ['$injector', url : '/settings/sessions' })); - // If user can manage connections, add links for connection management pages + // If user can view connection records, add links for connection history pages angular.forEach(canViewConnectionRecords, function addConnectionHistoryLink(dataSource) { pages.push(new PageDefinition({ name : [ diff --git a/guacamole/src/main/frontend/src/app/rest/types/PermissionSet.js b/guacamole/src/main/frontend/src/app/rest/types/PermissionSet.js index 9dd1ac8d6..2a549456b 100644 --- a/guacamole/src/main/frontend/src/app/rest/types/PermissionSet.js +++ b/guacamole/src/main/frontend/src/app/rest/types/PermissionSet.js @@ -136,6 +136,11 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * Permission to administer the entire system. */ ADMINISTER : "ADMINISTER", + + /** + * Permission to view connection and user records for the entire system. + */ + AUDIT : "AUDIT", /** * Permission to create new users. diff --git a/guacamole/src/main/frontend/src/translations/en.json b/guacamole/src/main/frontend/src/translations/en.json index 1c7e08a82..d02968787 100644 --- a/guacamole/src/main/frontend/src/translations/en.json +++ b/guacamole/src/main/frontend/src/translations/en.json @@ -408,6 +408,7 @@ "ERROR_PASSWORD_MISMATCH" : "@:APP.ERROR_PASSWORD_MISMATCH", "FIELD_HEADER_ADMINISTER_SYSTEM" : "Administer system:", + "FIELD_HEADER_AUDIT_SYSTEM" : "Audit system:", "FIELD_HEADER_CHANGE_OWN_PASSWORD" : "Change own password:", "FIELD_HEADER_CREATE_NEW_USERS" : "Create new users:", "FIELD_HEADER_CREATE_NEW_USER_GROUPS" : "Create new user groups:", @@ -449,6 +450,7 @@ "DIALOG_HEADER_ERROR" : "@:APP.DIALOG_HEADER_ERROR", "FIELD_HEADER_ADMINISTER_SYSTEM" : "@:MANAGE_USER.FIELD_HEADER_ADMINISTER_SYSTEM", + "FIELD_HEADER_AUDIT_SYSTEM" : "@:MANAGE_USER.FIELD_HEADER_AUDIT_SYSTEM", "FIELD_HEADER_CHANGE_OWN_PASSWORD" : "@:MANAGE_USER.FIELD_HEADER_CHANGE_OWN_PASSWORD", "FIELD_HEADER_CREATE_NEW_USERS" : "@:MANAGE_USER.FIELD_HEADER_CREATE_NEW_USERS", "FIELD_HEADER_CREATE_NEW_USER_GROUPS" : "@:MANAGE_USER.FIELD_HEADER_CREATE_NEW_USER_GROUPS", diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java index b0f6537a7..c4744e2d9 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java @@ -74,7 +74,8 @@ public class ExtensionModule extends ServletModule { "1.5.2", "1.5.3", "1.5.4", - "1.5.5" + "1.5.5", + "1.6.0" )); /** diff --git a/pom.xml b/pom.xml index c3c242d80..a2155f4e3 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ org.apache.guacamole guacamole-client pom - 1.5.5 + 1.6.0 guacamole-client http://guacamole.apache.org/