Merge 1.3.0 changes back to master.

This commit is contained in:
Michael Jumper
2020-10-30 11:30:11 -07:00
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.
*/
private final Set<ActivityRecordSearchTerm> requiredContents =
new HashSet<ActivityRecordSearchTerm>();
new HashSet<>();
/**
* 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.
*/
private final List<ActivityRecordSortPredicate> sortPredicates =
new ArrayList<ActivityRecordSortPredicate>();
new ArrayList<>();
/**
* Retrieves the history records matching the given criteria. Retrieves up

View File

@@ -62,8 +62,12 @@ public interface ConnectionRecordMapper {
* 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
* 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
* The search terms that must match the returned records.
*
@@ -77,7 +81,8 @@ public interface ConnectionRecordMapper {
* @return
* 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("limit") int limit);
@@ -86,8 +91,13 @@ public interface ConnectionRecordMapper {
* the given terms, sorted by the given predicates. Only records that are
* associated with data explicitly readable by the given user will be
* 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
* The user whose permissions should determine whether a record is
* returned.
@@ -111,7 +121,8 @@ public interface ConnectionRecordMapper {
* @return
* 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("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@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.ActivityRecordSortPredicate;
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.ConnectionRecord;
@@ -43,6 +44,30 @@ public class ConnectionRecordSet extends ModeledActivityRecordSet<ConnectionReco
@Inject
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
protected Collection<ConnectionRecord> retrieveHistory(
AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents,
@@ -50,7 +75,7 @@ public class ConnectionRecordSet extends ModeledActivityRecordSet<ConnectionReco
throws GuacamoleException {
// Retrieve history from database
return connectionService.retrieveHistory(getCurrentUser(),
return connectionService.retrieveHistory(identifier, getCurrentUser(),
requiredContents, sortPredicates, limit);
}

View File

@@ -213,7 +213,7 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
Map<String, String> parameters = connection.getConfiguration().getParameters();
// 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()) {
// Get parameter name and value
@@ -329,7 +329,7 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
public Map<String, String> retrieveParameters(ModeledAuthenticatedUser user,
String identifier) {
Map<String, String> parameterMap = new HashMap<String, String>();
Map<String, String> parameterMap = new HashMap<>();
// Determine whether we have permission to read parameters
boolean canRetrieveParameters;
@@ -382,7 +382,7 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
protected List<ConnectionRecord> getObjectInstances(List<ConnectionRecordModel> models) {
// 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)
objects.add(getObjectInstance(model));
@@ -411,28 +411,16 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
ModeledConnection connection) throws GuacamoleException {
String identifier = connection.getIdentifier();
// Retrieve history only if READ permission is granted
if (hasObjectPermission(user, identifier, ObjectPermission.Type.READ)) {
// Retrieve history
List<ConnectionRecordModel> models = connectionRecordMapper.select(identifier);
// Get currently-active connections
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;
}
// The user does not have permission to read the history
throw new GuacamoleSecurityException("Permission denied.");
// Get current active connections.
List<ConnectionRecord> records = new ArrayList<>(tunnelService.getActiveConnections(connection));
Collections.reverse(records);
// Add in the history records.
records.addAll(retrieveHistory(identifier, user, Collections.emptyList(),
Collections.emptyList(), Integer.MAX_VALUE));
return records;
}
@@ -442,6 +430,60 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
* 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;
// Bypass permission checks if the user is privileged
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);
}
/**
* 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 user
* The user retrieving the connection history.
*
@@ -467,22 +509,9 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
Collection<ActivityRecordSearchTerm> requiredContents,
List<ActivityRecordSortPredicate> sortPredicates, int limit)
throws GuacamoleException {
List<ConnectionRecordModel> searchResults;
// 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);
return retrieveHistory(null, user, requiredContents, sortPredicates, limit);
}
/**

View File

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

View File

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

View File

@@ -21,11 +21,9 @@ package org.apache.guacamole.auth.jdbc.sharing.user;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
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.Connection;
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
public String getPassword() {
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.TimeZoneField;
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.RelatedObjectSet;
import org.apache.guacamole.net.auth.User;
@@ -182,6 +183,12 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
*/
@Inject
private Provider<UserParentUserGroupSet> parentUserGroupSetProvider;
/**
* Provider for creating user record sets.
*/
@Inject
private Provider<UserRecordSet> userRecordSetProvider;
/**
* Whether attributes which control access restrictions should be exposed
@@ -748,8 +755,11 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
}
@Override
public List<ActivityRecord> getHistory() throws GuacamoleException {
return userService.retrieveHistory(getCurrentUser(), this);
public ActivityRecordSet<ActivityRecord> getUserHistory()
throws GuacamoleException {
UserRecordSet userRecordSet = userRecordSetProvider.get();
userRecordSet.init(getCurrentUser(), this.getIdentifier());
return userRecordSet;
}
@Override

View File

@@ -73,8 +73,12 @@ public interface UserRecordMapper {
* 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
* 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
* The search terms that must match the returned records.
*
@@ -88,7 +92,8 @@ public interface UserRecordMapper {
* @return
* 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("limit") int limit);
@@ -97,11 +102,16 @@ public interface UserRecordMapper {
* the given terms, sorted by the given predicates. Only records that are
* associated with data explicitly readable by the given user will be
* 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
* The user whose permissions should determine whether a record is
* returned.
* The user whose permissions should determine whether a record is
* returned.
*
* @param terms
* The search terms that must match the returned records.
@@ -122,7 +132,8 @@ public interface UserRecordMapper {
* @return
* 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("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@Param("limit") int limit,

View File

@@ -44,6 +44,31 @@ public class UserRecordSet extends ModeledActivityRecordSet<ActivityRecord> {
@Inject
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
protected Collection<ActivityRecord> retrieveHistory(
AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents,
@@ -51,7 +76,7 @@ public class UserRecordSet extends ModeledActivityRecordSet<ActivityRecord> {
throws GuacamoleException {
// Retrieve history from database
return userService.retrieveHistory(getCurrentUser(),
return userService.retrieveHistory(identifier, getCurrentUser(),
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.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
@@ -593,13 +592,9 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
ModeledUser user) throws GuacamoleException {
String username = user.getIdentifier();
// Retrieve history only if READ permission is granted
if (hasObjectPermission(authenticatedUser, username, ObjectPermission.Type.READ))
return getObjectInstances(userRecordMapper.select(username));
// The user does not have permission to read the history
throw new GuacamoleSecurityException("Permission denied.");
return retrieveHistory(username, authenticatedUser, Collections.emptyList(),
Collections.emptyList(), Integer.MAX_VALUE);
}
@@ -609,6 +604,59 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
* 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);
}
/**
* 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 user
* The user retrieving the login history.
*
@@ -633,21 +681,9 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, 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(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);
return retrieveHistory(null, user, requiredContents, sortPredicates, limit);
}
}

View File

@@ -108,28 +108,35 @@
LEFT JOIN guacamole_user ON guacamole_connection_history.user_id = guacamole_user.user_id
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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
)
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>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -186,31 +193,38 @@
AND guacamole_user_permission.permission = 'READ'
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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'
)
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>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -105,25 +105,32 @@
FROM guacamole_user_history
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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'),
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -164,25 +171,32 @@
AND guacamole_user_permission.permission = 'READ'
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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'
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -106,28 +106,35 @@
FROM guacamole_connection_history
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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
)
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>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -184,31 +191,38 @@
AND guacamole_user_permission.permission = 'READ'
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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 (
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>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -105,25 +105,32 @@
FROM guacamole_user_history
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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),
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -164,25 +171,31 @@
AND guacamole_user_permission.permission = 'READ'
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -106,28 +106,35 @@
FROM [guacamole_connection_history]
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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
)
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>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -182,31 +189,38 @@
AND [guacamole_user_permission].permission = 'READ'
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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'
)
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>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>

View File

@@ -105,25 +105,32 @@
FROM [guacamole_user_history]
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<bind name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
@@ -162,25 +169,32 @@
AND [guacamole_user_permission].permission = 'READ'
<!-- Search terms -->
<foreach collection="terms" item="term"
open="WHERE " separator=" AND ">
(
<where>
<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'
)
<if test="term.startDate != null and term.endDate != null">
OR start_date BETWEEN #{term.startDate,jdbcType=TIMESTAMP} AND #{term.endDate,jdbcType=TIMESTAMP}
</if>
)
</foreach>
</foreach>
</where>
<!-- Bind sort property enum values for sake of readability -->
<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.Date;
import java.util.List;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
@@ -85,18 +84,7 @@ public abstract class AbstractUser extends AbstractIdentifiable
public Date getLastActive() {
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}
*

View File

@@ -19,10 +19,13 @@
package org.apache.guacamole.net.auth;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.protocol.GuacamoleConfiguration;
/**
@@ -98,17 +101,56 @@ public interface Connection extends Identifiable, Connectable, Attributes {
* 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).
* (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
* of this Connection.
* @deprecated
* 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.
*
* @return
* A list of ConnectionRecrods representing the usage history of this
* Connection.
*
* @throws GuacamoleException If an error occurs while reading the history
* of this connection, or if permission is
* denied.
* @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
* join this connection when it is active. The level of access granted to a

View File

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

View File

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

View File

@@ -19,9 +19,12 @@
package org.apache.guacamole.net.auth;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
/**
* 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
* 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).
* (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
* A list of ActivityRecords representing the login history of this
* User.
*
* @throws GuacamoleException
* If an error occurs while reading the history of this user, or if
* permission is denied.
* If history tracking is not implemented, if an error occurs while
* 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.

View File

@@ -35,10 +35,34 @@ import org.apache.guacamole.net.auth.ActivityRecordSet.SortableProperty;
public class SimpleActivityRecordSet<RecordType extends ActivityRecord>
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
public Collection<RecordType> asCollection()
throws GuacamoleException {
return Collections.<RecordType>emptyList();
return records;
}
@Override

View File

@@ -21,7 +21,6 @@ package org.apache.guacamole.net.auth.simple;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
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.SimpleGuacamoleTunnel;
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.GuacamoleProxyConfiguration;
import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
@@ -283,10 +283,11 @@ public class SimpleConnection extends AbstractConnection {
public Date getLastActive() {
return null;
}
@Override
public List<ConnectionRecord> getHistory() throws GuacamoleException {
return Collections.<ConnectionRecord>emptyList();
public ActivityRecordSet<ConnectionRecord> getConnectionHistory()
throws GuacamoleException {
return new SimpleActivityRecordSet<>();
}
}

View File

@@ -19,15 +19,13 @@
package org.apache.guacamole.rest.connection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.GuacamoleTunnel;
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.GuacamoleConfiguration;
@@ -123,24 +121,19 @@ public class APIConnectionWrapper implements Connection {
}
@Override
public Set<String> getSharingProfileIdentifiers() {
throw new UnsupportedOperationException("Operation not supported.");
public Set<String> getSharingProfileIdentifiers() throws GuacamoleException {
throw new GuacamoleUnsupportedException("Operation not supported.");
}
@Override
public GuacamoleTunnel connect(GuacamoleClientInformation info,
Map<String, String> tokens) throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported.");
throw new GuacamoleUnsupportedException("Operation not supported.");
}
@Override
public Date getLastActive() {
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.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -32,8 +30,8 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.GuacamoleUnsupportedException;
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.Permissions;
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.SystemPermission;
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.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.directory.DirectoryResource;
import org.apache.guacamole.rest.directory.DirectoryResourceFactory;
import org.apache.guacamole.rest.history.ConnectionHistoryResource;
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
@@ -59,6 +60,11 @@ import org.apache.guacamole.rest.sharingprofile.APISharingProfile;
@Consumes(MediaType.APPLICATION_JSON)
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
* Connection exposed by this resource.
@@ -150,18 +156,29 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
* @throws GuacamoleException
* If an error occurs while retrieving the connection history.
*/
@GET
@SuppressWarnings("deprecation")
@Path("history")
public List<APIConnectionRecord> getConnectionHistory()
public ConnectionHistoryResource getConnectionHistory()
throws GuacamoleException {
// Retrieve the requested connection's history
List<APIConnectionRecord> apiRecords = new ArrayList<APIConnectionRecord>();
for (ConnectionRecord record : connection.getHistory())
apiRecords.add(new APIConnectionRecord(record));
// Return the converted history
return apiRecords;
// Try the current getConnectionHistory() method, first, for connection history.
try {
return new ConnectionHistoryResource(connection.getConnectionHistory());
}
catch (GuacamoleUnsupportedException e) {
logger.debug("Call to getConnectionHistory() is unsupported, falling back to getHistory().", e);
}
// Fall back to the deprecated getHistory() method.
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
// are associated with this connection
Directory<SharingProfile> sharingProfiles = new DirectoryView<SharingProfile>(
Directory<SharingProfile> sharingProfiles = new DirectoryView<>(
userContext.getSharingProfileDirectory(),
connection.getSharingProfileIdentifiers()
);

View File

@@ -24,7 +24,9 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
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
@@ -64,7 +66,12 @@ public class HistoryResource {
*/
@Path("connections")
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")
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;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
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.RelatedObjectSet;
import org.apache.guacamole.net.auth.User;
@@ -139,9 +136,4 @@ public class APIUserWrapper implements User {
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.AssistedInject;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -33,19 +31,22 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException;
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.Credentials;
import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext;
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.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.permission.APIPermissionSet;
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
@@ -56,6 +57,11 @@ import org.apache.guacamole.rest.permission.PermissionSetResource;
public class UserResource
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
* exposed by this resource.
@@ -110,18 +116,29 @@ public class UserResource
* @throws GuacamoleException
* If an error occurs while retrieving the user history.
*/
@GET
@SuppressWarnings("deprecation")
@Path("history")
public List<APIActivityRecord> getUserHistory()
public UserHistoryResource getUserHistory()
throws GuacamoleException {
// Retrieve the requested user's history
List<APIActivityRecord> apiRecords = new ArrayList<APIActivityRecord>();
for (ActivityRecord record : user.getHistory())
apiRecords.add(new APIActivityRecord(record));
// Return the converted history
return apiRecords;
// First try to retrieve history using the current getUserHistory() method.
try {
return new UserHistoryResource(user.getUserHistory());
}
catch (GuacamoleUnsupportedException e) {
logger.debug("Call to getUserHistory() is unsupported, falling back to deprecated method getHistory().", e);
}
// Fall back to deprecated getHistory() method.
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<>());
}