From bcca5e6ee378eca0bce4f2a739ec1ecfb7ed7b21 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Tue, 18 Jul 2023 17:26:40 -0400 Subject: [PATCH] GUACAMOLE-1239: Make identifier comparison case-insensitive. --- .../auth/header/ConfigurationService.java | 20 ++++++++++++ .../header/HTTPHeaderGuacamoleProperties.java | 17 ++++++++-- .../auth/header/user/AuthenticatedUser.java | 18 +++++++++++ .../guacamole/auth/jdbc/JDBCEnvironment.java | 13 ++++++++ .../jdbc/user/ModeledAuthenticatedUser.java | 5 +++ .../guacamole/auth/jdbc/user/ModeledUser.java | 18 +++++++++++ .../auth/mysql/conf/MySQLEnvironment.java | 13 +++++++- .../mysql/conf/MySQLGuacamoleProperties.java | 10 +++++- .../conf/PostgreSQLEnvironment.java | 12 +++++++ .../conf/PostgreSQLGuacamoleProperties.java | 12 +++++++ .../sqlserver/conf/SQLServerEnvironment.java | 12 +++++++ .../conf/SQLServerGuacamoleProperties.java | 8 +++++ .../auth/json/ConfigurationService.java | 32 +++++++++++++++++++ .../auth/json/user/AuthenticatedUser.java | 19 +++++++++++ .../auth/ldap/user/LDAPAuthenticatedUser.java | 6 ++++ .../radius/conf/ConfigurationService.java | 16 ++++++++++ .../conf/RadiusGuacamoleProperties.java | 12 +++++++ .../auth/radius/user/AuthenticatedUser.java | 11 +++++++ .../auth/sso/user/SSOAuthenticatedUser.java | 8 +++++ .../net/auth/AbstractIdentifiable.java | 24 +++++++++++--- .../guacamole/net/auth/AbstractUser.java | 5 +++ .../guacamole/net/auth/Identifiable.java | 13 ++++++++ 22 files changed, 295 insertions(+), 9 deletions(-) diff --git a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/ConfigurationService.java b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/ConfigurationService.java index 2ab1350dc7..602a5f051a 100644 --- a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/ConfigurationService.java +++ b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/ConfigurationService.java @@ -53,5 +53,25 @@ public String getHttpAuthHeader() throws GuacamoleException { "REMOTE_USER" ); } + + /** + * Returns true if the username provided to the header authentication + * module should be treated as case-sensitive, or false if the username + * provided should be treated as case-insensitive. The default is false, + * the username will be case-insensitive. + * + * @return + * True if the username should be treated as case-sensitive, otherwise + * false. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public boolean getCaseSensitiveUsernames() throws GuacamoleException { + return environment.getProperty( + HTTPHeaderGuacamoleProperties.HTTP_AUTH_CASE_SENSITIVE_USERNAMES, + false + ); + } } diff --git a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderGuacamoleProperties.java b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderGuacamoleProperties.java index 733a1f8cdb..f75cc57962 100644 --- a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderGuacamoleProperties.java +++ b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderGuacamoleProperties.java @@ -19,7 +19,7 @@ package org.apache.guacamole.auth.header; -import org.apache.guacamole.properties.IntegerGuacamoleProperty; +import org.apache.guacamole.properties.BooleanGuacamoleProperty; import org.apache.guacamole.properties.StringGuacamoleProperty; @@ -36,7 +36,7 @@ public class HTTPHeaderGuacamoleProperties { private HTTPHeaderGuacamoleProperties() {} /** - * The header used for HTTP header authentication. + * A property used to configure the header used for HTTP header authentication. */ public static final StringGuacamoleProperty HTTP_AUTH_HEADER = new StringGuacamoleProperty() { @@ -44,5 +44,18 @@ private HTTPHeaderGuacamoleProperties() {} public String getName() { return "http-auth-header"; } }; + + /** + * A property used to configure whether or not the username provided by the + * header module should be treated as case-sensitive. By default usernames + * will not be case-sensitive. + */ + public static final BooleanGuacamoleProperty HTTP_AUTH_CASE_SENSITIVE_USERNAMES = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "http-auth-case-sensitive-usernames"; } + + }; } diff --git a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/user/AuthenticatedUser.java b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/user/AuthenticatedUser.java index 793fef01e6..7e00223da1 100644 --- a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/user/AuthenticatedUser.java +++ b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/user/AuthenticatedUser.java @@ -20,6 +20,8 @@ package org.apache.guacamole.auth.header.user; import com.google.inject.Inject; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.header.ConfigurationService; import org.apache.guacamole.net.auth.AbstractAuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Credentials; @@ -37,6 +39,12 @@ public class AuthenticatedUser extends AbstractAuthenticatedUser { */ @Inject private AuthenticationProvider authProvider; + + /** + * Service for retrieving header configuration information. + */ + @Inject + private ConfigurationService confService; /** * The credentials provided when this user was authenticated. @@ -58,6 +66,16 @@ public void init(String username, Credentials credentials) { setIdentifier(username.toLowerCase()); } + @Override + public boolean isCaseSensitive() { + try { + return confService.getCaseSensitiveUsernames(); + } + catch (GuacamoleException e) { + return false; + } + } + @Override public AuthenticationProvider getAuthenticationProvider() { return authProvider; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java index 27f3d0563d..dcc7544518 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java @@ -271,5 +271,18 @@ public boolean shouldUseBatchExecutor() { return true; } + + /** + * Returns a boolean value that indicates whether or not usernames should + * be treated as case-sensitive. + * + * @return + * true if usernames should be treated as case-sensitive, or false if + * usernames should be treated as case-insensitive. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public abstract boolean getCaseSensitiveUsernames() throws GuacamoleException; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java index 7ede92c6cd..6c5ca16f4d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java @@ -194,5 +194,10 @@ public Set getEffectiveUserGroups() { public boolean isPrivileged() throws GuacamoleException { return getUser().isPrivileged(); } + + @Override + public boolean isCaseSensitive() { + return user.isCaseSensitive(); + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index 811ccaa311..4ac0b95dca 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -36,6 +36,7 @@ import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService; import org.apache.guacamole.auth.jdbc.security.SaltService; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.JDBCEnvironment; import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.form.BooleanField; import org.apache.guacamole.form.DateField; @@ -180,6 +181,13 @@ public class ModeledUser extends ModeledPermissions implements User { */ @Inject private Provider userRecordSetProvider; + + /** + * The environment associated with this instance of the JDBC authentication + * module. + */ + @Inject + private JDBCEnvironment environment; /** * Whether attributes which control access restrictions should be exposed @@ -780,5 +788,15 @@ public Permissions getEffectivePermissions() throws GuacamoleException { public boolean isSkeleton() { return (getModel().getEntityID() == null); } + + @Override + public boolean isCaseSensitive() { + try { + return environment.getCaseSensitiveUsernames(); + } + catch (GuacamoleException e) { + return true; + } + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java index a3dea8964d..c5c142ef37 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java @@ -439,7 +439,18 @@ public boolean enforceAccessWindowsForActiveSessions() throws GuacamoleException // Enforce access window restrictions for active sessions unless explicitly disabled return getProperty( MySQLGuacamoleProperties.MYSQL_ENFORCE_ACCESS_WINDOWS_FOR_ACTIVE_SESSIONS, - true); + true + ); + } + + @Override + public boolean getCaseSensitiveUsernames() throws GuacamoleException { + + return getProperty( + MySQLGuacamoleProperties.MYSQL_CASE_SENSITIVE_USERNAMES, + false + ); + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java index 5e20b52c63..d2b80987a1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java @@ -301,6 +301,14 @@ private MySQLGuacamoleProperties() {} @Override public String getName() { return "mysql-batch-size"; } - }; + }; + + public static final BooleanGuacamoleProperty MYSQL_CASE_SENSITIVE_USERNAMES = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "mysql-case-sensitive-usernames"; } + + }; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java index a0e166aa62..0955ab13e7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java @@ -398,5 +398,17 @@ public boolean enforceAccessWindowsForActiveSessions() throws GuacamoleException PostgreSQLGuacamoleProperties.POSTGRESQL_ENFORCE_ACCESS_WINDOWS_FOR_ACTIVE_SESSIONS, true); } + + @Override + public boolean getCaseSensitiveUsernames() throws GuacamoleException { + + // By default, PostgreSQL does use case-sensitive string searches, so + // we will honor case-sensitive usernames. + return getProperty( + PostgreSQLGuacamoleProperties.POSTGRESQL_CASE_SENSITIVE_USERNAMES, + true + ); + + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java index 707b83ca19..c3f64a1547 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java @@ -314,5 +314,17 @@ private PostgreSQLGuacamoleProperties() {} public String getName() { return "postgresql-batch-size"; } }; + + /** + * A property that configures whether or not usernames should be treated as + * case-sensitive with the Postgres JDBC backend. + */ + public static final BooleanGuacamoleProperty POSTGRESQL_CASE_SENSITIVE_USERNAMES = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-case-sensitive-usernames"; } + + }; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java index 498479d795..5b0f6969b9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java @@ -328,5 +328,17 @@ public boolean trustAllServerCertificates() throws GuacamoleException { SQLServerGuacamoleProperties.SQLSERVER_TRUST_ALL_SERVER_CERTIFICATES, false); } + + @Override + public boolean getCaseSensitiveUsernames() throws GuacamoleException { + + // SQL Server uses case-insensitive string searches by default, so + // we do not enforce case-sensitivity unless otherwise configured. + return getProperty( + SQLServerGuacamoleProperties.SQLSERVER_CASE_SENSITIVE_USERNAMES, + false + ); + + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerGuacamoleProperties.java index c4df81381f..d978a53884 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerGuacamoleProperties.java @@ -257,5 +257,13 @@ private SQLServerGuacamoleProperties() {} public String getName() { return "sqlserver-trust-all-server-certificates"; } }; + + public static final BooleanGuacamoleProperty SQLSERVER_CASE_SENSITIVE_USERNAMES = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "sqlserver-case-sensitive-usernames" ; } + + }; } 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 2705e61ed3..9e6d5fbfd7 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 @@ -24,6 +24,7 @@ import java.util.Collections; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.environment.Environment; +import org.apache.guacamole.properties.BooleanGuacamoleProperty; import org.apache.guacamole.properties.ByteArrayProperty; import org.apache.guacamole.properties.StringGuacamoleProperty; @@ -39,6 +40,20 @@ public class ConfigurationService { @Inject private Environment environment; + /** + * Whether or not usernames of users associated with the JSON module should + * be treated as case-sensitive. + */ + private static final BooleanGuacamoleProperty JSON_CASE_SENSITIVE_USERNAMES = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { + return "json-case-sensitive-usernames"; + } + + }; + /** * The encryption key to use for all decryption and signature verification. */ @@ -64,6 +79,23 @@ public String getName() { } }; + + /** + * Returns true if the usernames of users authenticated by the JSON module + * should be treated as case-sensitive, or false if the usernames should + * be treated as case-insensitive. The default is false, usernames will + * be treated as case-insensitive. + * + * @return + * True if the usernames of users authenticated by this module should + * be treated as case-sensitive, otherwise false. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public boolean getCaseSensitiveUsernames() throws GuacamoleException { + return environment.getProperty(JSON_CASE_SENSITIVE_USERNAMES, false); + } /** * Returns the symmetric key which will be used to encrypt and sign all diff --git a/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/user/AuthenticatedUser.java b/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/user/AuthenticatedUser.java index 562d6a4268..37949c80aa 100644 --- a/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/user/AuthenticatedUser.java +++ b/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/user/AuthenticatedUser.java @@ -20,6 +20,8 @@ package org.apache.guacamole.auth.json.user; import com.google.inject.Inject; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.json.ConfigurationService; import org.apache.guacamole.net.auth.AbstractAuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Credentials; @@ -37,6 +39,13 @@ public class AuthenticatedUser extends AbstractAuthenticatedUser { */ @Inject private AuthenticationProvider authProvider; + + /** + * Reference to the configuration service associated with this + * authentication provider. + */ + @Inject + private ConfigurationService confService; /** * The credentials provided when this user was authenticated. @@ -66,6 +75,16 @@ public void init(Credentials credentials, UserData userData) { this.userData = userData; setIdentifier(userData.getUsername()); } + + @Override + public boolean isCaseSensitive() { + try { + return confService.getCaseSensitiveUsernames(); + } + catch (GuacamoleException e) { + return false; + } + } @Override public AuthenticationProvider getAuthenticationProvider() { diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPAuthenticatedUser.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPAuthenticatedUser.java index 2abe4aef09..4e2da161b8 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPAuthenticatedUser.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPAuthenticatedUser.java @@ -135,6 +135,12 @@ public ConnectedLDAPConfiguration getLDAPConfiguration() { return config; } + @Override + public boolean isCaseSensitive() { + // LDAP authentication is almost universally case-insensitive + return false; + } + @Override public AuthenticationProvider getAuthenticationProvider() { return authProvider; diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/ConfigurationService.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/ConfigurationService.java index 78738ed537..bc94e9e0f8 100644 --- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/ConfigurationService.java @@ -362,5 +362,21 @@ public InetAddress getRadiusNasIp() throws GuacamoleException { throw new GuacamoleServerException("Unknown host specified for NAS IP.", e); } } + + /** + * Returns true if the usernames of users authenticated by this module + * should be treated as case-sensitive, otherwise false. By default RADIUS + * users will not be treated as case-sensitive. + * + * @return + * True if usernames of users authenticated by this module should be + * treated as case-sensitive, otherwise false. + * + * @throws GuacamoleException + * If guacamole.properties cannot be read. + */ + public boolean getCaseSensitiveUsernames() throws GuacamoleException { + return environment.getProperty(RadiusGuacamoleProperties.RADIUS_CASE_SENSITIVE_USERNAMES, false); + } } diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusGuacamoleProperties.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusGuacamoleProperties.java index 06e186f238..a1fa27ace8 100644 --- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusGuacamoleProperties.java +++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/conf/RadiusGuacamoleProperties.java @@ -204,6 +204,18 @@ private RadiusGuacamoleProperties() {} public String getName() { return "radius-nas-ip"; } }; + + /** + * A property that configures whether or not the usernames of users + * authenticated via the RADIUS module will be treated as case-sensitive. + */ + public static final BooleanGuacamoleProperty RADIUS_CASE_SENSITIVE_USERNAMES = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "radius-case-sensitive-usernames"; } + + }; } diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/user/AuthenticatedUser.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/user/AuthenticatedUser.java index a42925357c..58e349764e 100644 --- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/user/AuthenticatedUser.java +++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/user/AuthenticatedUser.java @@ -36,6 +36,12 @@ public class AuthenticatedUser extends AbstractAuthenticatedUser { */ @Inject private AuthenticationProvider authProvider; + + /** + * A reference to the configuration service associated with this module. + */ + @Inject + private ConfigurationService confService; /** * The credentials provided when this user was authenticated. @@ -62,5 +68,10 @@ public AuthenticationProvider getAuthenticationProvider() { public Credentials getCredentials() { return credentials; } + + @Override + public boolean isCaseSensitive() { + return confService.getCaseSensitiveUsernames(); + } } diff --git a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/user/SSOAuthenticatedUser.java b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/user/SSOAuthenticatedUser.java index 1e46f6d25b..11b84292b3 100644 --- a/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/user/SSOAuthenticatedUser.java +++ b/extensions/guacamole-auth-sso/modules/guacamole-auth-sso-base/src/main/java/org/apache/guacamole/auth/sso/user/SSOAuthenticatedUser.java @@ -112,5 +112,13 @@ public Credentials getCredentials() { public Set getEffectiveUserGroups() { return effectiveGroups; } + + @Override + public boolean isCaseSensitive() { + // Most SSO systems do not consider usernames to be case-sensitive + // so that is the default for SSO modules across the board, unless + // overriden by a specific implementation. + return false; + } } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractIdentifiable.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractIdentifiable.java index 3401719d42..b0a22e6c3a 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractIdentifiable.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractIdentifiable.java @@ -34,12 +34,19 @@ public abstract class AbstractIdentifiable implements Identifiable { @Override public String getIdentifier() { - return identifier; + if (identifier == null || isCaseSensitive()) + return identifier; + + return identifier.toLowerCase(); } @Override public void setIdentifier(String identifier) { - this.identifier = identifier; + if (isCaseSensitive()) + this.identifier = identifier; + else + if (identifier != null) + this.identifier = identifier.toLowerCase(); } @Override @@ -48,7 +55,10 @@ public int hashCode() { if (identifier == null) return 0; - return identifier.hashCode(); + if (isCaseSensitive()) + return identifier.hashCode(); + + return identifier.toLowerCase().hashCode(); } @Override @@ -65,8 +75,12 @@ public boolean equals(Object other) { if (otherIdentifier == null) return identifier == null; - // Otherwise, equal only if strings are identical - return otherIdentifier.equals(identifier); + // If this identifier is case-sensitive, evaluate with case-sensitivity. + if (isCaseSensitive()) + return otherIdentifier.equals(identifier); + + // The identifier should not be evaluated in a case-sensitive manner. + return otherIdentifier.equalsIgnoreCase(identifier); } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUser.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUser.java index f4e85ae6fd..bc71934f22 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUser.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUser.java @@ -49,6 +49,11 @@ public String getPassword() { public void setPassword(String password) { this.password = password; } + + @Override + public boolean isCaseSensitive() { + return false; + } /** * {@inheritDoc} diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Identifiable.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Identifiable.java index d32fec0636..b5e0136c2a 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Identifiable.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Identifiable.java @@ -43,5 +43,18 @@ public interface Identifiable { * The identifier to assign. */ public void setIdentifier(String identifier); + + /** + * Whether or not this identifier should be evaluated in a case-sensitive + * manner or not. By default this returns true and the identifier will + * be evaluated in a case-sensitive manner. + * + * @return + * True if the comparisons of this identifier should be case-sensitive, + * otherwise false. + */ + default public boolean isCaseSensitive() { + return true; + } }