mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-708: Merge add API for exposing privileged access to extensions.
This commit is contained in:
@@ -139,6 +139,7 @@ public class JDBCAuthenticationProviderService implements AuthenticationProvider
|
|||||||
|
|
||||||
// Initialize the UserContext with the user account and return it.
|
// Initialize the UserContext with the user account and return it.
|
||||||
context.init(user.getCurrentUser());
|
context.init(user.getCurrentUser());
|
||||||
|
context.recordUserLogin();
|
||||||
return context;
|
return context;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -82,22 +82,24 @@ public class ActiveConnectionPermissionService
|
|||||||
// Retrieve permissions only if allowed
|
// Retrieve permissions only if allowed
|
||||||
if (canReadPermissions(user, targetEntity)) {
|
if (canReadPermissions(user, targetEntity)) {
|
||||||
|
|
||||||
// Only administrators may access active connections
|
// Privileged accounts (such as administrators or UserContexts
|
||||||
boolean isAdmin = targetEntity.isAdministrator();
|
// returned by getPrivileged()) may always access active connections
|
||||||
|
boolean isPrivileged = targetEntity.isPrivileged();
|
||||||
|
|
||||||
// Get all active connections
|
// Get all active connections
|
||||||
Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
|
Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
|
||||||
|
|
||||||
// We have READ, and possibly DELETE, on all active connections
|
// We have READ, and possibly DELETE, on all active connections
|
||||||
Set<ObjectPermission> permissions = new HashSet<ObjectPermission>();
|
Set<ObjectPermission> permissions = new HashSet<>();
|
||||||
for (ActiveConnectionRecord record : records) {
|
for (ActiveConnectionRecord record : records) {
|
||||||
|
|
||||||
// Add implicit READ
|
// Add implicit READ
|
||||||
String identifier = record.getUUID().toString();
|
String identifier = record.getUUID().toString();
|
||||||
permissions.add(new ObjectPermission(ObjectPermission.Type.READ, identifier));
|
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 user is privileged, or the connection belongs
|
||||||
if (isAdmin || targetEntity.isUser(record.getUsername()))
|
// to the target user, then they can DELETE
|
||||||
|
if (isPrivileged || targetEntity.isUser(record.getUsername()))
|
||||||
permissions.add(new ObjectPermission(ObjectPermission.Type.DELETE, identifier));
|
permissions.add(new ObjectPermission(ObjectPermission.Type.DELETE, identifier));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -81,7 +81,7 @@ public class ActiveConnectionService
|
|||||||
Collection<String> identifiers) throws GuacamoleException {
|
Collection<String> identifiers) throws GuacamoleException {
|
||||||
|
|
||||||
String username = user.getIdentifier();
|
String username = user.getIdentifier();
|
||||||
boolean isAdmin = user.getUser().isAdministrator();
|
boolean isPrivileged = user.isPrivileged();
|
||||||
Set<String> identifierSet = new HashSet<String>(identifiers);
|
Set<String> identifierSet = new HashSet<String>(identifiers);
|
||||||
|
|
||||||
// Retrieve all visible connections (permissions enforced by tunnel service)
|
// 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
|
// be able to connect to (join) the active connection if they are
|
||||||
// the user that started the connection OR the user is an admin
|
// the user that started the connection OR the user is an admin
|
||||||
boolean hasPrivilegedAccess =
|
boolean hasPrivilegedAccess =
|
||||||
isAdmin || username.equals(record.getUsername());
|
isPrivileged || username.equals(record.getUsername());
|
||||||
|
|
||||||
// Add connection if within requested identifiers
|
// Add connection if within requested identifiers
|
||||||
if (identifierSet.contains(record.getUUID().toString())) {
|
if (identifierSet.contains(record.getUUID().toString())) {
|
||||||
@@ -211,7 +211,7 @@ public class ActiveConnectionService
|
|||||||
|
|
||||||
ObjectPermissionSet permissionSet = getPermissionSet(user);
|
ObjectPermissionSet permissionSet = getPermissionSet(user);
|
||||||
|
|
||||||
return user.getUser().isAdministrator()
|
return user.isPrivileged()
|
||||||
|| permissionSet.hasPermission(type, identifier);
|
|| permissionSet.hasPermission(type, identifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -148,8 +148,8 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
|
|||||||
protected boolean canUpdateModifiedParents(ModeledAuthenticatedUser user,
|
protected boolean canUpdateModifiedParents(ModeledAuthenticatedUser user,
|
||||||
String identifier, ModelType model) throws GuacamoleException {
|
String identifier, ModelType model) throws GuacamoleException {
|
||||||
|
|
||||||
// If user is an administrator, no need to check
|
// If user is privileged, no need to check
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Verify that we have permission to modify any modified parents
|
// Verify that we have permission to modify any modified parents
|
||||||
|
@@ -171,7 +171,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
|||||||
ObjectPermissionSet permissionSet = getEffectivePermissionSet(user);
|
ObjectPermissionSet permissionSet = getEffectivePermissionSet(user);
|
||||||
|
|
||||||
// Return whether permission is granted
|
// Return whether permission is granted
|
||||||
return user.getUser().isAdministrator()
|
return user.isPrivileged()
|
||||||
|| permissionSet.hasPermission(type, identifier);
|
|| permissionSet.hasPermission(type, identifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -248,7 +248,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
|||||||
ExternalType object, ModelType model) throws GuacamoleException {
|
ExternalType object, ModelType model) throws GuacamoleException {
|
||||||
|
|
||||||
// Verify permission to create objects
|
// Verify permission to create objects
|
||||||
if (!user.getUser().isAdministrator() && !hasCreatePermission(user))
|
if (!user.isPrivileged() && !hasCreatePermission(user))
|
||||||
throw new GuacamoleSecurityException("Permission denied.");
|
throw new GuacamoleSecurityException("Permission denied.");
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -395,8 +395,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
|||||||
|
|
||||||
Collection<ModelType> objects;
|
Collection<ModelType> objects;
|
||||||
|
|
||||||
// Bypass permission checks if the user is a system admin
|
// Bypass permission checks if the user is privileged
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
objects = getObjectMapper().select(identifiers);
|
objects = getObjectMapper().select(identifiers);
|
||||||
|
|
||||||
// Otherwise only return explicitly readable identifiers
|
// Otherwise only return explicitly readable identifiers
|
||||||
@@ -507,8 +507,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
|||||||
public Set<String> getIdentifiers(ModeledAuthenticatedUser user)
|
public Set<String> getIdentifiers(ModeledAuthenticatedUser user)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Bypass permission checks if the user is a system admin
|
// Bypass permission checks if the user is privileged
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
return getObjectMapper().selectIdentifiers();
|
return getObjectMapper().selectIdentifiers();
|
||||||
|
|
||||||
// Otherwise only return explicitly readable identifiers
|
// Otherwise only return explicitly readable identifiers
|
||||||
|
@@ -132,18 +132,20 @@ public abstract class ModeledPermissions<ModelType extends EntityModel>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether this entity is a system administrator, and thus is not
|
* Returns whether this entity is effectively unrestricted by permissions,
|
||||||
* restricted by permissions, taking into account permission inheritance
|
* such as a system administrator or an internal user operating via a
|
||||||
* via user groups.
|
* privileged UserContext. Permission inheritance via user groups is taken
|
||||||
|
* into account.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* true if this entity is a system administrator, false otherwise.
|
* true if this entity should be unrestricted by permissions, false
|
||||||
|
* otherwise.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs while determining the entity's system administrator
|
* If an error occurs while determining whether permission restrictions
|
||||||
* status.
|
* apply to the entity.
|
||||||
*/
|
*/
|
||||||
public boolean isAdministrator() throws GuacamoleException {
|
public boolean isPrivileged() throws GuacamoleException {
|
||||||
SystemPermissionSet systemPermissionSet = getEffective().getSystemPermissions();
|
SystemPermissionSet systemPermissionSet = getEffective().getSystemPermissions();
|
||||||
return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
|
return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
|
||||||
}
|
}
|
||||||
|
@@ -140,8 +140,9 @@ public abstract class RelatedObjectSet<ParentObjectType extends ModeledDirectory
|
|||||||
private boolean canAlterRelation(Collection<String> identifiers)
|
private boolean canAlterRelation(Collection<String> identifiers)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// System administrators may alter any relations
|
// Privileged users (such as system administrators) may alter any
|
||||||
if (getCurrentUser().getUser().isAdministrator())
|
// relations
|
||||||
|
if (getCurrentUser().isPrivileged())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Non-admin users require UPDATE permission on the parent object ...
|
// Non-admin users require UPDATE permission on the parent object ...
|
||||||
@@ -162,9 +163,9 @@ public abstract class RelatedObjectSet<ParentObjectType extends ModeledDirectory
|
|||||||
@Override
|
@Override
|
||||||
public Set<String> getObjects() throws GuacamoleException {
|
public Set<String> 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();
|
ModeledAuthenticatedUser user = getCurrentUser();
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
return getObjectRelationMapper().selectChildIdentifiers(parent.getModel());
|
return getObjectRelationMapper().selectChildIdentifiers(parent.getModel());
|
||||||
|
|
||||||
// Otherwise only return explicitly readable identifiers
|
// Otherwise only return explicitly readable identifiers
|
||||||
|
@@ -297,8 +297,8 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
|
|||||||
String identifier)
|
String identifier)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Bypass permission checks if the user is a system admin
|
// Bypass permission checks if the user is privileged
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
return connectionMapper.selectIdentifiersWithin(identifier);
|
return connectionMapper.selectIdentifiersWithin(identifier);
|
||||||
|
|
||||||
// Otherwise only return explicitly readable identifiers
|
// Otherwise only return explicitly readable identifiers
|
||||||
@@ -470,8 +470,8 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
|
|||||||
|
|
||||||
List<ConnectionRecordModel> searchResults;
|
List<ConnectionRecordModel> searchResults;
|
||||||
|
|
||||||
// Bypass permission checks if the user is a system admin
|
// Bypass permission checks if the user is privileged
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
searchResults = connectionRecordMapper.search(requiredContents,
|
searchResults = connectionRecordMapper.search(requiredContents,
|
||||||
sortPredicates, limit);
|
sortPredicates, limit);
|
||||||
|
|
||||||
|
@@ -218,8 +218,8 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService<M
|
|||||||
String identifier)
|
String identifier)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Bypass permission checks if the user is a system admin
|
// Bypass permission checks if the user is privileged
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
return connectionGroupMapper.selectIdentifiersWithin(identifier);
|
return connectionGroupMapper.selectIdentifiersWithin(identifier);
|
||||||
|
|
||||||
// Otherwise only return explicitly readable identifiers
|
// Otherwise only return explicitly readable identifiers
|
||||||
|
@@ -104,8 +104,8 @@ public abstract class AbstractPermissionService<PermissionSetType extends Permis
|
|||||||
if (targetEntity.isUser(user.getUser().getIdentifier()))
|
if (targetEntity.isUser(user.getUser().getIdentifier()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// A system adminstrator can do anything
|
// Privileged users (such as system administrators) may do anything
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Can read permissions on target entity if explicit READ is granted
|
// Can read permissions on target entity if explicit READ is granted
|
||||||
|
@@ -95,8 +95,8 @@ public abstract class ModeledObjectPermissionService
|
|||||||
Collection<ObjectPermission> permissions)
|
Collection<ObjectPermission> permissions)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// A system adminstrator can do anything
|
// Privileged users (such as system administrators) may do anything
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Verify user has update permission on the target entity
|
// Verify user has update permission on the target entity
|
||||||
@@ -187,8 +187,8 @@ public abstract class ModeledObjectPermissionService
|
|||||||
if (identifiers.isEmpty())
|
if (identifiers.isEmpty())
|
||||||
return identifiers;
|
return identifiers;
|
||||||
|
|
||||||
// If user is an admin, everything is accessible
|
// Privileged users (such as system administrators) may access everything
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
return identifiers;
|
return identifiers;
|
||||||
|
|
||||||
// Otherwise, return explicitly-retrievable identifiers only if allowed
|
// Otherwise, return explicitly-retrievable identifiers only if allowed
|
||||||
|
@@ -94,8 +94,9 @@ public class SystemPermissionService
|
|||||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||||
Collection<SystemPermission> permissions) throws GuacamoleException {
|
Collection<SystemPermission> permissions) throws GuacamoleException {
|
||||||
|
|
||||||
// Only an admin can create system permissions
|
// Only privileged users (such as system administrators) can create
|
||||||
if (user.getUser().isAdministrator()) {
|
// system permissions
|
||||||
|
if (user.isPrivileged()) {
|
||||||
Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions);
|
Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions);
|
||||||
systemPermissionMapper.insert(models);
|
systemPermissionMapper.insert(models);
|
||||||
return;
|
return;
|
||||||
@@ -111,8 +112,9 @@ public class SystemPermissionService
|
|||||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||||
Collection<SystemPermission> permissions) throws GuacamoleException {
|
Collection<SystemPermission> permissions) throws GuacamoleException {
|
||||||
|
|
||||||
// Only an admin can delete system permissions
|
// Only privileged users (such as system administrators) can delete
|
||||||
if (user.getUser().isAdministrator()) {
|
// system permissions
|
||||||
|
if (user.isPrivileged()) {
|
||||||
|
|
||||||
// Do not allow users to remove their own admin powers
|
// Do not allow users to remove their own admin powers
|
||||||
if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier()))
|
if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier()))
|
||||||
|
@@ -628,8 +628,9 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
|||||||
if (records.isEmpty())
|
if (records.isEmpty())
|
||||||
return Collections.<ActiveConnectionRecord>emptyList();
|
return Collections.<ActiveConnectionRecord>emptyList();
|
||||||
|
|
||||||
// A system administrator can view all connections; no need to filter
|
// Privileged users (such as system administrators) can view all
|
||||||
if (user.getUser().isAdministrator())
|
// connections; no need to filter
|
||||||
|
if (user.isPrivileged())
|
||||||
return records;
|
return records;
|
||||||
|
|
||||||
// Build set of all connection identifiers associated with active tunnels
|
// Build set of all connection identifiers associated with active tunnels
|
||||||
|
@@ -23,6 +23,7 @@ import com.google.common.collect.Sets;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
import org.apache.guacamole.net.auth.Credentials;
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
@@ -176,4 +177,22 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
|
|||||||
super.getEffectiveUserGroups());
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -48,6 +48,7 @@ import org.apache.guacamole.net.auth.ConnectionGroup;
|
|||||||
import org.apache.guacamole.net.auth.Directory;
|
import org.apache.guacamole.net.auth.Directory;
|
||||||
import org.apache.guacamole.net.auth.SharingProfile;
|
import org.apache.guacamole.net.auth.SharingProfile;
|
||||||
import org.apache.guacamole.net.auth.User;
|
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.UserGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,6 +118,12 @@ public class ModeledUserContext extends RestrictedObject
|
|||||||
@Inject
|
@Inject
|
||||||
private Provider<UserRecordSet> userRecordSetProvider;
|
private Provider<UserRecordSet> userRecordSetProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for retrieving UserContext instances.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private Provider<ModeledUserContext> userContextProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapper for user login records.
|
* Mapper for user login records.
|
||||||
*/
|
*/
|
||||||
@@ -124,7 +131,10 @@ public class ModeledUserContext extends RestrictedObject
|
|||||||
private UserRecordMapper userRecordMapper;
|
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;
|
private ActivityRecordModel userRecord;
|
||||||
|
|
||||||
@@ -141,15 +151,40 @@ public class ModeledUserContext extends RestrictedObject
|
|||||||
sharingProfileDirectory.init(currentUser);
|
sharingProfileDirectory.init(currentUser);
|
||||||
activeConnectionDirectory.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
|
// Create login record for user
|
||||||
userRecord = new ActivityRecordModel();
|
userRecord = new ActivityRecordModel();
|
||||||
userRecord.setUsername(currentUser.getIdentifier());
|
userRecord.setUsername(getCurrentUser().getIdentifier());
|
||||||
userRecord.setStartDate(new Date());
|
userRecord.setStartDate(new Date());
|
||||||
userRecord.setRemoteHost(currentUser.getCredentials().getRemoteAddress());
|
userRecord.setRemoteHost(getCurrentUser().getCredentials().getRemoteAddress());
|
||||||
|
|
||||||
// Insert record representing login
|
// Insert record representing login
|
||||||
userRecordMapper.insert(userRecord);
|
userRecordMapper.insert(userRecord);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserContext getPrivileged() {
|
||||||
|
ModeledUserContext context = userContextProvider.get();
|
||||||
|
context.init(new PrivilegedModeledAuthenticatedUser(getCurrentUser()));
|
||||||
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -253,9 +288,11 @@ public class ModeledUserContext extends RestrictedObject
|
|||||||
@Override
|
@Override
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
|
|
||||||
// Record logout time
|
// Record logout time only if login time was recorded
|
||||||
userRecord.setEndDate(new Date());
|
if (userRecord != null) {
|
||||||
userRecordMapper.update(userRecord);
|
userRecord.setEndDate(new Date());
|
||||||
|
userRecordMapper.update(userRecord);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -278,8 +278,8 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
|||||||
// Verify new password does not violate defined policies (if specified)
|
// Verify new password does not violate defined policies (if specified)
|
||||||
if (object.getPassword() != null) {
|
if (object.getPassword() != null) {
|
||||||
|
|
||||||
// Enforce password age only for non-adminstrators
|
// Enforce password age only for non-privileged users
|
||||||
if (!user.getUser().isAdministrator())
|
if (!user.isPrivileged())
|
||||||
passwordPolicyService.verifyPasswordAge(object);
|
passwordPolicyService.verifyPasswordAge(object);
|
||||||
|
|
||||||
// Always verify password complexity
|
// Always verify password complexity
|
||||||
@@ -626,8 +626,8 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
|||||||
|
|
||||||
List<ActivityRecordModel> searchResults;
|
List<ActivityRecordModel> searchResults;
|
||||||
|
|
||||||
// Bypass permission checks if the user is a system admin
|
// Bypass permission checks if the user is privileged
|
||||||
if (user.getUser().isAdministrator())
|
if (user.isPrivileged())
|
||||||
searchResults = userRecordMapper.search(requiredContents,
|
searchResults = userRecordMapper.search(requiredContents,
|
||||||
sortPredicates, limit);
|
sortPredicates, limit);
|
||||||
|
|
||||||
|
@@ -181,12 +181,13 @@ public class UserVerificationService {
|
|||||||
|
|
||||||
// Update user object
|
// Update user object
|
||||||
try {
|
try {
|
||||||
context.getUserDirectory().update(self);
|
context.getPrivileged().getUserDirectory().update(self);
|
||||||
}
|
}
|
||||||
catch (GuacamoleSecurityException e) {
|
catch (GuacamoleSecurityException e) {
|
||||||
logger.info("User \"{}\" cannot store their TOTP key as they "
|
logger.info("User \"{}\" cannot store their TOTP key as they "
|
||||||
+ "lack permission to update their own account. TOTP "
|
+ "lack permission to update their own account and the "
|
||||||
+ "will be disabled for this user.",
|
+ "TOTP extension was unable to obtain privileged access. "
|
||||||
|
+ "TOTP will be disabled for this user.",
|
||||||
self.getIdentifier());
|
self.getIdentifier());
|
||||||
logger.debug("Permission denied to set TOTP key of user "
|
logger.debug("Permission denied to set TOTP key of user "
|
||||||
+ "account.", e);
|
+ "account.", e);
|
||||||
|
@@ -254,4 +254,16 @@ public abstract class AbstractUserContext implements UserContext {
|
|||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* <p>This implementation simply returns <code>this</code>. Implementations
|
||||||
|
* that wish to provide additional privileges to extensions requesting
|
||||||
|
* privileged access should override this function.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public UserContext getPrivileged() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -152,4 +152,9 @@ public class DelegatingUserContext implements UserContext {
|
|||||||
userContext.invalidate();
|
userContext.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserContext getPrivileged() {
|
||||||
|
return userContext.getPrivileged();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -262,4 +262,29 @@ public interface UserContext {
|
|||||||
*/
|
*/
|
||||||
void invalidate();
|
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.
|
||||||
|
*
|
||||||
|
* <p>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.
|
||||||
|
*
|
||||||
|
* <p>A default implementation which simply returns <code>this</code> 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user