GUACAMOLE-1123: Merge standardization on ActivityRecordSet for history retrieval.

This commit is contained in:
Mike Jumper
2020-10-30 11:27:04 -07:00
committed by GitHub
29 changed files with 765 additions and 407 deletions

View File

@@ -48,7 +48,7 @@ public abstract class ModeledActivityRecordSet<RecordType extends ActivityRecord
* strings within the collection will be excluded from the results. * strings within the collection will be excluded from the results.
*/ */
private final Set<ActivityRecordSearchTerm> requiredContents = private final Set<ActivityRecordSearchTerm> requiredContents =
new HashSet<ActivityRecordSearchTerm>(); new HashSet<>();
/** /**
* The maximum number of history records that should be returned by a call * The maximum number of history records that should be returned by a call
@@ -62,7 +62,7 @@ public abstract class ModeledActivityRecordSet<RecordType extends ActivityRecord
* properties. * properties.
*/ */
private final List<ActivityRecordSortPredicate> sortPredicates = private final List<ActivityRecordSortPredicate> sortPredicates =
new ArrayList<ActivityRecordSortPredicate>(); new ArrayList<>();
/** /**
* Retrieves the history records matching the given criteria. Retrieves up * Retrieves the history records matching the given criteria. Retrieves up

View File

@@ -62,7 +62,11 @@ public interface ConnectionRecordMapper {
* the data they are associated with is is readable by any particular user. * the data they are associated with is is readable by any particular user.
* This should only be called on behalf of a system administrator. If * This should only be called on behalf of a system administrator. If
* records are needed by a non-administrative user who must have explicit * records are needed by a non-administrative user who must have explicit
* read rights, use searchReadable() instead. * read rights, use {@link searchReadable()} instead.
*
* @param identifier
* The optional connection identifier to which records should be limited,
* or null if all records should be retrieved.
* *
* @param terms * @param terms
* The search terms that must match the returned records. * The search terms that must match the returned records.
@@ -77,7 +81,8 @@ public interface ConnectionRecordMapper {
* @return * @return
* The results of the search performed with the given parameters. * The results of the search performed with the given parameters.
*/ */
List<ConnectionRecordModel> search(@Param("terms") Collection<ActivityRecordSearchTerm> terms, List<ConnectionRecordModel> search(@Param("identifier") String identifier,
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates, @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@Param("limit") int limit); @Param("limit") int limit);
@@ -86,7 +91,12 @@ public interface ConnectionRecordMapper {
* the given terms, sorted by the given predicates. Only records that are * the given terms, sorted by the given predicates. Only records that are
* associated with data explicitly readable by the given user will be * associated with data explicitly readable by the given user will be
* returned. If records are needed by a system administrator (who, by * returned. If records are needed by a system administrator (who, by
* definition, does not need explicit read rights), use search() instead. * definition, does not need explicit read rights), use {@link search()}
* instead.
*
* @param identifier
* The optional connection identifier for which records should be
* retrieved, or null if all readable records should be retrieved.
* *
* @param user * @param user
* The user whose permissions should determine whether a record is * The user whose permissions should determine whether a record is
@@ -111,7 +121,8 @@ public interface ConnectionRecordMapper {
* @return * @return
* The results of the search performed with the given parameters. * The results of the search performed with the given parameters.
*/ */
List<ConnectionRecordModel> searchReadable(@Param("user") UserModel user, List<ConnectionRecordModel> searchReadable(@Param("identifier") String identifier,
@Param("user") UserModel user,
@Param("terms") Collection<ActivityRecordSearchTerm> terms, @Param("terms") Collection<ActivityRecordSearchTerm> terms,
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates, @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@Param("limit") int limit, @Param("limit") int limit,

View File

@@ -27,6 +27,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecordSet; import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecordSet;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.ConnectionRecord; import org.apache.guacamole.net.auth.ConnectionRecord;
@@ -43,6 +44,30 @@ public class ConnectionRecordSet extends ModeledActivityRecordSet<ConnectionReco
@Inject @Inject
private ConnectionService connectionService; private ConnectionService connectionService;
/**
* The identifier of the connection to which this record set should be
* limited, if any. If null, the set should contain all records readable
* by the user making the request.
*/
private String identifier = null;
/**
* Initializes this object, associating it with the current authenticated
* user and connection identifier.
*
* @param currentUser
* The user that created or retrieved this object.
*
* @param identifier
* The connection identifier to which this record set should be limited,
* or null if the record set should contain all records readable by the
* currentUser.
*/
protected void init(ModeledAuthenticatedUser currentUser, String identifier) {
super.init(currentUser);
this.identifier = identifier;
}
@Override @Override
protected Collection<ConnectionRecord> retrieveHistory( protected Collection<ConnectionRecord> retrieveHistory(
AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents, AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents,
@@ -50,7 +75,7 @@ public class ConnectionRecordSet extends ModeledActivityRecordSet<ConnectionReco
throws GuacamoleException { throws GuacamoleException {
// Retrieve history from database // Retrieve history from database
return connectionService.retrieveHistory(getCurrentUser(), return connectionService.retrieveHistory(identifier, getCurrentUser(),
requiredContents, sortPredicates, limit); requiredContents, sortPredicates, limit);
} }

View File

@@ -213,7 +213,7 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
Map<String, String> parameters = connection.getConfiguration().getParameters(); Map<String, String> parameters = connection.getConfiguration().getParameters();
// Convert parameters to model objects // Convert parameters to model objects
Collection<ConnectionParameterModel> parameterModels = new ArrayList<ConnectionParameterModel>(parameters.size()); Collection<ConnectionParameterModel> parameterModels = new ArrayList<>(parameters.size());
for (Map.Entry<String, String> parameterEntry : parameters.entrySet()) { for (Map.Entry<String, String> parameterEntry : parameters.entrySet()) {
// Get parameter name and value // Get parameter name and value
@@ -329,7 +329,7 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
public Map<String, String> retrieveParameters(ModeledAuthenticatedUser user, public Map<String, String> retrieveParameters(ModeledAuthenticatedUser user,
String identifier) { String identifier) {
Map<String, String> parameterMap = new HashMap<String, String>(); Map<String, String> parameterMap = new HashMap<>();
// Determine whether we have permission to read parameters // Determine whether we have permission to read parameters
boolean canRetrieveParameters; boolean canRetrieveParameters;
@@ -382,7 +382,7 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
protected List<ConnectionRecord> getObjectInstances(List<ConnectionRecordModel> models) { protected List<ConnectionRecord> getObjectInstances(List<ConnectionRecordModel> models) {
// Create new list of records by manually converting each model // Create new list of records by manually converting each model
List<ConnectionRecord> objects = new ArrayList<ConnectionRecord>(models.size()); List<ConnectionRecord> objects = new ArrayList<>(models.size());
for (ConnectionRecordModel model : models) for (ConnectionRecordModel model : models)
objects.add(getObjectInstance(model)); objects.add(getObjectInstance(model));
@@ -412,27 +412,69 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
String identifier = connection.getIdentifier(); String identifier = connection.getIdentifier();
// Retrieve history only if READ permission is granted // Get current active connections.
if (hasObjectPermission(user, identifier, ObjectPermission.Type.READ)) { List<ConnectionRecord> records = new ArrayList<>(tunnelService.getActiveConnections(connection));
Collections.reverse(records);
// Retrieve history // Add in the history records.
List<ConnectionRecordModel> models = connectionRecordMapper.select(identifier); records.addAll(retrieveHistory(identifier, user, Collections.emptyList(),
Collections.emptyList(), Integer.MAX_VALUE));
// Get currently-active connections return records;
List<ConnectionRecord> records = new ArrayList<ConnectionRecord>(tunnelService.getActiveConnections(connection));
Collections.reverse(records);
// Add past connections from model objects }
for (ConnectionRecordModel model : models)
records.add(getObjectInstance(model));
// Return converted history list /**
return records; * Retrieves the connection history records matching the given criteria.
* Retrieves up to <code>limit</code> connection history records matching
* the given terms and sorted by the given predicates. Only history records
* associated with data that the given user can read are returned.
*
* @param identifier
* The optional connection identifier for which history records should
* be retrieved, or null if all readable records should be retrieved.
*
* @param user
* The user retrieving the connection history.
*
* @param requiredContents
* The search terms that must be contained somewhere within each of the
* returned records.
*
* @param sortPredicates
* A list of predicates to sort the returned records by, in order of
* priority.
*
* @param limit
* The maximum number of records that should be returned.
*
* @return
* The connection history of the given connection, including any
* active connections.
*
* @throws GuacamoleException
* If permission to read the connection history is denied.
*/
public List<ConnectionRecord> retrieveHistory(String identifier,
ModeledAuthenticatedUser user,
Collection<ActivityRecordSearchTerm> requiredContents,
List<ActivityRecordSortPredicate> sortPredicates, int limit)
throws GuacamoleException {
} List<ConnectionRecordModel> searchResults;
// The user does not have permission to read the history // Bypass permission checks if the user is privileged
throw new GuacamoleSecurityException("Permission denied."); if (user.isPrivileged())
searchResults = connectionRecordMapper.search(identifier, requiredContents,
sortPredicates, limit);
// Otherwise only return explicitly readable history records
else
searchResults = connectionRecordMapper.searchReadable(identifier,
user.getUser().getModel(), requiredContents, sortPredicates,
limit, user.getEffectiveUserGroups());
return getObjectInstances(searchResults);
} }
@@ -468,20 +510,7 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
List<ActivityRecordSortPredicate> sortPredicates, int limit) List<ActivityRecordSortPredicate> sortPredicates, int limit)
throws GuacamoleException { throws GuacamoleException {
List<ConnectionRecordModel> searchResults; return retrieveHistory(null, user, requiredContents, sortPredicates, limit);
// Bypass permission checks if the user is privileged
if (user.isPrivileged())
searchResults = connectionRecordMapper.search(requiredContents,
sortPredicates, limit);
// Otherwise only return explicitly readable history records
else
searchResults = connectionRecordMapper.searchReadable(
user.getUser().getModel(), requiredContents, sortPredicates,
limit, user.getEffectiveUserGroups());
return getObjectInstances(searchResults);
} }

View File

@@ -40,6 +40,7 @@ import org.apache.guacamole.form.Form;
import org.apache.guacamole.form.NumericField; import org.apache.guacamole.form.NumericField;
import org.apache.guacamole.form.TextField; import org.apache.guacamole.form.TextField;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.net.auth.ActivityRecordSet;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionRecord; import org.apache.guacamole.net.auth.ConnectionRecord;
import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration;
@@ -196,6 +197,12 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
@Inject @Inject
private Provider<ModeledGuacamoleConfiguration> configProvider; private Provider<ModeledGuacamoleConfiguration> configProvider;
/**
* Provider for creating connection record sets.
*/
@Inject
private Provider<ConnectionRecordSet> connectionRecordSetProvider;
/** /**
* The manually-set GuacamoleConfiguration, if any. * The manually-set GuacamoleConfiguration, if any.
*/ */
@@ -254,8 +261,11 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
} }
@Override @Override
public List<? extends ConnectionRecord> getHistory() throws GuacamoleException { public ActivityRecordSet<ConnectionRecord> getConnectionHistory()
return connectionService.retrieveHistory(getCurrentUser(), this); throws GuacamoleException {
ConnectionRecordSet connectionRecordSet = connectionRecordSetProvider.get();
connectionRecordSet.init(getCurrentUser(), this.getIdentifier());
return connectionRecordSet;
} }
@Override @Override

View File

@@ -22,7 +22,6 @@ package org.apache.guacamole.auth.jdbc.sharing.connection;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
@@ -31,7 +30,6 @@ import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionRecord;
import org.apache.guacamole.protocol.GuacamoleClientInformation; import org.apache.guacamole.protocol.GuacamoleClientInformation;
import org.apache.guacamole.protocol.GuacamoleConfiguration; import org.apache.guacamole.protocol.GuacamoleConfiguration;
@@ -152,12 +150,6 @@ public class SharedConnection implements Connection {
return null; return null;
} }
@Override
public List<? extends ConnectionRecord> getHistory()
throws GuacamoleException {
return Collections.<ConnectionRecord>emptyList();
}
@Override @Override
public Set<String> getSharingProfileIdentifiers() public Set<String> getSharingProfileIdentifiers()
throws GuacamoleException { throws GuacamoleException {

View File

@@ -21,11 +21,9 @@ package org.apache.guacamole.auth.jdbc.sharing.user;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.sharing.permission.SharedObjectPermissionSet; import org.apache.guacamole.auth.jdbc.sharing.permission.SharedObjectPermissionSet;
import org.apache.guacamole.net.auth.ActivityRecord;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
@@ -99,14 +97,6 @@ public class SharedUser implements User {
} }
@Override
public List<ActivityRecord> getHistory() throws GuacamoleException {
// History is not recorded for shared users
return Collections.<ActivityRecord>emptyList();
}
@Override @Override
public String getPassword() { public String getPassword() {
return null; return null;

View File

@@ -47,6 +47,7 @@ import org.apache.guacamole.form.TextField;
import org.apache.guacamole.form.TimeField; import org.apache.guacamole.form.TimeField;
import org.apache.guacamole.form.TimeZoneField; import org.apache.guacamole.form.TimeZoneField;
import org.apache.guacamole.net.auth.ActivityRecord; import org.apache.guacamole.net.auth.ActivityRecord;
import org.apache.guacamole.net.auth.ActivityRecordSet;
import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.RelatedObjectSet; import org.apache.guacamole.net.auth.RelatedObjectSet;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
@@ -183,6 +184,12 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
@Inject @Inject
private Provider<UserParentUserGroupSet> parentUserGroupSetProvider; private Provider<UserParentUserGroupSet> parentUserGroupSetProvider;
/**
* Provider for creating user record sets.
*/
@Inject
private Provider<UserRecordSet> userRecordSetProvider;
/** /**
* Whether attributes which control access restrictions should be exposed * Whether attributes which control access restrictions should be exposed
* via getAttributes() or allowed to be set via setAttributes(). * via getAttributes() or allowed to be set via setAttributes().
@@ -748,8 +755,11 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
} }
@Override @Override
public List<ActivityRecord> getHistory() throws GuacamoleException { public ActivityRecordSet<ActivityRecord> getUserHistory()
return userService.retrieveHistory(getCurrentUser(), this); throws GuacamoleException {
UserRecordSet userRecordSet = userRecordSetProvider.get();
userRecordSet.init(getCurrentUser(), this.getIdentifier());
return userRecordSet;
} }
@Override @Override

View File

@@ -73,7 +73,11 @@ public interface UserRecordMapper {
* the data they are associated with is is readable by any particular user. * the data they are associated with is is readable by any particular user.
* This should only be called on behalf of a system administrator. If * This should only be called on behalf of a system administrator. If
* records are needed by a non-administrative user who must have explicit * records are needed by a non-administrative user who must have explicit
* read rights, use searchReadable() instead. * read rights, use {@link searchReadable()} instead.
*
* @param username
* The optional username to which records should be limited, or null
* if all records should be retrieved.
* *
* @param terms * @param terms
* The search terms that must match the returned records. * The search terms that must match the returned records.
@@ -88,7 +92,8 @@ public interface UserRecordMapper {
* @return * @return
* The results of the search performed with the given parameters. * The results of the search performed with the given parameters.
*/ */
List<ActivityRecordModel> search(@Param("terms") Collection<ActivityRecordSearchTerm> terms, List<ActivityRecordModel> search(@Param("username") String username,
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates, @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@Param("limit") int limit); @Param("limit") int limit);
@@ -97,11 +102,16 @@ public interface UserRecordMapper {
* the given terms, sorted by the given predicates. Only records that are * the given terms, sorted by the given predicates. Only records that are
* associated with data explicitly readable by the given user will be * associated with data explicitly readable by the given user will be
* returned. If records are needed by a system administrator (who, by * returned. If records are needed by a system administrator (who, by
* definition, does not need explicit read rights), use search() instead. * definition, does not need explicit read rights), use {@link search()}
* instead.
*
* @param username
* The optional username to which records should be limited, or null
* if all readable records should be retrieved.
* *
* @param user * @param user
* The user whose permissions should determine whether a record is * The user whose permissions should determine whether a record is
* returned. * returned.
* *
* @param terms * @param terms
* The search terms that must match the returned records. * The search terms that must match the returned records.
@@ -122,7 +132,8 @@ public interface UserRecordMapper {
* @return * @return
* The results of the search performed with the given parameters. * The results of the search performed with the given parameters.
*/ */
List<ActivityRecordModel> searchReadable(@Param("user") UserModel user, List<ActivityRecordModel> searchReadable(@Param("username") String username,
@Param("user") UserModel user,
@Param("terms") Collection<ActivityRecordSearchTerm> terms, @Param("terms") Collection<ActivityRecordSearchTerm> terms,
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates, @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@Param("limit") int limit, @Param("limit") int limit,

View File

@@ -44,6 +44,31 @@ public class UserRecordSet extends ModeledActivityRecordSet<ActivityRecord> {
@Inject @Inject
private UserService userService; private UserService userService;
/**
* The identifier that indicates which user object these records should be
* limited to, if any. If null is specified (the default) then all records
* that are readable by the current user will be retrieved.
*/
private String identifier = null;
/**
* Initialize this UserRecordSet with currentUser requesting the login
* records, and, optionally, the identifier of the user to which records
* should be limited.
*
* @param currentUser
* The user requesting login history.
*
* @param identifier
* The identifier of the user whose login history should be contained
* in this record set, or null if the record set should contain all
* records readable by the currentUser.
*/
protected void init(ModeledAuthenticatedUser currentUser, String identifier) {
super.init(currentUser);
this.identifier = identifier;
}
@Override @Override
protected Collection<ActivityRecord> retrieveHistory( protected Collection<ActivityRecord> retrieveHistory(
AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents, AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents,
@@ -51,7 +76,7 @@ public class UserRecordSet extends ModeledActivityRecordSet<ActivityRecord> {
throws GuacamoleException { throws GuacamoleException {
// Retrieve history from database // Retrieve history from database
return userService.retrieveHistory(getCurrentUser(), return userService.retrieveHistory(identifier, getCurrentUser(),
requiredContents, sortPredicates, limit); requiredContents, sortPredicates, limit);
} }

View File

@@ -32,7 +32,6 @@ import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectService; import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectService;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel; import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
@@ -594,12 +593,61 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
String username = user.getIdentifier(); String username = user.getIdentifier();
// Retrieve history only if READ permission is granted return retrieveHistory(username, authenticatedUser, Collections.emptyList(),
if (hasObjectPermission(authenticatedUser, username, ObjectPermission.Type.READ)) Collections.emptyList(), Integer.MAX_VALUE);
return getObjectInstances(userRecordMapper.select(username));
// The user does not have permission to read the history }
throw new GuacamoleSecurityException("Permission denied.");
/**
* Retrieves user login history records matching the given criteria.
* Retrieves up to <code>limit</code> user history records matching the
* given terms and sorted by the given predicates. Only history records
* associated with data that the given user can read are returned.
*
* @param username
* The optional username to which history records should be limited, or
* null if all readable records should be retrieved.
*
* @param user
* The user retrieving the login history.
*
* @param requiredContents
* The search terms that must be contained somewhere within each of the
* returned records.
*
* @param sortPredicates
* A list of predicates to sort the returned records by, in order of
* priority.
*
* @param limit
* The maximum number of records that should be returned.
*
* @return
* The login history of the given user, including any active sessions.
*
* @throws GuacamoleException
* If permission to read the user login history is denied.
*/
public List<ActivityRecord> retrieveHistory(String username,
ModeledAuthenticatedUser user,
Collection<ActivityRecordSearchTerm> requiredContents,
List<ActivityRecordSortPredicate> sortPredicates, int limit)
throws GuacamoleException {
List<ActivityRecordModel> searchResults;
// Bypass permission checks if the user is privileged
if (user.isPrivileged())
searchResults = userRecordMapper.search(username, requiredContents,
sortPredicates, limit);
// Otherwise only return explicitly readable history records
else
searchResults = userRecordMapper.searchReadable(username,
user.getUser().getModel(),
requiredContents, sortPredicates, limit, user.getEffectiveUserGroups());
return getObjectInstances(searchResults);
} }
@@ -634,19 +682,7 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
List<ActivityRecordSortPredicate> sortPredicates, int limit) List<ActivityRecordSortPredicate> sortPredicates, int limit)
throws GuacamoleException { throws GuacamoleException {
List<ActivityRecordModel> searchResults; return retrieveHistory(null, user, requiredContents, sortPredicates, limit);
// Bypass permission checks if the user is privileged
if (user.isPrivileged())
searchResults = userRecordMapper.search(requiredContents,
sortPredicates, limit);
// Otherwise only return explicitly readable history records
else
searchResults = userRecordMapper.searchReadable(user.getUser().getModel(),
requiredContents, sortPredicates, limit, user.getEffectiveUserGroups());
return getObjectInstances(searchResults);
} }

View File

@@ -108,28 +108,35 @@
LEFT JOIN guacamole_user ON guacamole_connection_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user ON guacamole_connection_history.user_id = guacamole_user.user_id
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="identifier != null">
guacamole_connection_history.connection_id = #{identifier,jdbcType=VARCHAR}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
guacamole_connection_history.user_id IN (
SELECT user_id
FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
)
OR guacamole_connection_history.connection_id IN (
SELECT connection_id
FROM guacamole_connection
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
guacamole_connection_history.user_id IN (
SELECT user_id
FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
) )
</foreach>
OR guacamole_connection_history.connection_id IN ( </where>
SELECT connection_id
FROM guacamole_connection
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -186,31 +193,38 @@
AND guacamole_user_permission.permission = 'READ' AND guacamole_user_permission.permission = 'READ'
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="identifier != null">
guacamole_connection_history.connection_id = #{identifier,jdbcType=VARCHAR}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
guacamole_connection_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'
)
OR guacamole_connection_history.connection_id IN (
SELECT connection_id
FROM guacamole_connection
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
guacamole_connection_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'
) )
</foreach>
OR guacamole_connection_history.connection_id IN ( </where>
SELECT connection_id
FROM guacamole_connection
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -105,25 +105,32 @@
FROM guacamole_user_history FROM guacamole_user_history
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="username != null">
guacamole_user_history.username = #{username,jdbcType=VARCHAR}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
guacamole_user_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'),
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
guacamole_user_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'),
) )
</foreach>
<if test="term.startDate != null and term.endDate != null"> </where>
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -164,25 +171,32 @@
AND guacamole_user_permission.permission = 'READ' AND guacamole_user_permission.permission = 'READ'
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="username != null">
guacamole_entity.name = #{username,jdbcType=VARCHAR}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
guacamole_user_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
guacamole_user_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'
) )
</foreach>
<if test="term.startDate != null and term.endDate != null"> </where>
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -106,28 +106,35 @@
FROM guacamole_connection_history FROM guacamole_connection_history
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="identifier != null">
guacamole_connection_history.connection_id = #{identifier,jdbcType=INTEGER}::integer
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
guacamole_connection_history.user_id IN (
SELECT user_id
FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
)
OR guacamole_connection_history.connection_id IN (
SELECT connection_id
FROM guacamole_connection
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
guacamole_connection_history.user_id IN (
SELECT user_id
FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
) )
</foreach>
OR guacamole_connection_history.connection_id IN ( </where>
SELECT connection_id
FROM guacamole_connection
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -184,31 +191,38 @@
AND guacamole_user_permission.permission = 'READ' AND guacamole_user_permission.permission = 'READ'
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="identifier != null">
guacamole_connection_history.connection_id = #{identifier,jdbcType=INTEGER}::integer
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
guacamole_connection_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'::guacamole_entity_type
)
OR guacamole_connection_history.connection_id IN (
SELECT connection_id
FROM guacamole_connection
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
guacamole_connection_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'::guacamole_entity_type
) )
</foreach>
OR guacamole_connection_history.connection_id IN ( </where>
SELECT connection_id
FROM guacamole_connection
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -105,25 +105,32 @@
FROM guacamole_user_history FROM guacamole_user_history
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="username != null">
guacamole_user_history.username = #{username,jdbcType=VARCHAR}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
guacamole_user_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'::guacamole_entity_type),
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
guacamole_user_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'::guacamole_entity_type),
) )
</foreach>
<if test="term.startDate != null and term.endDate != null"> </where>
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -164,25 +171,31 @@
AND guacamole_user_permission.permission = 'READ' AND guacamole_user_permission.permission = 'READ'
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND "> <if test="username != null">
( guacamole_entity.name = #{username,jdbcType=VARCHAR}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
guacamole_user_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'::guacamole_entity_type
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
guacamole_user_history.user_id IN (
SELECT user_id
FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
AND guacamole_entity.type = 'USER'::guacamole_entity_type
) )
</foreach>
<if test="term.startDate != null and term.endDate != null"> </where>
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -106,28 +106,35 @@
FROM [guacamole_connection_history] FROM [guacamole_connection_history]
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="identifier != null">
[guacamole_connection_history].connection_id = #{identifier,jdbcType=INTEGER}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
[guacamole_connection_history].user_id IN (
SELECT user_id
FROM [guacamole_user]
WHERE CHARINDEX(#{term.term,jdbcType=VARCHAR}, username) > 0
)
OR [guacamole_connection_history].connection_id IN (
SELECT connection_id
FROM [guacamole_connection]
WHERE CHARINDEX(#{term.term,jdbcType=VARCHAR}, connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
[guacamole_connection_history].user_id IN (
SELECT user_id
FROM [guacamole_user]
WHERE CHARINDEX(#{term.term,jdbcType=VARCHAR}, username) > 0
) )
</foreach>
OR [guacamole_connection_history].connection_id IN ( </where>
SELECT connection_id
FROM [guacamole_connection]
WHERE CHARINDEX(#{term.term,jdbcType=VARCHAR}, connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -182,31 +189,38 @@
AND [guacamole_user_permission].permission = 'READ' AND [guacamole_user_permission].permission = 'READ'
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="identifier != null">
[guacamole_connection_history].connection_id = #{identifier,jdbcType=INTEGER}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
[guacamole_connection_history].user_id IN (
SELECT user_id
FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE
CHARINDEX(#{term.term,jdbcType=VARCHAR}, [guacamole_entity].name) > 0
AND [guacamole_entity].type = 'USER'
)
OR [guacamole_connection_history].connection_id IN (
SELECT connection_id
FROM [guacamole_connection]
WHERE CHARINDEX(#{term.term,jdbcType=VARCHAR}, connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
[guacamole_connection_history].user_id IN (
SELECT user_id
FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE
CHARINDEX(#{term.term,jdbcType=VARCHAR}, [guacamole_entity].name) > 0
AND [guacamole_entity].type = 'USER'
) )
</foreach>
OR [guacamole_connection_history].connection_id IN ( </where>
SELECT connection_id
FROM [guacamole_connection]
WHERE CHARINDEX(#{term.term,jdbcType=VARCHAR}, connection_name) > 0
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -105,25 +105,32 @@
FROM [guacamole_user_history] FROM [guacamole_user_history]
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="username != null">
[guacamole_user_history].username = #{username,jdbcType=VARCHAR}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
[guacamole_user_history].user_id IN (
SELECT user_id
FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE
CHARINDEX(#{term.term,jdbcType=VARCHAR}, [guacamole_entity].name) > 0
AND [guacamole_entity].type = 'USER'),
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
[guacamole_user_history].user_id IN (
SELECT user_id
FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE
CHARINDEX(#{term.term,jdbcType=VARCHAR}, [guacamole_entity].name) > 0
AND [guacamole_entity].type = 'USER'),
) )
</foreach>
<if test="term.startDate != null and term.endDate != null"> </where>
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -162,25 +169,32 @@
AND [guacamole_user_permission].permission = 'READ' AND [guacamole_user_permission].permission = 'READ'
<!-- Search terms --> <!-- Search terms -->
<foreach collection="terms" item="term" <where>
open="WHERE " separator=" AND ">
( <if test="username != null">
[guacamole_entity].name = #{username,jdbcType=VARCHAR}
</if>
<foreach collection="terms" item="term" open=" AND " separator=" AND ">
(
[guacamole_user_history].user_id IN (
SELECT user_id
FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE
CHARINDEX(#{term.term,jdbcType=VARCHAR}, [guacamole_entity].name) > 0
AND [guacamole_entity].type = 'USER'
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
[guacamole_user_history].user_id IN (
SELECT user_id
FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE
CHARINDEX(#{term.term,jdbcType=VARCHAR}, [guacamole_entity].name) > 0
AND [guacamole_entity].type = 'USER'
) )
</foreach>
<if test="term.startDate != null and term.endDate != null"> </where>
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
<!-- Bind sort property enum values for sake of readability --> <!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/> <bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -21,7 +21,6 @@ package org.apache.guacamole.net.auth;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
@@ -86,17 +85,6 @@ public abstract class AbstractUser extends AbstractIdentifiable
return null; return null;
} }
/**
* {@inheritDoc}
*
* <p>This implementation simply an immutable, empty list. Implementations
* that wish to expose user login history should override this function.
*/
@Override
public List<ActivityRecord> getHistory() throws GuacamoleException {
return Collections.emptyList();
}
/** /**
* {@inheritDoc} * {@inheritDoc}
* *

View File

@@ -19,10 +19,13 @@
package org.apache.guacamole.net.auth; package org.apache.guacamole.net.auth;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.protocol.GuacamoleConfiguration; import org.apache.guacamole.protocol.GuacamoleConfiguration;
/** /**
@@ -98,16 +101,55 @@ public interface Connection extends Identifiable, Connectable, Attributes {
* of this Connection, including any active users. ConnectionRecords * of this Connection, including any active users. ConnectionRecords
* in this list will be sorted in descending order of end time (active * in this list will be sorted in descending order of end time (active
* connections are first), and then in descending order of start time * connections are first), and then in descending order of start time
* (newer connections are first). * (newer connections are first). If connection history tracking is
* not implemented this method should throw GuacamoleUnsupportedException.
* *
* @return A list of ConnectionRecrods representing the usage history * @deprecated
* of this Connection. * This function has been deprecated in favor of
* {@link getConnectionHistory}, which returns the connection history
* as an ActivityRecordSet that can be easily sorted and filtered.
* While the getHistory() method is provided for API compatibility,
* new implementations should avoid use of this method and, instead,
* implement the getConnectionHistory() method.
* *
* @throws GuacamoleException If an error occurs while reading the history * @return
* of this connection, or if permission is * A list of ConnectionRecrods representing the usage history of this
* denied. * Connection.
*
* @throws GuacamoleException
* If history tracking is not implemented, if an error occurs while
* reading the history of this connection, or if permission is
* denied.
*/ */
public List<? extends ConnectionRecord> getHistory() throws GuacamoleException; @Deprecated
default List<? extends ConnectionRecord> getHistory()
throws GuacamoleException {
return Collections.unmodifiableList(new ArrayList<>(getConnectionHistory().asCollection()));
}
/**
* Returns an ActivityRecordSet containing ConnectionRecords that
* represent the usage history of this Connection, including any active
* users. ConnectionRecords in this list will be sorted in descending order
* of end time (active connections are first), and then in descending order
* of start time (newer connections are first). If connection history
* tracking has not been implemented, or has been implemented using the
* deprecated {@link getHistory} method, this function should throw
* GuacamoleUnsupportedExpcetion.
*
* @return
* An ActivityRecordSet containing ConnectionRecords representing the
* usage history of this Connection.
*
* @throws GuacamoleException
* If history tracking is not implemented, if an error occurs while
* reading the history of this connection, or if permission is
* denied.
*/
default ActivityRecordSet<ConnectionRecord> getConnectionHistory()
throws GuacamoleException {
throw new GuacamoleUnsupportedException("This implementation of Connection does not provide connection history.");
}
/** /**
* Returns identifiers of all readable sharing profiles that can be used to * Returns identifiers of all readable sharing profiles that can be used to

View File

@@ -134,12 +134,19 @@ public class DelegatingConnection implements Connection {
return connection.getLastActive(); return connection.getLastActive();
} }
@Deprecated
@Override @Override
public List<? extends ConnectionRecord> getHistory() public List<? extends ConnectionRecord> getHistory()
throws GuacamoleException { throws GuacamoleException {
return connection.getHistory(); return connection.getHistory();
} }
@Override
public ActivityRecordSet<ConnectionRecord> getConnectionHistory()
throws GuacamoleException {
return connection.getConnectionHistory();
}
@Override @Override
public Set<String> getSharingProfileIdentifiers() public Set<String> getSharingProfileIdentifiers()
throws GuacamoleException { throws GuacamoleException {

View File

@@ -93,12 +93,19 @@ public class DelegatingUser implements User {
return user.getLastActive(); return user.getLastActive();
} }
@Deprecated
@Override @Override
public List<? extends ActivityRecord> getHistory() public List<? extends ActivityRecord> getHistory()
throws GuacamoleException { throws GuacamoleException {
return user.getHistory(); return user.getHistory();
} }
@Override
public ActivityRecordSet<ActivityRecord> getUserHistory()
throws GuacamoleException {
return user.getUserHistory();
}
@Override @Override
public SystemPermissionSet getSystemPermissions() public SystemPermissionSet getSystemPermissions()
throws GuacamoleException { throws GuacamoleException {

View File

@@ -19,9 +19,12 @@
package org.apache.guacamole.net.auth; package org.apache.guacamole.net.auth;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
/** /**
* A user of the Guacamole web application. * A user of the Guacamole web application.
@@ -93,17 +96,50 @@ public interface User extends Identifiable, Attributes, Permissions {
* of this user, including any active sessions. ActivityRecords * of this user, including any active sessions. ActivityRecords
* in this list will be sorted in descending order of end time (active * in this list will be sorted in descending order of end time (active
* sessions are first), and then in descending order of start time * sessions are first), and then in descending order of start time
* (newer sessions are first). * (newer sessions are first). If user login history is not implemented
* this method should throw GuacamoleUnsupportedException.
*
* @deprecated
* This function is deprecated in favor of {@link getUserHistory}, which
* returns the login history as an ActivityRecordSet which supports
* various sort and filter functions. While this continues to be defined
* for API compatibility, new implementation should avoid this function
* and use getUserHistory(), instead.
* *
* @return * @return
* A list of ActivityRecords representing the login history of this * A list of ActivityRecords representing the login history of this
* User. * User.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while reading the history of this user, or if * If history tracking is not implemented, if an error occurs while
* permission is denied. * reading the history of this user, or if permission is denied.
*/ */
List<? extends ActivityRecord> getHistory() throws GuacamoleException; @Deprecated
default List<? extends ActivityRecord> getHistory() throws GuacamoleException {
return Collections.unmodifiableList(new ArrayList<>(getUserHistory().asCollection()));
}
/**
* Returns an ActivityRecordSet containing ActivityRecords representing
* the login history for this user, including any active sessions.
* ActivityRecords in this list will be sorted in descending order of end
* time (active sessions are first), and then in descending order of start
* time (newer sessions are first). If login history tracking is not
* implemented, or is only implemented using the deprecated {@link getHistory}
* method, this method should throw GuacamoleUnsupportedException.
*
* @return
* An ActivityRecordSet containing ActivityRecords representing the
* login history for this user.
*
* @throws GuacamoleException
* If history tracking is not implemented, if an error occurs while
* reading the history of this user, or if permission is denied.
*/
default ActivityRecordSet<ActivityRecord> getUserHistory()
throws GuacamoleException {
throw new GuacamoleUnsupportedException("The default implementation of User does not provide login history.");
}
/** /**
* Returns a set of all readable user groups of which this user is a member. * Returns a set of all readable user groups of which this user is a member.

View File

@@ -35,10 +35,34 @@ import org.apache.guacamole.net.auth.ActivityRecordSet.SortableProperty;
public class SimpleActivityRecordSet<RecordType extends ActivityRecord> public class SimpleActivityRecordSet<RecordType extends ActivityRecord>
implements ActivityRecordSet<RecordType> { implements ActivityRecordSet<RecordType> {
/**
* The records associated with this record set, if any.
*/
private final Collection<RecordType> records;
/**
* Create a new SimpleActivityRecordSet that contains an empty set of
* records.
*/
public SimpleActivityRecordSet() {
records = Collections.emptyList();
}
/**
* Create a new SimpleActivityRecordSet that contains the provided records
* which will back this record set.
*
* @param records
* The records that this SimpleActivityRecordSet should contain.
*/
public SimpleActivityRecordSet(Collection<? extends RecordType> records) {
this.records = Collections.unmodifiableCollection(records);
}
@Override @Override
public Collection<RecordType> asCollection() public Collection<RecordType> asCollection()
throws GuacamoleException { throws GuacamoleException {
return Collections.<RecordType>emptyList(); return records;
} }
@Override @Override

View File

@@ -21,7 +21,6 @@ package org.apache.guacamole.net.auth.simple;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.GuacamoleServerException;
@@ -33,6 +32,7 @@ import org.apache.guacamole.net.InetGuacamoleSocket;
import org.apache.guacamole.net.SSLGuacamoleSocket; import org.apache.guacamole.net.SSLGuacamoleSocket;
import org.apache.guacamole.net.SimpleGuacamoleTunnel; import org.apache.guacamole.net.SimpleGuacamoleTunnel;
import org.apache.guacamole.net.auth.AbstractConnection; import org.apache.guacamole.net.auth.AbstractConnection;
import org.apache.guacamole.net.auth.ActivityRecordSet;
import org.apache.guacamole.net.auth.ConnectionRecord; import org.apache.guacamole.net.auth.ConnectionRecord;
import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration;
import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket; import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
@@ -285,8 +285,9 @@ public class SimpleConnection extends AbstractConnection {
} }
@Override @Override
public List<ConnectionRecord> getHistory() throws GuacamoleException { public ActivityRecordSet<ConnectionRecord> getConnectionHistory()
return Collections.<ConnectionRecord>emptyList(); throws GuacamoleException {
return new SimpleActivityRecordSet<>();
} }
} }

View File

@@ -19,15 +19,13 @@
package org.apache.guacamole.rest.connection; package org.apache.guacamole.rest.connection;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionRecord;
import org.apache.guacamole.protocol.GuacamoleClientInformation; import org.apache.guacamole.protocol.GuacamoleClientInformation;
import org.apache.guacamole.protocol.GuacamoleConfiguration; import org.apache.guacamole.protocol.GuacamoleConfiguration;
@@ -123,14 +121,14 @@ public class APIConnectionWrapper implements Connection {
} }
@Override @Override
public Set<String> getSharingProfileIdentifiers() { public Set<String> getSharingProfileIdentifiers() throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported."); throw new GuacamoleUnsupportedException("Operation not supported.");
} }
@Override @Override
public GuacamoleTunnel connect(GuacamoleClientInformation info, public GuacamoleTunnel connect(GuacamoleClientInformation info,
Map<String, String> tokens) throws GuacamoleException { Map<String, String> tokens) throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported."); throw new GuacamoleUnsupportedException("Operation not supported.");
} }
@Override @Override
@@ -138,9 +136,4 @@ public class APIConnectionWrapper implements Connection {
return null; return null;
} }
@Override
public List<? extends ConnectionRecord> getHistory() throws GuacamoleException {
return Collections.<ConnectionRecord>emptyList();
}
} }

View File

@@ -22,8 +22,6 @@ package org.apache.guacamole.rest.connection;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@@ -32,8 +30,8 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionRecord;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.rest.directory.DirectoryView; import org.apache.guacamole.rest.directory.DirectoryView;
@@ -43,13 +41,16 @@ import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet; import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermission; import org.apache.guacamole.net.auth.permission.SystemPermission;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet; import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
import org.apache.guacamole.rest.history.APIConnectionRecord; import org.apache.guacamole.net.auth.simple.SimpleActivityRecordSet;
import org.apache.guacamole.protocol.GuacamoleConfiguration; import org.apache.guacamole.protocol.GuacamoleConfiguration;
import org.apache.guacamole.rest.directory.DirectoryObjectResource; import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator; import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.directory.DirectoryResource; import org.apache.guacamole.rest.directory.DirectoryResource;
import org.apache.guacamole.rest.directory.DirectoryResourceFactory; import org.apache.guacamole.rest.directory.DirectoryResourceFactory;
import org.apache.guacamole.rest.history.ConnectionHistoryResource;
import org.apache.guacamole.rest.sharingprofile.APISharingProfile; import org.apache.guacamole.rest.sharingprofile.APISharingProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* A REST resource which abstracts the operations available on an existing * A REST resource which abstracts the operations available on an existing
@@ -59,6 +60,11 @@ import org.apache.guacamole.rest.sharingprofile.APISharingProfile;
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public class ConnectionResource extends DirectoryObjectResource<Connection, APIConnection> { public class ConnectionResource extends DirectoryObjectResource<Connection, APIConnection> {
/**
* Logger for this class.
*/
private static final Logger logger = LoggerFactory.getLogger(ConnectionResource.class);
/** /**
* The UserContext associated with the Directory which contains the * The UserContext associated with the Directory which contains the
* Connection exposed by this resource. * Connection exposed by this resource.
@@ -150,18 +156,29 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving the connection history. * If an error occurs while retrieving the connection history.
*/ */
@GET @SuppressWarnings("deprecation")
@Path("history") @Path("history")
public List<APIConnectionRecord> getConnectionHistory() public ConnectionHistoryResource getConnectionHistory()
throws GuacamoleException { throws GuacamoleException {
// Retrieve the requested connection's history // Try the current getConnectionHistory() method, first, for connection history.
List<APIConnectionRecord> apiRecords = new ArrayList<APIConnectionRecord>(); try {
for (ConnectionRecord record : connection.getHistory()) return new ConnectionHistoryResource(connection.getConnectionHistory());
apiRecords.add(new APIConnectionRecord(record)); }
catch (GuacamoleUnsupportedException e) {
logger.debug("Call to getConnectionHistory() is unsupported, falling back to getHistory().", e);
}
// Return the converted history // Fall back to the deprecated getHistory() method.
return apiRecords; try {
return new ConnectionHistoryResource(new SimpleActivityRecordSet<>(connection.getHistory()));
}
catch (GuacamoleUnsupportedException e) {
logger.debug("Call to getHistory() is unsupported, no connection history records will be returned.", e);
}
// If all fails, return an empty connection history set.
return new ConnectionHistoryResource(new SimpleActivityRecordSet<>());
} }
@@ -184,7 +201,7 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
// Produce subset of all SharingProfiles, containing only those which // Produce subset of all SharingProfiles, containing only those which
// are associated with this connection // are associated with this connection
Directory<SharingProfile> sharingProfiles = new DirectoryView<SharingProfile>( Directory<SharingProfile> sharingProfiles = new DirectoryView<>(
userContext.getSharingProfileDirectory(), userContext.getSharingProfileDirectory(),
connection.getSharingProfileIdentifiers() connection.getSharingProfileIdentifiers()
); );

View File

@@ -24,7 +24,9 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.simple.SimpleActivityRecordSet;
/** /**
* A REST resource for retrieving and managing the history records of Guacamole * A REST resource for retrieving and managing the history records of Guacamole
@@ -64,7 +66,12 @@ public class HistoryResource {
*/ */
@Path("connections") @Path("connections")
public ConnectionHistoryResource getConnectionHistory() throws GuacamoleException { public ConnectionHistoryResource getConnectionHistory() throws GuacamoleException {
return new ConnectionHistoryResource(userContext.getConnectionHistory()); try {
return new ConnectionHistoryResource(userContext.getConnectionHistory());
}
catch (GuacamoleUnsupportedException e) {
return new ConnectionHistoryResource(new SimpleActivityRecordSet<>());
}
} }
/** /**
@@ -81,7 +88,12 @@ public class HistoryResource {
*/ */
@Path("users") @Path("users")
public UserHistoryResource getUserHistory() throws GuacamoleException { public UserHistoryResource getUserHistory() throws GuacamoleException {
return new UserHistoryResource(userContext.getUserHistory()); try {
return new UserHistoryResource(userContext.getUserHistory());
}
catch (GuacamoleUnsupportedException e) {
return new UserHistoryResource(new SimpleActivityRecordSet<>());
}
} }
} }

View File

@@ -19,13 +19,10 @@
package org.apache.guacamole.rest.user; package org.apache.guacamole.rest.user;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.auth.ActivityRecord;
import org.apache.guacamole.net.auth.Permissions; import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.RelatedObjectSet; import org.apache.guacamole.net.auth.RelatedObjectSet;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
@@ -139,9 +136,4 @@ public class APIUserWrapper implements User {
return null; return null;
} }
@Override
public List<? extends ActivityRecord> getHistory() throws GuacamoleException {
return Collections.<ActivityRecord>emptyList();
}
} }

View File

@@ -21,8 +21,6 @@ package org.apache.guacamole.rest.user;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@@ -33,19 +31,22 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.net.auth.ActivityRecord; import org.apache.guacamole.GuacamoleUnsupportedException;
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;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.Directory; import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException; import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException;
import org.apache.guacamole.net.auth.simple.SimpleActivityRecordSet;
import org.apache.guacamole.rest.directory.DirectoryObjectResource; import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator; import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.history.APIActivityRecord; import org.apache.guacamole.rest.history.UserHistoryResource;
import org.apache.guacamole.rest.identifier.RelatedObjectSetResource; import org.apache.guacamole.rest.identifier.RelatedObjectSetResource;
import org.apache.guacamole.rest.permission.APIPermissionSet; import org.apache.guacamole.rest.permission.APIPermissionSet;
import org.apache.guacamole.rest.permission.PermissionSetResource; import org.apache.guacamole.rest.permission.PermissionSetResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* A REST resource which abstracts the operations available on an existing * A REST resource which abstracts the operations available on an existing
@@ -56,6 +57,11 @@ import org.apache.guacamole.rest.permission.PermissionSetResource;
public class UserResource public class UserResource
extends DirectoryObjectResource<User, APIUser> { extends DirectoryObjectResource<User, APIUser> {
/**
* Logger for this class.
*/
private static final Logger logger = LoggerFactory.getLogger(UserResource.class);
/** /**
* The UserContext associated with the Directory which contains the User * The UserContext associated with the Directory which contains the User
* exposed by this resource. * exposed by this resource.
@@ -110,18 +116,29 @@ public class UserResource
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving the user history. * If an error occurs while retrieving the user history.
*/ */
@GET @SuppressWarnings("deprecation")
@Path("history") @Path("history")
public List<APIActivityRecord> getUserHistory() public UserHistoryResource getUserHistory()
throws GuacamoleException { throws GuacamoleException {
// Retrieve the requested user's history // First try to retrieve history using the current getUserHistory() method.
List<APIActivityRecord> apiRecords = new ArrayList<APIActivityRecord>(); try {
for (ActivityRecord record : user.getHistory()) return new UserHistoryResource(user.getUserHistory());
apiRecords.add(new APIActivityRecord(record)); }
catch (GuacamoleUnsupportedException e) {
logger.debug("Call to getUserHistory() is unsupported, falling back to deprecated method getHistory().", e);
}
// Return the converted history // Fall back to deprecated getHistory() method.
return apiRecords; try {
return new UserHistoryResource(new SimpleActivityRecordSet<>(user.getHistory()));
}
catch (GuacamoleUnsupportedException e) {
logger.debug("Call to getHistory() is unsupported, no user history records will be returned.", e);
}
// If both are unimplemented, return an empty history set.
return new UserHistoryResource(new SimpleActivityRecordSet<>());
} }