From 47f7eb34b62aa92eab795164a384dd9ed1de35c8 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 17 Feb 2019 20:48:57 -0800 Subject: [PATCH 1/5] GUACAMOLE-708: Define getPrivileged() mechanism for allowing internal, privileged access for the benefit of other extensions. --- .../net/auth/AbstractUserContext.java | 12 +++++++++ .../net/auth/DelegatingUserContext.java | 5 ++++ .../guacamole/net/auth/UserContext.java | 25 +++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUserContext.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUserContext.java index eb31f7edb..c4dbf10b0 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUserContext.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUserContext.java @@ -254,4 +254,16 @@ public abstract class AbstractUserContext implements UserContext { public void invalidate() { } + /** + * {@inheritDoc} + * + *

This implementation simply returns this. Implementations + * that wish to provide additional privileges to extensions requesting + * privileged access should override this function. + */ + @Override + public UserContext getPrivileged() { + return this; + } + } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingUserContext.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingUserContext.java index 9db6adb79..85e025909 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingUserContext.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/DelegatingUserContext.java @@ -152,4 +152,9 @@ public class DelegatingUserContext implements UserContext { userContext.invalidate(); } + @Override + public UserContext getPrivileged() { + return userContext.getPrivileged(); + } + } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/UserContext.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/UserContext.java index ea7c8c40e..ccdcaae09 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/UserContext.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/UserContext.java @@ -262,4 +262,29 @@ public interface UserContext { */ void invalidate(); + /** + * Returns a user context which provides privileged access. Unlike the + * original user context, which is required to enforce its own permissions + * and act only within the rights of the associated user, the user context + * returned by this function MAY ignore the restrictions that otherwise + * limit the current user's access. + * + *

This function is intended to allow extensions which decorate other + * extensions to act independently of the restrictions that affect the + * current user. This function will only be invoked by extensions and + * WILL NOT be invoked directly by the web application. Implementations of + * this function MAY still enforce access restrictions, particularly if + * they do not want to grant full, unrestricted access to other extensions. + * + *

A default implementation which simply returns this is + * provided for compatibility with Apache Guacamole 1.1.0 and older. + * + * @return + * A user context instance which MAY ignore some or all restrictions + * which otherwise limit the current user's access. + */ + default UserContext getPrivileged() { + return this; + } + } From 4e8c9e1cb7fb6f86d1753a32936091ad09cf39ac Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 17 Feb 2019 20:54:40 -0800 Subject: [PATCH 2/5] GUACAMOLE-708: Remove requirement for users to have UPDATE permission on themselves for TOTP to work. --- .../guacamole/auth/totp/user/UserVerificationService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 a73d08f96..e0cd84b3d 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 @@ -181,12 +181,13 @@ public class UserVerificationService { // Update user object try { - context.getUserDirectory().update(self); + context.getPrivileged().getUserDirectory().update(self); } catch (GuacamoleSecurityException e) { logger.info("User \"{}\" cannot store their TOTP key as they " - + "lack permission to update their own account. TOTP " - + "will be disabled for this user.", + + "lack permission to update their own account and the " + + "TOTP extension was unable to obtain privileged access. " + + "TOTP will be disabled for this user.", self.getIdentifier()); logger.debug("Permission denied to set TOTP key of user " + "account.", e); From 6f37e5d07db637b420e664b41d8ef122a24214d2 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 16 Jun 2020 16:35:34 -0700 Subject: [PATCH 3/5] GUACAMOLE-708: Replace isAdministrator() checks with more generic isPrivileged(). --- .../ActiveConnectionPermissionService.java | 9 +++++---- .../ActiveConnectionService.java | 4 ++-- .../ModeledChildDirectoryObjectService.java | 2 +- .../base/ModeledDirectoryObjectService.java | 8 ++++---- .../auth/jdbc/base/ModeledPermissions.java | 16 +++++++++------- .../auth/jdbc/base/RelatedObjectSet.java | 4 ++-- .../jdbc/connection/ConnectionService.java | 4 ++-- .../ConnectionGroupService.java | 2 +- .../permission/AbstractPermissionService.java | 2 +- .../ModeledObjectPermissionService.java | 4 ++-- .../permission/SystemPermissionService.java | 4 ++-- .../AbstractGuacamoleTunnelService.java | 2 +- .../jdbc/user/ModeledAuthenticatedUser.java | 19 +++++++++++++++++++ .../guacamole/auth/jdbc/user/UserService.java | 4 ++-- 14 files changed, 53 insertions(+), 31 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java index 1e525710d..fc21a5abb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java @@ -82,21 +82,22 @@ public class ActiveConnectionPermissionService // Retrieve permissions only if allowed if (canReadPermissions(user, targetEntity)) { - // Only administrators may access active connections - boolean isAdmin = targetEntity.isAdministrator(); + // Administrators may always access active connections + boolean isAdmin = targetEntity.isPrivileged(); // Get all active connections Collection records = tunnelService.getActiveConnections(user); // We have READ, and possibly DELETE, on all active connections - Set permissions = new HashSet(); + Set permissions = new HashSet<>(); for (ActiveConnectionRecord record : records) { // Add implicit READ String identifier = record.getUUID().toString(); permissions.add(new ObjectPermission(ObjectPermission.Type.READ, identifier)); - // If we're an admin, or the connection is ours, then we can DELETE + // If the target use is an admin, or the connection belongs to + // the target user, then they can DELETE if (isAdmin || targetEntity.isUser(record.getUsername())) permissions.add(new ObjectPermission(ObjectPermission.Type.DELETE, identifier)); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java index c21e9c36c..da5e0ccf9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java @@ -81,7 +81,7 @@ public class ActiveConnectionService Collection identifiers) throws GuacamoleException { String username = user.getIdentifier(); - boolean isAdmin = user.getUser().isAdministrator(); + boolean isAdmin = user.isPrivileged(); Set identifierSet = new HashSet(identifiers); // Retrieve all visible connections (permissions enforced by tunnel service) @@ -211,7 +211,7 @@ public class ActiveConnectionService ObjectPermissionSet permissionSet = getPermissionSet(user); - return user.getUser().isAdministrator() + return user.isPrivileged() || permissionSet.hasPermission(type, identifier); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java index f517e2788..220f55c15 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java @@ -149,7 +149,7 @@ public abstract class ModeledChildDirectoryObjectService objects; // Bypass permission checks if the user is a system admin - if (user.getUser().isAdministrator()) + if (user.isPrivileged()) objects = getObjectMapper().select(identifiers); // Otherwise only return explicitly readable identifiers @@ -508,7 +508,7 @@ public abstract class ModeledDirectoryObjectService } /** - * Returns whether this entity is a system administrator, and thus is not - * restricted by permissions, taking into account permission inheritance - * via user groups. + * Returns whether this entity is effectively unrestricted by permissions, + * such as a system administrator or an internal user operating via a + * privileged UserContext. Permission inheritance via user groups is taken + * into account. * * @return - * true if this entity is a system administrator, false otherwise. + * true if this entity should be unrestricted by permissions, false + * otherwise. * * @throws GuacamoleException - * If an error occurs while determining the entity's system administrator - * status. + * If an error occurs while determining whether permission restrictions + * apply to the entity. */ - public boolean isAdministrator() throws GuacamoleException { + public boolean isPrivileged() throws GuacamoleException { SystemPermissionSet systemPermissionSet = getEffective().getSystemPermissions(); return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java index f7b75ef12..3de857329 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java @@ -141,7 +141,7 @@ public abstract class RelatedObjectSet searchResults; // Bypass permission checks if the user is a system admin - if (user.getUser().isAdministrator()) + if (user.isPrivileged()) searchResults = connectionRecordMapper.search(requiredContents, sortPredicates, limit); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java index 3e9ec72a8..32d9f8c13 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java @@ -219,7 +219,7 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService permissions) throws GuacamoleException { // Only an admin can create system permissions - if (user.getUser().isAdministrator()) { + if (user.isPrivileged()) { Collection models = getModelInstances(targetEntity, permissions); systemPermissionMapper.insert(models); return; @@ -112,7 +112,7 @@ public class SystemPermissionService Collection permissions) throws GuacamoleException { // Only an admin can delete system permissions - if (user.getUser().isAdministrator()) { + if (user.isPrivileged()) { // Do not allow users to remove their own admin powers if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier())) 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 abecf32f8..1b8dd1762 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 @@ -629,7 +629,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS return Collections.emptyList(); // A system administrator can view all connections; no need to filter - if (user.getUser().isAdministrator()) + if (user.isPrivileged()) return records; // Build set of all connection identifiers associated with active tunnels 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 5778ad01a..7ede92c6c 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 @@ -23,6 +23,7 @@ import com.google.common.collect.Sets; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Credentials; @@ -176,4 +177,22 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser { super.getEffectiveUserGroups()); } + /** + * Returns whether this user is effectively unrestricted by permissions, + * such as a system administrator or an internal user operating via a + * privileged UserContext. Permission inheritance via user groups is taken + * into account. + * + * @return + * true if this user should be unrestricted by permissions, false + * otherwise. + * + * @throws GuacamoleException + * If an error occurs while determining whether permission restrictions + * apply to the user. + */ + public boolean isPrivileged() throws GuacamoleException { + return getUser().isPrivileged(); + } + } 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 a68f08237..dbbffe35e 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 @@ -279,7 +279,7 @@ public class UserService extends ModeledDirectoryObjectService searchResults; // Bypass permission checks if the user is a system admin - if (user.getUser().isAdministrator()) + if (user.isPrivileged()) searchResults = userRecordMapper.search(requiredContents, sortPredicates, limit); From 0b2269f1eab6a3ab3e2a3d6a6c32bf5dc934a65c Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 16 Jun 2020 20:07:58 -0700 Subject: [PATCH 4/5] GUACAMOLE-708: Add support for getPrivileged() to JDBC UserContext. --- .../JDBCAuthenticationProviderService.java | 1 + .../auth/jdbc/user/ModeledUserContext.java | 49 +++++++++++++++--- .../PrivilegedModeledAuthenticatedUser.java | 50 +++++++++++++++++++ 3 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/PrivilegedModeledAuthenticatedUser.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java index 646bf20d3..1bb2c68e7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java @@ -139,6 +139,7 @@ public class JDBCAuthenticationProviderService implements AuthenticationProvider // Initialize the UserContext with the user account and return it. context.init(user.getCurrentUser()); + context.recordUserLogin(); return context; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java index e98a25a04..fe60a5faf 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java @@ -48,6 +48,7 @@ import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.User; +import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserGroup; /** @@ -117,6 +118,12 @@ public class ModeledUserContext extends RestrictedObject @Inject private Provider userRecordSetProvider; + /** + * Provider for retrieving UserContext instances. + */ + @Inject + private Provider userContextProvider; + /** * Mapper for user login records. */ @@ -124,7 +131,10 @@ public class ModeledUserContext extends RestrictedObject private UserRecordMapper userRecordMapper; /** - * The activity record associated with this user's Guacamole session. + * The activity record associated with this user's Guacamole session. If + * this user's session will not have an associated activity record, such as + * a temporary privileged session created via getPrivileged(), this will be + * null. */ private ActivityRecordModel userRecord; @@ -141,15 +151,40 @@ public class ModeledUserContext extends RestrictedObject sharingProfileDirectory.init(currentUser); activeConnectionDirectory.init(currentUser); + } + + /** + * Records that the user associated with this UserContext has logged in, + * creating a partial activity record. The resulting activity record will + * contain a start date only, with the end date being automatically + * populated when this UserContext is invalidated. If this function is + * invoked more than once for the same UserContext, only the first + * invocation has any effect. If this function is never invoked, no + * activity record will be recorded, including when this UserContext is + * invalidated. + */ + public void recordUserLogin() { + + // Do nothing if invoked multiple times + if (userRecord != null) + return; + // Create login record for user userRecord = new ActivityRecordModel(); - userRecord.setUsername(currentUser.getIdentifier()); + userRecord.setUsername(getCurrentUser().getIdentifier()); userRecord.setStartDate(new Date()); - userRecord.setRemoteHost(currentUser.getCredentials().getRemoteAddress()); + userRecord.setRemoteHost(getCurrentUser().getCredentials().getRemoteAddress()); // Insert record representing login userRecordMapper.insert(userRecord); + + } + @Override + public UserContext getPrivileged() { + ModeledUserContext context = userContextProvider.get(); + context.init(new PrivilegedModeledAuthenticatedUser(getCurrentUser())); + return context; } @Override @@ -253,9 +288,11 @@ public class ModeledUserContext extends RestrictedObject @Override public void invalidate() { - // Record logout time - userRecord.setEndDate(new Date()); - userRecordMapper.update(userRecord); + // Record logout time only if login time was recorded + if (userRecord != null) { + userRecord.setEndDate(new Date()); + userRecordMapper.update(userRecord); + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/PrivilegedModeledAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/PrivilegedModeledAuthenticatedUser.java new file mode 100644 index 000000000..82fcf0852 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/PrivilegedModeledAuthenticatedUser.java @@ -0,0 +1,50 @@ +/* + * 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.jdbc.user; + +import org.apache.guacamole.GuacamoleException; + +/** + * A ModeledAuthenticatedUser which is always privileged, returning true for + * every call to isPrivileged(). + */ +public class PrivilegedModeledAuthenticatedUser extends ModeledAuthenticatedUser { + + /** + * Creates a new PrivilegedModeledAuthenticatedUser which shares the same + * user identity as the given ModeledAuthenticatedUser. Regardless of the + * privileges explicitly granted to the given user, the resulting + * PrivilegedModeledAuthenticatedUser will always assert that it is + * privileged. + * + * @param authenticatedUser + * The ModeledAuthenticatedUser that declares the identity of the user + * in question. + */ + public PrivilegedModeledAuthenticatedUser(ModeledAuthenticatedUser authenticatedUser){ + super(authenticatedUser, authenticatedUser.getModelAuthenticationProvider(), authenticatedUser.getUser()); + } + + @Override + public boolean isPrivileged() throws GuacamoleException { + return true; + } + +} From c7ba1e65d3aac20bb31ddb42f9f8f195a2811f12 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 17 Jun 2020 21:43:42 -0700 Subject: [PATCH 5/5] GUACAMOLE-708: Update comments to reflect generalization of privileged access beyond administrators. --- .../ActiveConnectionPermissionService.java | 11 ++++++----- .../activeconnection/ActiveConnectionService.java | 4 ++-- .../jdbc/base/ModeledChildDirectoryObjectService.java | 2 +- .../auth/jdbc/base/ModeledDirectoryObjectService.java | 4 ++-- .../guacamole/auth/jdbc/base/RelatedObjectSet.java | 5 +++-- .../auth/jdbc/connection/ConnectionService.java | 4 ++-- .../jdbc/connectiongroup/ConnectionGroupService.java | 2 +- .../jdbc/permission/AbstractPermissionService.java | 2 +- .../permission/ModeledObjectPermissionService.java | 4 ++-- .../auth/jdbc/permission/SystemPermissionService.java | 6 ++++-- .../jdbc/tunnel/AbstractGuacamoleTunnelService.java | 3 ++- .../apache/guacamole/auth/jdbc/user/UserService.java | 4 ++-- 12 files changed, 28 insertions(+), 23 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java index fc21a5abb..2a4cd9ee5 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java @@ -82,8 +82,9 @@ public class ActiveConnectionPermissionService // Retrieve permissions only if allowed if (canReadPermissions(user, targetEntity)) { - // Administrators may always access active connections - boolean isAdmin = targetEntity.isPrivileged(); + // Privileged accounts (such as administrators or UserContexts + // returned by getPrivileged()) may always access active connections + boolean isPrivileged = targetEntity.isPrivileged(); // Get all active connections Collection records = tunnelService.getActiveConnections(user); @@ -96,9 +97,9 @@ public class ActiveConnectionPermissionService String identifier = record.getUUID().toString(); permissions.add(new ObjectPermission(ObjectPermission.Type.READ, identifier)); - // If the target use is an admin, or the connection belongs to - // the target user, then they can DELETE - if (isAdmin || targetEntity.isUser(record.getUsername())) + // If the target user is privileged, or the connection belongs + // to the target user, then they can DELETE + if (isPrivileged || targetEntity.isUser(record.getUsername())) permissions.add(new ObjectPermission(ObjectPermission.Type.DELETE, identifier)); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java index da5e0ccf9..046cee1e2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java @@ -81,7 +81,7 @@ public class ActiveConnectionService Collection identifiers) throws GuacamoleException { String username = user.getIdentifier(); - boolean isAdmin = user.isPrivileged(); + boolean isPrivileged = user.isPrivileged(); Set identifierSet = new HashSet(identifiers); // Retrieve all visible connections (permissions enforced by tunnel service) @@ -95,7 +95,7 @@ public class ActiveConnectionService // be able to connect to (join) the active connection if they are // the user that started the connection OR the user is an admin boolean hasPrivilegedAccess = - isAdmin || username.equals(record.getUsername()); + isPrivileged || username.equals(record.getUsername()); // Add connection if within requested identifiers if (identifierSet.contains(record.getUUID().toString())) { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java index 220f55c15..76903134c 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java @@ -148,7 +148,7 @@ public abstract class ModeledChildDirectoryObjectService objects; - // Bypass permission checks if the user is a system admin + // Bypass permission checks if the user is privileged if (user.isPrivileged()) objects = getObjectMapper().select(identifiers); @@ -507,7 +507,7 @@ public abstract class ModeledDirectoryObjectService getIdentifiers(ModeledAuthenticatedUser user) throws GuacamoleException { - // Bypass permission checks if the user is a system admin + // Bypass permission checks if the user is privileged if (user.isPrivileged()) return getObjectMapper().selectIdentifiers(); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java index 3de857329..810e9a5f1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java @@ -140,7 +140,8 @@ public abstract class RelatedObjectSet identifiers) throws GuacamoleException { - // System administrators may alter any relations + // Privileged users (such as system administrators) may alter any + // relations if (getCurrentUser().isPrivileged()) return true; @@ -162,7 +163,7 @@ public abstract class RelatedObjectSet getObjects() throws GuacamoleException { - // Bypass permission checks if the user is a system admin + // Bypass permission checks if the user is a privileged ModeledAuthenticatedUser user = getCurrentUser(); if (user.isPrivileged()) return getObjectRelationMapper().selectChildIdentifiers(parent.getModel()); 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 98c71db7c..926df32fa 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 @@ -297,7 +297,7 @@ public class ConnectionService extends ModeledChildDirectoryObjectService searchResults; - // Bypass permission checks if the user is a system admin + // Bypass permission checks if the user is privileged if (user.isPrivileged()) searchResults = connectionRecordMapper.search(requiredContents, sortPredicates, limit); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java index 32d9f8c13..dbf7793ec 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java @@ -218,7 +218,7 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService permissions) throws GuacamoleException { - // A system adminstrator can do anything + // Privileged users (such as system administrators) may do anything if (user.isPrivileged()) return true; @@ -187,7 +187,7 @@ public abstract class ModeledObjectPermissionService if (identifiers.isEmpty()) return identifiers; - // If user is an admin, everything is accessible + // Privileged users (such as system administrators) may access everything if (user.isPrivileged()) return identifiers; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java index c33242e5d..4b8269f6b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java @@ -94,7 +94,8 @@ public class SystemPermissionService ModeledPermissions targetEntity, Collection permissions) throws GuacamoleException { - // Only an admin can create system permissions + // Only privileged users (such as system administrators) can create + // system permissions if (user.isPrivileged()) { Collection models = getModelInstances(targetEntity, permissions); systemPermissionMapper.insert(models); @@ -111,7 +112,8 @@ public class SystemPermissionService ModeledPermissions targetEntity, Collection permissions) throws GuacamoleException { - // Only an admin can delete system permissions + // Only privileged users (such as system administrators) can delete + // system permissions if (user.isPrivileged()) { // Do not allow users to remove their own admin powers 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 1b8dd1762..383ef3a9b 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 @@ -628,7 +628,8 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS if (records.isEmpty()) return Collections.emptyList(); - // A system administrator can view all connections; no need to filter + // Privileged users (such as system administrators) can view all + // connections; no need to filter if (user.isPrivileged()) return records; 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 dbbffe35e..0aecd10fa 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 @@ -278,7 +278,7 @@ public class UserService extends ModeledDirectoryObjectService searchResults; - // Bypass permission checks if the user is a system admin + // Bypass permission checks if the user is privileged if (user.isPrivileged()) searchResults = userRecordMapper.search(requiredContents, sortPredicates, limit);