GUACAMOLE-394: Implement full retrieval of user login history.
Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/7e8accab Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/7e8accab Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/7e8accab Branch: refs/heads/staging/0.9.14 Commit: 7e8accab62a2ea2be89cc24de5a152c7147c983e Parents: 2414c9a Author: Michael Jumper <[email protected]> Authored: Tue Sep 12 14:21:32 2017 -0700 Committer: Michael Jumper <[email protected]> Committed: Mon Dec 11 23:51:57 2017 -0800 ---------------------------------------------------------------------- .../guacamole/auth/jdbc/user/ModeledUser.java | 8 +- .../auth/jdbc/user/ModeledUserContext.java | 10 +- .../guacamole/auth/jdbc/user/UserRecordSet.java | 59 ++++++++ .../guacamole/auth/jdbc/user/UserService.java | 133 ++++++++++++++++++- 4 files changed, 207 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/7e8accab/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index b039a4e..5ffc458 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -145,6 +145,12 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us )); /** + * Service for managing users. + */ + @Inject + private UserService userService; + + /** * Service for hashing passwords. */ @Inject @@ -801,7 +807,7 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us @Override public List<ActivityRecord> getHistory() throws GuacamoleException { - return Collections.<ActivityRecord>emptyList(); + return userService.retrieveHistory(getCurrentUser(), this); } } http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/7e8accab/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java index 1b238ab..fc2c972 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java @@ -99,6 +99,12 @@ public class ModeledUserContext extends RestrictedObject */ @Inject private Provider<ConnectionRecordSet> connectionRecordSetProvider; + + /** + * Provider for creating user record sets. + */ + @Inject + private Provider<UserRecordSet> userRecordSetProvider; @Override public void init(ModeledAuthenticatedUser currentUser) { @@ -167,7 +173,9 @@ public class ModeledUserContext extends RestrictedObject @Override public ActivityRecordSet<ActivityRecord> getUserHistory() throws GuacamoleException { - return new SimpleActivityRecordSet<ActivityRecord>(); + UserRecordSet userRecordSet = userRecordSetProvider.get(); + userRecordSet.init(getCurrentUser()); + return userRecordSet; } @Override http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/7e8accab/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordSet.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordSet.java new file mode 100644 index 0000000..c1b4897 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordSet.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc.user; + +import com.google.inject.Inject; +import java.util.Collection; +import java.util.List; +import java.util.Set; +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.net.auth.ActivityRecord; +import org.apache.guacamole.net.auth.AuthenticatedUser; + +/** + * A JDBC implementation of ActivityRecordSet for retrieving user login history. + * Calls to asCollection() will query user login records from the database. + * Which records are returned will be determined by the values passed in + * earlier. + */ +public class UserRecordSet extends ModeledActivityRecordSet<ActivityRecord> { + + /** + * Service for managing user objects. + */ + @Inject + private UserService userService; + + @Override + protected Collection<ActivityRecord> retrieveHistory( + AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents, + List<ActivityRecordSortPredicate> sortPredicates, int limit) + throws GuacamoleException { + + // Retrieve history from database + return userService.retrieveHistory(getCurrentUser(), + requiredContents, sortPredicates, limit); + + } + +} http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/7e8accab/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java index 3dc025f..090963f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java @@ -21,16 +21,24 @@ package org.apache.guacamole.auth.jdbc.user; import com.google.inject.Inject; import com.google.inject.Provider; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import javax.servlet.http.HttpServletRequest; import org.apache.guacamole.net.auth.Credentials; 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; +import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate; +import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord; +import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordModel; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel; import org.apache.guacamole.auth.jdbc.permission.UserPermissionMapper; @@ -38,8 +46,10 @@ import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService; import org.apache.guacamole.auth.jdbc.security.PasswordPolicyService; import org.apache.guacamole.form.Field; import org.apache.guacamole.form.PasswordField; +import org.apache.guacamole.net.auth.ActivityRecord; import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; +import org.apache.guacamole.net.auth.ConnectionRecord; import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.credentials.CredentialsInfo; import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException; @@ -116,7 +126,13 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User */ @Inject private UserPermissionMapper userPermissionMapper; - + + /** + * Mapper for accessing user login history. + */ + @Inject + private UserRecordMapper userRecordMapper; + /** * Provider for creating users. */ @@ -460,4 +476,119 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User } + /** + * Returns a ActivityRecord object which is backed by the given model. + * + * @param model + * The model object to use to back the returned connection record + * object. + * + * @return + * A connection record object which is backed by the given model. + */ + protected ActivityRecord getObjectInstance(ActivityRecordModel model) { + return new ModeledActivityRecord(model); + } + + /** + * Returns a list of ActivityRecord objects which are backed by the + * models in the given list. + * + * @param models + * The model objects to use to back the activity record objects + * within the returned list. + * + * @return + * A list of activity record objects which are backed by the models + * in the given list. + */ + protected List<ActivityRecord> getObjectInstances(List<ActivityRecordModel> models) { + + // Create new list of records by manually converting each model + List<ActivityRecord> objects = new ArrayList<ActivityRecord>(models.size()); + for (ActivityRecordModel model : models) + objects.add(getObjectInstance(model)); + + return objects; + + } + + /** + * Retrieves the login history of the given user, including any active + * sessions. + * + * @param authenticatedUser + * The user retrieving the login history. + * + * @param user + * The user whose history is being retrieved. + * + * @return + * The login history of the given user, including any active sessions. + * + * @throws GuacamoleException + * If permission to read the login history is denied. + */ + public List<ActivityRecord> retrieveHistory(ModeledAuthenticatedUser authenticatedUser, + 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."); + + } + + /** + * 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. + * + * @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(ModeledAuthenticatedUser user, + Collection<ActivityRecordSearchTerm> requiredContents, + List<ActivityRecordSortPredicate> sortPredicates, int limit) + throws GuacamoleException { + + List<ActivityRecordModel> searchResults; + + // Bypass permission checks if the user is a system admin + if (user.getUser().isAdministrator()) + searchResults = userRecordMapper.search(requiredContents, + sortPredicates, limit); + + // Otherwise only return explicitly readable history records + else + searchResults = userRecordMapper.searchReadable(user.getUser().getModel(), + requiredContents, sortPredicates, limit); + + return getObjectInstances(searchResults); + + } + + }
