mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 05:31:22 +00:00
Merge 0.9.14 changes back to master.
This commit is contained in:
@@ -76,6 +76,7 @@ import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileParameterMapp
|
|||||||
import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileService;
|
import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileService;
|
||||||
import org.apache.guacamole.auth.jdbc.tunnel.RestrictedGuacamoleTunnelService;
|
import org.apache.guacamole.auth.jdbc.tunnel.RestrictedGuacamoleTunnelService;
|
||||||
import org.apache.guacamole.auth.jdbc.user.PasswordRecordMapper;
|
import org.apache.guacamole.auth.jdbc.user.PasswordRecordMapper;
|
||||||
|
import org.apache.guacamole.auth.jdbc.user.UserRecordMapper;
|
||||||
import org.mybatis.guice.MyBatisModule;
|
import org.mybatis.guice.MyBatisModule;
|
||||||
import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
|
import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
|
||||||
|
|
||||||
@@ -126,6 +127,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
|
|||||||
addMapperClass(SharingProfilePermissionMapper.class);
|
addMapperClass(SharingProfilePermissionMapper.class);
|
||||||
addMapperClass(UserMapper.class);
|
addMapperClass(UserMapper.class);
|
||||||
addMapperClass(UserPermissionMapper.class);
|
addMapperClass(UserPermissionMapper.class);
|
||||||
|
addMapperClass(UserRecordMapper.class);
|
||||||
|
|
||||||
// Bind core implementations of guacamole-ext classes
|
// Bind core implementations of guacamole-ext classes
|
||||||
bind(ActiveConnectionDirectory.class);
|
bind(ActiveConnectionDirectory.class);
|
||||||
|
@@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* 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.base;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single activity record representing an arbitrary activity performed by a
|
||||||
|
* user.
|
||||||
|
*/
|
||||||
|
public class ActivityRecordModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of this object in the database, if any.
|
||||||
|
*/
|
||||||
|
private Integer recordID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The database ID of the user associated with this activity record.
|
||||||
|
*/
|
||||||
|
private Integer userID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username of the user that performed the activity.
|
||||||
|
*/
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The remote host associated with the user that performed the activity.
|
||||||
|
*/
|
||||||
|
private String remoteHost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time the activity was initiated by the associated user.
|
||||||
|
*/
|
||||||
|
private Date startDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time the activity ended, or null if the end time is not known or
|
||||||
|
* the activity is still in progress.
|
||||||
|
*/
|
||||||
|
private Date endDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ID of this record in the database, if it exists.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The ID of this record in the database, or null if this record was
|
||||||
|
* not retrieved from the database.
|
||||||
|
*/
|
||||||
|
public Integer getRecordID() {
|
||||||
|
return recordID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the database ID of this record to the given value.
|
||||||
|
*
|
||||||
|
* @param recordID
|
||||||
|
* The ID to assign to this object.
|
||||||
|
*/
|
||||||
|
public void setRecordID(Integer recordID) {
|
||||||
|
this.recordID = recordID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the database ID of the user associated with this activity
|
||||||
|
* record.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The database ID of the user associated with this activity record.
|
||||||
|
*/
|
||||||
|
public Integer getUserID() {
|
||||||
|
return userID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the database ID of the user associated with this activity record.
|
||||||
|
*
|
||||||
|
* @param userID
|
||||||
|
* The database ID of the user to associate with this activity
|
||||||
|
* record.
|
||||||
|
*/
|
||||||
|
public void setUserID(Integer userID) {
|
||||||
|
this.userID = userID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the username of the user that performed the activity associated
|
||||||
|
* with this record.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The username of the user that performed the activity associated with
|
||||||
|
* this record.
|
||||||
|
*/
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the username of the user that performed the activity associated
|
||||||
|
* with this record.
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* The username of the user that performed the activity associated with
|
||||||
|
* this record.
|
||||||
|
*/
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the remote host associated with the user that performed the
|
||||||
|
* activity.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The remote host associated with the user that performed the activity.
|
||||||
|
*/
|
||||||
|
public String getRemoteHost() {
|
||||||
|
return remoteHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the remote host associated with the user that performed the
|
||||||
|
* activity.
|
||||||
|
*
|
||||||
|
* @param remoteHost
|
||||||
|
* The remote host associated with the user that performed the activity.
|
||||||
|
*/
|
||||||
|
public void setRemoteHost(String remoteHost) {
|
||||||
|
this.remoteHost = remoteHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time the activity was initiated by the associated user.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The time the activity was initiated by the associated user.
|
||||||
|
*/
|
||||||
|
public Date getStartDate() {
|
||||||
|
return startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the time the activity was initiated by the associated user.
|
||||||
|
*
|
||||||
|
* @param startDate
|
||||||
|
* The time the activity was initiated by the associated user.
|
||||||
|
*/
|
||||||
|
public void setStartDate(Date startDate) {
|
||||||
|
this.startDate = startDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time the activity ended, or null if the end time is not
|
||||||
|
* known or the activity is still in progress.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The time the activity ended, or null if the end time is not known or
|
||||||
|
* the activity is still in progress.
|
||||||
|
*/
|
||||||
|
public Date getEndDate() {
|
||||||
|
return endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the time the activity ended, if known.
|
||||||
|
*
|
||||||
|
* @param endDate
|
||||||
|
* The time the activity ended, or null if the end time is not known or
|
||||||
|
* the activity is still in progress.
|
||||||
|
*/
|
||||||
|
public void setEndDate(Date endDate) {
|
||||||
|
this.endDate = endDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -17,7 +17,7 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.guacamole.auth.jdbc.connection;
|
package org.apache.guacamole.auth.jdbc.base;
|
||||||
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -25,11 +25,11 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A search term for querying historical connection records. This will contain
|
* A search term for querying historical records of arbitrary activities. This
|
||||||
* a the search term in string form and, if that string appears to be a date. a
|
* will contain a the search term in string form and, if that string appears to
|
||||||
* corresponding date range.
|
* be a date. a corresponding date range.
|
||||||
*/
|
*/
|
||||||
public class ConnectionRecordSearchTerm {
|
public class ActivityRecordSearchTerm {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A pattern that can match a year, year and month, or year and month and
|
* A pattern that can match a year, year and month, or year and month and
|
||||||
@@ -180,7 +180,7 @@ public class ConnectionRecordSearchTerm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new ConnectionRecordSearchTerm representing the given string.
|
* Creates a new ActivityRecordSearchTerm representing the given string.
|
||||||
* If the given string appears to be a date, the start and end dates of the
|
* If the given string appears to be a date, the start and end dates of the
|
||||||
* implied date range will be automatically determined and made available
|
* implied date range will be automatically determined and made available
|
||||||
* via getStartDate() and getEndDate() respectively.
|
* via getStartDate() and getEndDate() respectively.
|
||||||
@@ -188,7 +188,7 @@ public class ConnectionRecordSearchTerm {
|
|||||||
* @param term
|
* @param term
|
||||||
* The string that should be searched for.
|
* The string that should be searched for.
|
||||||
*/
|
*/
|
||||||
public ConnectionRecordSearchTerm(String term) {
|
public ActivityRecordSearchTerm(String term) {
|
||||||
|
|
||||||
// Search terms absolutely must not be null
|
// Search terms absolutely must not be null
|
||||||
if (term == null)
|
if (term == null)
|
||||||
@@ -281,10 +281,10 @@ public class ConnectionRecordSearchTerm {
|
|||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
|
|
||||||
if (obj == null || !(obj instanceof ConnectionRecordSearchTerm))
|
if (obj == null || !(obj instanceof ActivityRecordSearchTerm))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return ((ConnectionRecordSearchTerm) obj).getTerm().equals(getTerm());
|
return ((ActivityRecordSearchTerm) obj).getTerm().equals(getTerm());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@@ -17,18 +17,18 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.guacamole.auth.jdbc.connection;
|
package org.apache.guacamole.auth.jdbc.base;
|
||||||
|
|
||||||
import org.apache.guacamole.net.auth.ActivityRecordSet;
|
import org.apache.guacamole.net.auth.ActivityRecordSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sort predicate which species the property to use when sorting connection
|
* A sort predicate which species the property to use when sorting activity
|
||||||
* records, along with the sort order.
|
* records, along with the sort order.
|
||||||
*/
|
*/
|
||||||
public class ConnectionRecordSortPredicate {
|
public class ActivityRecordSortPredicate {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The property to use when sorting ConnectionRecords.
|
* The property to use when sorting ActivityRecords.
|
||||||
*/
|
*/
|
||||||
private final ActivityRecordSet.SortableProperty property;
|
private final ActivityRecordSet.SortableProperty property;
|
||||||
|
|
||||||
@@ -38,26 +38,26 @@ public class ConnectionRecordSortPredicate {
|
|||||||
private final boolean descending;
|
private final boolean descending;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new ConnectionRecordSortPredicate with the given sort property
|
* Creates a new ActivityRecordSortPredicate with the given sort property
|
||||||
* and sort order.
|
* and sort order.
|
||||||
*
|
*
|
||||||
* @param property
|
* @param property
|
||||||
* The property to use when sorting ConnectionRecords.
|
* The property to use when sorting ActivityRecords.
|
||||||
*
|
*
|
||||||
* @param descending
|
* @param descending
|
||||||
* Whether the sort order is descending (true) or ascending (false).
|
* Whether the sort order is descending (true) or ascending (false).
|
||||||
*/
|
*/
|
||||||
public ConnectionRecordSortPredicate(ActivityRecordSet.SortableProperty property,
|
public ActivityRecordSortPredicate(ActivityRecordSet.SortableProperty property,
|
||||||
boolean descending) {
|
boolean descending) {
|
||||||
this.property = property;
|
this.property = property;
|
||||||
this.descending = descending;
|
this.descending = descending;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the property that should be used when sorting ConnectionRecords.
|
* Returns the property that should be used when sorting ActivityRecords.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The property that should be used when sorting ConnectionRecords.
|
* The property that should be used when sorting ActivityRecords.
|
||||||
*/
|
*/
|
||||||
public ActivityRecordSet.SortableProperty getProperty() {
|
public ActivityRecordSet.SortableProperty getProperty() {
|
||||||
return property;
|
return property;
|
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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.base;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import org.apache.guacamole.net.auth.ActivityRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An ActivityRecord which is backed by a database model.
|
||||||
|
*/
|
||||||
|
public class ModeledActivityRecord implements ActivityRecord {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The model object backing this activity record.
|
||||||
|
*/
|
||||||
|
private final ActivityRecordModel model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ModeledActivityRecord backed by the given model object.
|
||||||
|
* Changes to this record will affect the backing model object, and changes
|
||||||
|
* to the backing model object will affect this record.
|
||||||
|
*
|
||||||
|
* @param model
|
||||||
|
* The model object to use to back this activity record.
|
||||||
|
*/
|
||||||
|
public ModeledActivityRecord(ActivityRecordModel model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getStartDate() {
|
||||||
|
return model.getStartDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getEndDate() {
|
||||||
|
return model.getEndDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRemoteHost() {
|
||||||
|
return model.getRemoteHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return model.getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActive() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* 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.base;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.net.auth.ActivityRecord;
|
||||||
|
import org.apache.guacamole.net.auth.ActivityRecordSet;
|
||||||
|
import org.apache.guacamole.net.auth.ActivityRecordSet.SortableProperty;
|
||||||
|
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JDBC implementation of ActivityRecordSet. Calls to asCollection() will
|
||||||
|
* query history records using an implementation-specific mechanism. Which
|
||||||
|
* records are returned will be determined by the values passed in earlier.
|
||||||
|
*
|
||||||
|
* @param <RecordType>
|
||||||
|
* The type of ActivityRecord contained within this set.
|
||||||
|
*/
|
||||||
|
public abstract class ModeledActivityRecordSet<RecordType extends ActivityRecord>
|
||||||
|
extends RestrictedObject implements ActivityRecordSet<RecordType> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of strings that each must occur somewhere within the returned
|
||||||
|
* records, whether within the associated username, an associated date, or
|
||||||
|
* other related data. If non-empty, any record not matching each of the
|
||||||
|
* strings within the collection will be excluded from the results.
|
||||||
|
*/
|
||||||
|
private final Set<ActivityRecordSearchTerm> requiredContents =
|
||||||
|
new HashSet<ActivityRecordSearchTerm>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of history records that should be returned by a call
|
||||||
|
* to asCollection().
|
||||||
|
*/
|
||||||
|
private int limit = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of predicates to apply while sorting the resulting records,
|
||||||
|
* describing the properties involved and the sort order for those
|
||||||
|
* properties.
|
||||||
|
*/
|
||||||
|
private final List<ActivityRecordSortPredicate> sortPredicates =
|
||||||
|
new ArrayList<ActivityRecordSortPredicate>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the history records matching the given criteria. Retrieves up
|
||||||
|
* to <code>limit</code> 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 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
|
||||||
|
* A collection of all history records matching the given criteria.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If permission to read the history records is denied.
|
||||||
|
*/
|
||||||
|
protected abstract Collection<RecordType> retrieveHistory(
|
||||||
|
AuthenticatedUser user,
|
||||||
|
Set<ActivityRecordSearchTerm> requiredContents,
|
||||||
|
List<ActivityRecordSortPredicate> sortPredicates,
|
||||||
|
int limit) throws GuacamoleException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<RecordType> asCollection()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return retrieveHistory(getCurrentUser(), requiredContents,
|
||||||
|
sortPredicates, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModeledActivityRecordSet<RecordType> contains(String value)
|
||||||
|
throws GuacamoleException {
|
||||||
|
requiredContents.add(new ActivityRecordSearchTerm(value));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModeledActivityRecordSet<RecordType> limit(int limit) throws GuacamoleException {
|
||||||
|
this.limit = Math.min(this.limit, limit);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ModeledActivityRecordSet<RecordType> sort(SortableProperty property, boolean desc)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
sortPredicates.add(new ActivityRecordSortPredicate(
|
||||||
|
property,
|
||||||
|
desc
|
||||||
|
));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.jdbc.connection;
|
package org.apache.guacamole.auth.jdbc.connection;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.apache.guacamole.auth.jdbc.base.ChildObjectModel;
|
import org.apache.guacamole.auth.jdbc.base.ChildObjectModel;
|
||||||
@@ -92,6 +93,12 @@ public class ConnectionModel extends ChildObjectModel {
|
|||||||
*/
|
*/
|
||||||
private EncryptionMethod proxyEncryptionMethod;
|
private EncryptionMethod proxyEncryptionMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date and time that this connection was last used, or null if this
|
||||||
|
* connection has never been used.
|
||||||
|
*/
|
||||||
|
private Date lastActive;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new, empty connection.
|
* Creates a new, empty connection.
|
||||||
*/
|
*/
|
||||||
@@ -341,6 +348,32 @@ public class ConnectionModel extends ChildObjectModel {
|
|||||||
this.sharingProfileIdentifiers = sharingProfileIdentifiers;
|
this.sharingProfileIdentifiers = sharingProfileIdentifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date and time that this connection was last used, or null if
|
||||||
|
* this connection has never been used.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The date and time that this connection was last used, or null if this
|
||||||
|
* connection has never been used.
|
||||||
|
*/
|
||||||
|
public Date getLastActive() {
|
||||||
|
return lastActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the date and time that this connection was last used. This value is
|
||||||
|
* expected to be set automatically via queries, derived from connection
|
||||||
|
* history records. It does NOT correspond to an actual column, and values
|
||||||
|
* set manually through invoking this function will not persist.
|
||||||
|
*
|
||||||
|
* @param lastActive
|
||||||
|
* The date and time that this connection was last used, or null if this
|
||||||
|
* connection has never been used.
|
||||||
|
*/
|
||||||
|
public void setLastActive(Date lastActive) {
|
||||||
|
this.lastActive = lastActive;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIdentifier() {
|
public String getIdentifier() {
|
||||||
|
|
||||||
|
@@ -21,6 +21,8 @@ package org.apache.guacamole.auth.jdbc.connection;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
|
||||||
|
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.guacamole.auth.jdbc.user.UserModel;
|
import org.apache.guacamole.auth.jdbc.user.UserModel;
|
||||||
|
|
||||||
@@ -75,8 +77,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<ConnectionRecordSearchTerm> terms,
|
List<ConnectionRecordModel> search(@Param("terms") Collection<ActivityRecordSearchTerm> terms,
|
||||||
@Param("sortPredicates") List<ConnectionRecordSortPredicate> sortPredicates,
|
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
|
||||||
@Param("limit") int limit);
|
@Param("limit") int limit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,8 +106,8 @@ public interface ConnectionRecordMapper {
|
|||||||
* 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("user") UserModel user,
|
||||||
@Param("terms") Collection<ConnectionRecordSearchTerm> terms,
|
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
|
||||||
@Param("sortPredicates") List<ConnectionRecordSortPredicate> sortPredicates,
|
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
|
||||||
@Param("limit") int limit);
|
@Param("limit") int limit);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -19,14 +19,14 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.jdbc.connection;
|
package org.apache.guacamole.auth.jdbc.connection;
|
||||||
|
|
||||||
import java.util.Date;
|
import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single connection record representing a past usage of a particular
|
* A single connection record representing a past usage of a particular
|
||||||
* connection. If the connection was being shared, the sharing profile used to
|
* connection. If the connection was being shared, the sharing profile used to
|
||||||
* join the connection is included in the record.
|
* join the connection is included in the record.
|
||||||
*/
|
*/
|
||||||
public class ConnectionRecordModel {
|
public class ConnectionRecordModel extends ActivityRecordModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the connection associated with this connection record.
|
* The identifier of the connection associated with this connection record.
|
||||||
@@ -53,32 +53,6 @@ public class ConnectionRecordModel {
|
|||||||
*/
|
*/
|
||||||
private String sharingProfileName;
|
private String sharingProfileName;
|
||||||
|
|
||||||
/**
|
|
||||||
* The database ID of the user associated with this connection record.
|
|
||||||
*/
|
|
||||||
private Integer userID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The username of the user associated with this connection record.
|
|
||||||
*/
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The remote host associated with this connection record.
|
|
||||||
*/
|
|
||||||
private String remoteHost;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The time the connection was initiated by the associated user.
|
|
||||||
*/
|
|
||||||
private Date startDate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The time the connection ended, or null if the end time is not known or
|
|
||||||
* the connection is still running.
|
|
||||||
*/
|
|
||||||
private Date endDate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the identifier of the connection associated with this connection
|
* Returns the identifier of the connection associated with this connection
|
||||||
* record.
|
* record.
|
||||||
@@ -179,109 +153,4 @@ public class ConnectionRecordModel {
|
|||||||
this.sharingProfileName = sharingProfileName;
|
this.sharingProfileName = sharingProfileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the database ID of the user associated with this connection
|
|
||||||
* record.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The database ID of the user associated with this connection record.
|
|
||||||
*/
|
|
||||||
public Integer getUserID() {
|
|
||||||
return userID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the database ID of the user associated with this connection record.
|
|
||||||
*
|
|
||||||
* @param userID
|
|
||||||
* The database ID of the user to associate with this connection
|
|
||||||
* record.
|
|
||||||
*/
|
|
||||||
public void setUserID(Integer userID) {
|
|
||||||
this.userID = userID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the username of the user associated with this connection record.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The username of the user associated with this connection record.
|
|
||||||
*/
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the username of the user associated with this connection record.
|
|
||||||
*
|
|
||||||
* @param username
|
|
||||||
* The username of the user to associate with this connection record.
|
|
||||||
*/
|
|
||||||
public void setUsername(String username) {
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the remote host associated with this connection record.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The remote host associated with this connection record.
|
|
||||||
*/
|
|
||||||
public String getRemoteHost() {
|
|
||||||
return remoteHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the remote host associated with this connection record.
|
|
||||||
*
|
|
||||||
* @param remoteHost
|
|
||||||
* The remote host to associate with this connection record.
|
|
||||||
*/
|
|
||||||
public void setRemoteHost(String remoteHost) {
|
|
||||||
this.remoteHost = remoteHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the date that the associated connection was established.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The date the associated connection was established.
|
|
||||||
*/
|
|
||||||
public Date getStartDate() {
|
|
||||||
return startDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the date that the associated connection was established.
|
|
||||||
*
|
|
||||||
* @param startDate
|
|
||||||
* The date that the associated connection was established.
|
|
||||||
*/
|
|
||||||
public void setStartDate(Date startDate) {
|
|
||||||
this.startDate = startDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the date that the associated connection ended, or null if no
|
|
||||||
* end date was recorded. The lack of an end date does not necessarily
|
|
||||||
* mean that the connection is still active.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The date the associated connection ended, or null if no end date was
|
|
||||||
* recorded.
|
|
||||||
*/
|
|
||||||
public Date getEndDate() {
|
|
||||||
return endDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the date that the associated connection ended.
|
|
||||||
*
|
|
||||||
* @param endDate
|
|
||||||
* The date that the associated connection ended.
|
|
||||||
*/
|
|
||||||
public void setEndDate(Date endDate) {
|
|
||||||
this.endDate = endDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,15 +20,14 @@
|
|||||||
package org.apache.guacamole.auth.jdbc.connection;
|
package org.apache.guacamole.auth.jdbc.connection;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
|
||||||
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.auth.jdbc.base.RestrictedObject;
|
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
|
||||||
import org.apache.guacamole.net.auth.ActivityRecordSet;
|
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
|
||||||
import org.apache.guacamole.net.auth.ActivityRecordSet.SortableProperty;
|
import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecordSet;
|
||||||
|
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.ConnectionRecord;
|
import org.apache.guacamole.net.auth.ConnectionRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,8 +35,7 @@ import org.apache.guacamole.net.auth.ConnectionRecord;
|
|||||||
* asCollection() will query connection history records from the database. Which
|
* asCollection() will query connection history records from the database. Which
|
||||||
* records are returned will be determined by the values passed in earlier.
|
* records are returned will be determined by the values passed in earlier.
|
||||||
*/
|
*/
|
||||||
public class ConnectionRecordSet extends RestrictedObject
|
public class ConnectionRecordSet extends ModeledActivityRecordSet<ConnectionRecord> {
|
||||||
implements ActivityRecordSet<ConnectionRecord> {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for managing connection objects.
|
* Service for managing connection objects.
|
||||||
@@ -45,60 +43,15 @@ public class ConnectionRecordSet extends RestrictedObject
|
|||||||
@Inject
|
@Inject
|
||||||
private ConnectionService connectionService;
|
private ConnectionService connectionService;
|
||||||
|
|
||||||
/**
|
|
||||||
* The set of strings that each must occur somewhere within the returned
|
|
||||||
* connection records, whether within the associated username, the name of
|
|
||||||
* the associated connection, or any associated date. If non-empty, any
|
|
||||||
* connection record not matching each of the strings within the collection
|
|
||||||
* will be excluded from the results.
|
|
||||||
*/
|
|
||||||
private final Set<ConnectionRecordSearchTerm> requiredContents =
|
|
||||||
new HashSet<ConnectionRecordSearchTerm>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum number of connection history records that should be returned
|
|
||||||
* by a call to asCollection().
|
|
||||||
*/
|
|
||||||
private int limit = Integer.MAX_VALUE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of predicates to apply while sorting the resulting connection
|
|
||||||
* records, describing the properties involved and the sort order for those
|
|
||||||
* properties.
|
|
||||||
*/
|
|
||||||
private final List<ConnectionRecordSortPredicate> connectionRecordSortPredicates =
|
|
||||||
new ArrayList<ConnectionRecordSortPredicate>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ConnectionRecord> asCollection()
|
protected Collection<ConnectionRecord> retrieveHistory(
|
||||||
|
AuthenticatedUser user, Set<ActivityRecordSearchTerm> requiredContents,
|
||||||
|
List<ActivityRecordSortPredicate> sortPredicates, int limit)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
// Retrieve history from database
|
||||||
return connectionService.retrieveHistory(getCurrentUser(),
|
return connectionService.retrieveHistory(getCurrentUser(),
|
||||||
requiredContents, connectionRecordSortPredicates, limit);
|
requiredContents, sortPredicates, limit);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConnectionRecordSet contains(String value)
|
|
||||||
throws GuacamoleException {
|
|
||||||
requiredContents.add(new ConnectionRecordSearchTerm(value));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConnectionRecordSet limit(int limit) throws GuacamoleException {
|
|
||||||
this.limit = Math.min(this.limit, limit);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConnectionRecordSet sort(SortableProperty property, boolean desc)
|
|
||||||
throws GuacamoleException {
|
|
||||||
|
|
||||||
connectionRecordSortPredicates.add(new ConnectionRecordSortPredicate(
|
|
||||||
property,
|
|
||||||
desc
|
|
||||||
));
|
|
||||||
|
|
||||||
return this;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -34,6 +34,8 @@ import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
|||||||
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.GuacamoleSecurityException;
|
||||||
|
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
|
||||||
|
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
|
||||||
import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService;
|
import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService;
|
||||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
|
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
|
||||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
|
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
|
||||||
@@ -460,8 +462,8 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
|
|||||||
* If permission to read the connection history is denied.
|
* If permission to read the connection history is denied.
|
||||||
*/
|
*/
|
||||||
public List<ConnectionRecord> retrieveHistory(ModeledAuthenticatedUser user,
|
public List<ConnectionRecord> retrieveHistory(ModeledAuthenticatedUser user,
|
||||||
Collection<ConnectionRecordSearchTerm> requiredContents,
|
Collection<ActivityRecordSearchTerm> requiredContents,
|
||||||
List<ConnectionRecordSortPredicate> sortPredicates, int limit)
|
List<ActivityRecordSortPredicate> sortPredicates, int limit)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
List<ConnectionRecordModel> searchResults;
|
List<ConnectionRecordModel> searchResults;
|
||||||
|
@@ -235,7 +235,7 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date getLastActive() {
|
public Date getLastActive() {
|
||||||
return null;
|
return getModel().getLastActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -20,13 +20,14 @@
|
|||||||
package org.apache.guacamole.auth.jdbc.connection;
|
package org.apache.guacamole.auth.jdbc.connection;
|
||||||
|
|
||||||
|
|
||||||
import java.util.Date;
|
import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord;
|
||||||
import org.apache.guacamole.net.auth.ConnectionRecord;
|
import org.apache.guacamole.net.auth.ConnectionRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ConnectionRecord which is backed by a database model.
|
* A ConnectionRecord which is backed by a database model.
|
||||||
*/
|
*/
|
||||||
public class ModeledConnectionRecord implements ConnectionRecord {
|
public class ModeledConnectionRecord extends ModeledActivityRecord
|
||||||
|
implements ConnectionRecord {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The model object backing this connection record.
|
* The model object backing this connection record.
|
||||||
@@ -42,6 +43,7 @@ public class ModeledConnectionRecord implements ConnectionRecord {
|
|||||||
* The model object to use to back this connection record.
|
* The model object to use to back this connection record.
|
||||||
*/
|
*/
|
||||||
public ModeledConnectionRecord(ConnectionRecordModel model) {
|
public ModeledConnectionRecord(ConnectionRecordModel model) {
|
||||||
|
super(model);
|
||||||
this.model = model;
|
this.model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,29 +67,4 @@ public class ModeledConnectionRecord implements ConnectionRecord {
|
|||||||
return model.getSharingProfileName();
|
return model.getSharingProfileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Date getStartDate() {
|
|
||||||
return model.getStartDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Date getEndDate() {
|
|
||||||
return model.getEndDate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRemoteHost() {
|
|
||||||
return model.getRemoteHost();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsername() {
|
|
||||||
return model.getUsername();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isActive() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -144,6 +144,12 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
|
|||||||
ACCOUNT_RESTRICTIONS
|
ACCOUNT_RESTRICTIONS
|
||||||
));
|
));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for managing users.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for hashing passwords.
|
* Service for hashing passwords.
|
||||||
*/
|
*/
|
||||||
@@ -795,13 +801,13 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date getLastActive() {
|
public Timestamp getLastActive() {
|
||||||
return null;
|
return getModel().getLastActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ActivityRecord> getHistory() throws GuacamoleException {
|
public List<ActivityRecord> getHistory() throws GuacamoleException {
|
||||||
return Collections.<ActivityRecord>emptyList();
|
return userService.retrieveHistory(getCurrentUser(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -26,9 +26,11 @@ import org.apache.guacamole.auth.jdbc.connection.ConnectionDirectory;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
|
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
|
||||||
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionDirectory;
|
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionDirectory;
|
||||||
|
import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
|
||||||
import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordSet;
|
import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordSet;
|
||||||
import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
|
import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||||
import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
||||||
@@ -44,7 +46,6 @@ import org.apache.guacamole.net.auth.ConnectionGroup;
|
|||||||
import org.apache.guacamole.net.auth.Directory;
|
import org.apache.guacamole.net.auth.Directory;
|
||||||
import org.apache.guacamole.net.auth.SharingProfile;
|
import org.apache.guacamole.net.auth.SharingProfile;
|
||||||
import org.apache.guacamole.net.auth.User;
|
import org.apache.guacamole.net.auth.User;
|
||||||
import org.apache.guacamole.net.auth.simple.SimpleActivityRecordSet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UserContext implementation which is driven by an arbitrary, underlying
|
* UserContext implementation which is driven by an arbitrary, underlying
|
||||||
@@ -99,7 +100,24 @@ public class ModeledUserContext extends RestrictedObject
|
|||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
private Provider<ConnectionRecordSet> connectionRecordSetProvider;
|
private Provider<ConnectionRecordSet> connectionRecordSetProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for creating user record sets.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private Provider<UserRecordSet> userRecordSetProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapper for user login records.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private UserRecordMapper userRecordMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The activity record associated with this user's Guacamole session.
|
||||||
|
*/
|
||||||
|
private ActivityRecordModel userRecord;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(ModeledAuthenticatedUser currentUser) {
|
public void init(ModeledAuthenticatedUser currentUser) {
|
||||||
|
|
||||||
@@ -112,6 +130,15 @@ public class ModeledUserContext extends RestrictedObject
|
|||||||
sharingProfileDirectory.init(currentUser);
|
sharingProfileDirectory.init(currentUser);
|
||||||
activeConnectionDirectory.init(currentUser);
|
activeConnectionDirectory.init(currentUser);
|
||||||
|
|
||||||
|
// Create login record for user
|
||||||
|
userRecord = new ActivityRecordModel();
|
||||||
|
userRecord.setUsername(currentUser.getIdentifier());
|
||||||
|
userRecord.setStartDate(new Date());
|
||||||
|
userRecord.setRemoteHost(currentUser.getCredentials().getRemoteHostname());
|
||||||
|
|
||||||
|
// Insert record representing login
|
||||||
|
userRecordMapper.insert(userRecord);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -167,7 +194,9 @@ public class ModeledUserContext extends RestrictedObject
|
|||||||
@Override
|
@Override
|
||||||
public ActivityRecordSet<ActivityRecord> getUserHistory()
|
public ActivityRecordSet<ActivityRecord> getUserHistory()
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
return new SimpleActivityRecordSet<ActivityRecord>();
|
UserRecordSet userRecordSet = userRecordSetProvider.get();
|
||||||
|
userRecordSet.init(getCurrentUser());
|
||||||
|
return userRecordSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -202,7 +231,11 @@ public class ModeledUserContext extends RestrictedObject
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
// Nothing to invalidate
|
|
||||||
|
// Record logout time
|
||||||
|
userRecord.setEndDate(new Date());
|
||||||
|
userRecordMapper.update(userRecord);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -114,6 +114,12 @@ public class UserModel extends ObjectModel {
|
|||||||
*/
|
*/
|
||||||
private String organizationalRole;
|
private String organizationalRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date and time that this user was last active, or null if this user
|
||||||
|
* has never logged in.
|
||||||
|
*/
|
||||||
|
private Timestamp lastActive;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new, empty user.
|
* Creates a new, empty user.
|
||||||
*/
|
*/
|
||||||
@@ -465,4 +471,30 @@ public class UserModel extends ObjectModel {
|
|||||||
this.organizationalRole = organizationalRole;
|
this.organizationalRole = organizationalRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the date and time that this user was last active, or null if
|
||||||
|
* this user has never logged in.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The date and time that this user was last active, or null if this
|
||||||
|
* user has never logged in.
|
||||||
|
*/
|
||||||
|
public Timestamp getLastActive() {
|
||||||
|
return lastActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the date and time that this user was last active. This value is
|
||||||
|
* expected to be set automatically via queries, derived from user history
|
||||||
|
* records. It does NOT correspond to an actual column, and values set
|
||||||
|
* manually through invoking this function will not persist.
|
||||||
|
*
|
||||||
|
* @param lastActive
|
||||||
|
* The date and time that this user was last active, or null if this
|
||||||
|
* user has never logged in.
|
||||||
|
*/
|
||||||
|
public void setLastActive(Timestamp lastActive) {
|
||||||
|
this.lastActive = lastActive;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* 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 java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
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.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapper for user login activity records.
|
||||||
|
*/
|
||||||
|
public interface UserRecordMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of all user login records associated with the user
|
||||||
|
* having the given username.
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* The username of the user whose login records are to be retrieved.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A collection of all user login records associated with the user
|
||||||
|
* having the given username. This collection will be empty if no such
|
||||||
|
* user exists.
|
||||||
|
*/
|
||||||
|
List<ActivityRecordModel> select(@Param("username") String username);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the given user login record.
|
||||||
|
*
|
||||||
|
* @param record
|
||||||
|
* The user login record to insert.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The number of rows inserted.
|
||||||
|
*/
|
||||||
|
int insert(@Param("record") ActivityRecordModel record);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the given user login record.
|
||||||
|
*
|
||||||
|
* @param record
|
||||||
|
* The user login record to update.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The number of rows updated.
|
||||||
|
*/
|
||||||
|
int update(@Param("record") ActivityRecordModel record);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for up to <code>limit</code> user login records that contain
|
||||||
|
* the given terms, sorted by the given predicates, regardless of whether
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param terms
|
||||||
|
* The search terms that must match 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 results of the search performed with the given parameters.
|
||||||
|
*/
|
||||||
|
List<ActivityRecordModel> search(@Param("terms") Collection<ActivityRecordSearchTerm> terms,
|
||||||
|
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
|
||||||
|
@Param("limit") int limit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for up to <code>limit</code> user login records that contain
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user whose permissions should determine whether a record is
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* @param terms
|
||||||
|
* The search terms that must match 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 results of the search performed with the given parameters.
|
||||||
|
*/
|
||||||
|
List<ActivityRecordModel> searchReadable(@Param("user") UserModel user,
|
||||||
|
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
|
||||||
|
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
|
||||||
|
@Param("limit") int limit);
|
||||||
|
|
||||||
|
}
|
@@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -21,16 +21,24 @@ package org.apache.guacamole.auth.jdbc.user;
|
|||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.apache.guacamole.net.auth.Credentials;
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
|
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.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.ObjectPermissionMapper;
|
||||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
|
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
|
||||||
import org.apache.guacamole.auth.jdbc.permission.UserPermissionMapper;
|
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.auth.jdbc.security.PasswordPolicyService;
|
||||||
import org.apache.guacamole.form.Field;
|
import org.apache.guacamole.form.Field;
|
||||||
import org.apache.guacamole.form.PasswordField;
|
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.AuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
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.User;
|
||||||
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||||
import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
|
import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
|
||||||
@@ -116,7 +126,13 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
|||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
private UserPermissionMapper userPermissionMapper;
|
private UserPermissionMapper userPermissionMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapper for accessing user login history.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private UserRecordMapper userRecordMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provider for creating users.
|
* 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -336,6 +336,7 @@ CREATE TABLE `guacamole_connection_history` (
|
|||||||
KEY `sharing_profile_id` (`sharing_profile_id`),
|
KEY `sharing_profile_id` (`sharing_profile_id`),
|
||||||
KEY `start_date` (`start_date`),
|
KEY `start_date` (`start_date`),
|
||||||
KEY `end_date` (`end_date`),
|
KEY `end_date` (`end_date`),
|
||||||
|
KEY `connection_start_date` (`connection_id`, `start_date`),
|
||||||
|
|
||||||
CONSTRAINT `guacamole_connection_history_ibfk_1`
|
CONSTRAINT `guacamole_connection_history_ibfk_1`
|
||||||
FOREIGN KEY (`user_id`)
|
FOREIGN KEY (`user_id`)
|
||||||
@@ -351,6 +352,31 @@ CREATE TABLE `guacamole_connection_history` (
|
|||||||
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- User login/logout history
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE guacamole_user_history (
|
||||||
|
|
||||||
|
`history_id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` int(11) DEFAULT NULL,
|
||||||
|
`username` varchar(128) NOT NULL,
|
||||||
|
`remote_host` varchar(256) DEFAULT NULL,
|
||||||
|
`start_date` datetime NOT NULL,
|
||||||
|
`end_date` datetime DEFAULT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (history_id),
|
||||||
|
KEY `user_id` (`user_id`),
|
||||||
|
KEY `start_date` (`start_date`),
|
||||||
|
KEY `end_date` (`end_date`),
|
||||||
|
KEY `user_start_date` (`user_id`, `start_date`),
|
||||||
|
|
||||||
|
CONSTRAINT guacamole_user_history_ibfk_1
|
||||||
|
FOREIGN KEY (user_id)
|
||||||
|
REFERENCES guacamole_user (user_id) ON DELETE SET NULL
|
||||||
|
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- User password history
|
-- User password history
|
||||||
--
|
--
|
||||||
|
@@ -37,3 +37,34 @@ ALTER TABLE guacamole_connection
|
|||||||
|
|
||||||
ALTER TABLE guacamole_connection_history
|
ALTER TABLE guacamole_connection_history
|
||||||
ADD COLUMN remote_host VARCHAR(256) DEFAULT NULL;
|
ADD COLUMN remote_host VARCHAR(256) DEFAULT NULL;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Add covering index for connection history connection and start date
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE guacamole_connection_history ADD KEY (connection_id, start_date);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- User login/logout history
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE guacamole_user_history (
|
||||||
|
|
||||||
|
`history_id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` int(11) DEFAULT NULL,
|
||||||
|
`username` varchar(128) NOT NULL,
|
||||||
|
`remote_host` varchar(256) DEFAULT NULL,
|
||||||
|
`start_date` datetime NOT NULL,
|
||||||
|
`end_date` datetime DEFAULT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (history_id),
|
||||||
|
KEY `user_id` (`user_id`),
|
||||||
|
KEY `start_date` (`start_date`),
|
||||||
|
KEY `end_date` (`end_date`),
|
||||||
|
KEY `user_start_date` (`user_id`, `start_date`),
|
||||||
|
|
||||||
|
CONSTRAINT guacamole_user_history_ibfk_1
|
||||||
|
FOREIGN KEY (user_id)
|
||||||
|
REFERENCES guacamole_user (user_id) ON DELETE SET NULL
|
||||||
|
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
|
javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
|
||||||
<result column="connection_weight" property="connectionWeight" jdbcType="INTEGER"/>
|
<result column="connection_weight" property="connectionWeight" jdbcType="INTEGER"/>
|
||||||
<result column="failover_only" property="failoverOnly" jdbcType="BOOLEAN"/>
|
<result column="failover_only" property="failoverOnly" jdbcType="BOOLEAN"/>
|
||||||
|
<result column="last_active" property="lastActive" jdbcType="TIMESTAMP"/>
|
||||||
|
|
||||||
<!-- Associated sharing profiles -->
|
<!-- Associated sharing profiles -->
|
||||||
<collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
|
<collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
|
||||||
@@ -89,8 +90,8 @@
|
|||||||
resultSets="connections,sharingProfiles">
|
resultSets="connections,sharingProfiles">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
connection_id,
|
guacamole_connection.connection_id,
|
||||||
connection_name,
|
guacamole_connection.connection_name,
|
||||||
parent_id,
|
parent_id,
|
||||||
protocol,
|
protocol,
|
||||||
max_connections,
|
max_connections,
|
||||||
@@ -99,13 +100,16 @@
|
|||||||
proxy_port,
|
proxy_port,
|
||||||
proxy_encryption_method,
|
proxy_encryption_method,
|
||||||
connection_weight,
|
connection_weight,
|
||||||
failover_only
|
failover_only,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_connection
|
FROM guacamole_connection
|
||||||
WHERE connection_id IN
|
LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
|
||||||
|
WHERE guacamole_connection.connection_id IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=VARCHAR}
|
#{identifier,jdbcType=VARCHAR}
|
||||||
</foreach>;
|
</foreach>
|
||||||
|
GROUP BY guacamole_connection.connection_id;
|
||||||
|
|
||||||
SELECT primary_connection_id, sharing_profile_id
|
SELECT primary_connection_id, sharing_profile_id
|
||||||
FROM guacamole_sharing_profile
|
FROM guacamole_sharing_profile
|
||||||
@@ -123,7 +127,7 @@
|
|||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
guacamole_connection.connection_id,
|
guacamole_connection.connection_id,
|
||||||
connection_name,
|
guacamole_connection.connection_name,
|
||||||
parent_id,
|
parent_id,
|
||||||
protocol,
|
protocol,
|
||||||
max_connections,
|
max_connections,
|
||||||
@@ -132,16 +136,19 @@
|
|||||||
proxy_port,
|
proxy_port,
|
||||||
proxy_encryption_method,
|
proxy_encryption_method,
|
||||||
connection_weight,
|
connection_weight,
|
||||||
failover_only
|
failover_only,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_connection
|
FROM guacamole_connection
|
||||||
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
|
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
|
||||||
|
LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
|
||||||
WHERE guacamole_connection.connection_id IN
|
WHERE guacamole_connection.connection_id IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=VARCHAR}
|
#{identifier,jdbcType=VARCHAR}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND user_id = #{user.objectID,jdbcType=INTEGER}
|
AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
|
||||||
AND permission = 'READ';
|
AND permission = 'READ'
|
||||||
|
GROUP BY guacamole_connection.connection_id;
|
||||||
|
|
||||||
SELECT primary_connection_id, guacamole_sharing_profile.sharing_profile_id
|
SELECT primary_connection_id, guacamole_sharing_profile.sharing_profile_id
|
||||||
FROM guacamole_sharing_profile
|
FROM guacamole_sharing_profile
|
||||||
@@ -160,8 +167,8 @@
|
|||||||
<select id="selectOneByName" resultMap="ConnectionResultMap">
|
<select id="selectOneByName" resultMap="ConnectionResultMap">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
connection_id,
|
guacamole_connection.connection_id,
|
||||||
connection_name,
|
guacamole_connection.connection_name,
|
||||||
parent_id,
|
parent_id,
|
||||||
protocol,
|
protocol,
|
||||||
max_connections,
|
max_connections,
|
||||||
@@ -170,12 +177,15 @@
|
|||||||
proxy_port,
|
proxy_port,
|
||||||
proxy_encryption_method,
|
proxy_encryption_method,
|
||||||
connection_weight,
|
connection_weight,
|
||||||
failover_only
|
failover_only,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_connection
|
FROM guacamole_connection
|
||||||
|
LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
|
||||||
WHERE
|
WHERE
|
||||||
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
|
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
|
||||||
<if test="parentIdentifier == null">parent_id IS NULL</if>
|
<if test="parentIdentifier == null">parent_id IS NULL</if>
|
||||||
AND connection_name = #{name,jdbcType=VARCHAR}
|
AND guacamole_connection.connection_name = #{name,jdbcType=VARCHAR}
|
||||||
|
GROUP BY guacamole_connection.connection_id
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@@ -41,6 +41,7 @@
|
|||||||
<result column="email_address" property="emailAddress" jdbcType="VARCHAR"/>
|
<result column="email_address" property="emailAddress" jdbcType="VARCHAR"/>
|
||||||
<result column="organization" property="organization" jdbcType="VARCHAR"/>
|
<result column="organization" property="organization" jdbcType="VARCHAR"/>
|
||||||
<result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
|
<result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
|
||||||
|
<result column="last_active" property="lastActive" jdbcType="TIMESTAMP"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<!-- Select all usernames -->
|
<!-- Select all usernames -->
|
||||||
@@ -63,8 +64,8 @@
|
|||||||
<select id="select" resultMap="UserResultMap">
|
<select id="select" resultMap="UserResultMap">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
user_id,
|
guacamole_user.user_id,
|
||||||
username,
|
guacamole_user.username,
|
||||||
password_hash,
|
password_hash,
|
||||||
password_salt,
|
password_salt,
|
||||||
password_date,
|
password_date,
|
||||||
@@ -78,13 +79,16 @@
|
|||||||
full_name,
|
full_name,
|
||||||
email_address,
|
email_address,
|
||||||
organization,
|
organization,
|
||||||
organizational_role
|
organizational_role,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_user
|
FROM guacamole_user
|
||||||
WHERE username IN
|
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
|
||||||
|
WHERE guacamole_user.username IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=VARCHAR}
|
#{identifier,jdbcType=VARCHAR}
|
||||||
</foreach>
|
</foreach>
|
||||||
|
GROUP BY guacamole_user.user_id
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -93,7 +97,7 @@
|
|||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
guacamole_user.user_id,
|
guacamole_user.user_id,
|
||||||
username,
|
guacamole_user.username,
|
||||||
password_hash,
|
password_hash,
|
||||||
password_salt,
|
password_salt,
|
||||||
password_date,
|
password_date,
|
||||||
@@ -107,16 +111,19 @@
|
|||||||
full_name,
|
full_name,
|
||||||
email_address,
|
email_address,
|
||||||
organization,
|
organization,
|
||||||
organizational_role
|
organizational_role,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_user
|
FROM guacamole_user
|
||||||
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
|
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
|
||||||
WHERE username IN
|
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
|
||||||
|
WHERE guacamole_user.username IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=VARCHAR}
|
#{identifier,jdbcType=VARCHAR}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
|
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
|
||||||
AND permission = 'READ'
|
AND permission = 'READ'
|
||||||
|
GROUP BY guacamole_user.user_id
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -124,8 +131,8 @@
|
|||||||
<select id="selectOne" resultMap="UserResultMap">
|
<select id="selectOne" resultMap="UserResultMap">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
user_id,
|
guacamole_user.user_id,
|
||||||
username,
|
guacamole_user.username,
|
||||||
password_hash,
|
password_hash,
|
||||||
password_salt,
|
password_salt,
|
||||||
password_date,
|
password_date,
|
||||||
@@ -139,10 +146,13 @@
|
|||||||
full_name,
|
full_name,
|
||||||
email_address,
|
email_address,
|
||||||
organization,
|
organization,
|
||||||
organizational_role
|
organizational_role,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_user
|
FROM guacamole_user
|
||||||
|
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
|
||||||
WHERE
|
WHERE
|
||||||
username = #{username,jdbcType=VARCHAR}
|
guacamole_user.username = #{username,jdbcType=VARCHAR}
|
||||||
|
GROUP BY guacamole_user.user_id
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@@ -0,0 +1,187 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserRecordMapper" >
|
||||||
|
|
||||||
|
<!-- Result mapper for system permissions -->
|
||||||
|
<resultMap id="UserRecordResultMap" type="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
|
||||||
|
<id column="history_id" property="recordID" jdbcType="INTEGER"/>
|
||||||
|
<result column="remote_host" property="remoteHost" jdbcType="VARCHAR"/>
|
||||||
|
<result column="user_id" property="userID" jdbcType="INTEGER"/>
|
||||||
|
<result column="username" property="username" jdbcType="VARCHAR"/>
|
||||||
|
<result column="start_date" property="startDate" jdbcType="TIMESTAMP"/>
|
||||||
|
<result column="end_date" property="endDate" jdbcType="TIMESTAMP"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- Select all user records from a given user -->
|
||||||
|
<select id="select" resultMap="UserRecordResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
guacamole_user_history.remote_host,
|
||||||
|
guacamole_user_history.user_id,
|
||||||
|
guacamole_user_history.username,
|
||||||
|
guacamole_user_history.start_date,
|
||||||
|
guacamole_user_history.end_date
|
||||||
|
FROM guacamole_user_history
|
||||||
|
JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id
|
||||||
|
WHERE
|
||||||
|
guacamole_user.username = #{username,jdbcType=VARCHAR}
|
||||||
|
ORDER BY
|
||||||
|
guacamole_user_history.start_date DESC,
|
||||||
|
guacamole_user_history.end_date DESC
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- Insert the given user record -->
|
||||||
|
<insert id="insert" useGeneratedKeys="true" keyProperty="record.recordID"
|
||||||
|
parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
|
||||||
|
|
||||||
|
INSERT INTO guacamole_user_history (
|
||||||
|
remote_host,
|
||||||
|
user_id,
|
||||||
|
username,
|
||||||
|
start_date,
|
||||||
|
end_date
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
#{record.remoteHost,jdbcType=VARCHAR},
|
||||||
|
(SELECT user_id FROM guacamole_user
|
||||||
|
WHERE username = #{record.username,jdbcType=VARCHAR}),
|
||||||
|
#{record.username,jdbcType=VARCHAR},
|
||||||
|
#{record.startDate,jdbcType=TIMESTAMP},
|
||||||
|
#{record.endDate,jdbcType=TIMESTAMP}
|
||||||
|
)
|
||||||
|
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<!-- Update the given user record -->
|
||||||
|
<update id="update" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
|
||||||
|
UPDATE guacamole_user_history
|
||||||
|
SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
|
||||||
|
user_id = (SELECT user_id FROM guacamole_user
|
||||||
|
WHERE username = #{record.username,jdbcType=VARCHAR}),
|
||||||
|
username = #{record.username,jdbcType=VARCHAR},
|
||||||
|
start_date = #{record.startDate,jdbcType=TIMESTAMP},
|
||||||
|
end_date = #{record.endDate,jdbcType=TIMESTAMP}
|
||||||
|
WHERE history_id = #{record.recordID,jdbcType=INTEGER}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- Search for specific user records -->
|
||||||
|
<select id="search" resultMap="UserRecordResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
guacamole_user_history.remote_host,
|
||||||
|
guacamole_user_history.user_id,
|
||||||
|
guacamole_user_history.username,
|
||||||
|
guacamole_user_history.start_date,
|
||||||
|
guacamole_user_history.end_date
|
||||||
|
FROM guacamole_user_history
|
||||||
|
|
||||||
|
<!-- Search terms -->
|
||||||
|
<foreach collection="terms" item="term"
|
||||||
|
open="WHERE " separator=" AND ">
|
||||||
|
(
|
||||||
|
|
||||||
|
guacamole_user_history.user_id IN (
|
||||||
|
SELECT user_id
|
||||||
|
FROM guacamole_user
|
||||||
|
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 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 name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
|
||||||
|
|
||||||
|
<!-- Sort predicates -->
|
||||||
|
<foreach collection="sortPredicates" item="sortPredicate"
|
||||||
|
open="ORDER BY " separator=", ">
|
||||||
|
<choose>
|
||||||
|
<when test="sortPredicate.property == START_DATE">guacamole_user_history.start_date</when>
|
||||||
|
<otherwise>1</otherwise>
|
||||||
|
</choose>
|
||||||
|
<if test="sortPredicate.descending">DESC</if>
|
||||||
|
</foreach>
|
||||||
|
|
||||||
|
LIMIT #{limit,jdbcType=INTEGER}
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- Search for specific user records -->
|
||||||
|
<select id="searchReadable" resultMap="UserRecordResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
guacamole_user_history.remote_host,
|
||||||
|
guacamole_user_history.user_id,
|
||||||
|
guacamole_user_history.username,
|
||||||
|
guacamole_user_history.start_date,
|
||||||
|
guacamole_user_history.end_date
|
||||||
|
FROM guacamole_user_history
|
||||||
|
|
||||||
|
<!-- Restrict to readable users -->
|
||||||
|
JOIN guacamole_user_permission ON
|
||||||
|
guacamole_user_history.user_id = guacamole_user_permission.affected_user_id
|
||||||
|
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
|
||||||
|
AND guacamole_user_permission.permission = 'READ'
|
||||||
|
|
||||||
|
<!-- Search terms -->
|
||||||
|
<foreach collection="terms" item="term"
|
||||||
|
open="WHERE " separator=" AND ">
|
||||||
|
(
|
||||||
|
|
||||||
|
guacamole_user_history.user_id IN (
|
||||||
|
SELECT user_id
|
||||||
|
FROM guacamole_user
|
||||||
|
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 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 name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
|
||||||
|
|
||||||
|
<!-- Sort predicates -->
|
||||||
|
<foreach collection="sortPredicates" item="sortPredicate"
|
||||||
|
open="ORDER BY " separator=", ">
|
||||||
|
<choose>
|
||||||
|
<when test="sortPredicate.property == START_DATE">guacamole_user_history.start_date</when>
|
||||||
|
<otherwise>1</otherwise>
|
||||||
|
</choose>
|
||||||
|
<if test="sortPredicate.descending">DESC</if>
|
||||||
|
</foreach>
|
||||||
|
|
||||||
|
LIMIT #{limit,jdbcType=INTEGER}
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
@@ -438,6 +438,42 @@ CREATE INDEX guacamole_connection_history_start_date
|
|||||||
CREATE INDEX guacamole_connection_history_end_date
|
CREATE INDEX guacamole_connection_history_end_date
|
||||||
ON guacamole_connection_history(end_date);
|
ON guacamole_connection_history(end_date);
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_connection_history_connection_id_start_date
|
||||||
|
ON guacamole_connection_history(connection_id, start_date);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- User login/logout history
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE guacamole_user_history (
|
||||||
|
|
||||||
|
history_id serial NOT NULL,
|
||||||
|
user_id integer DEFAULT NULL,
|
||||||
|
username varchar(128) NOT NULL,
|
||||||
|
remote_host varchar(256) DEFAULT NULL,
|
||||||
|
start_date timestamptz NOT NULL,
|
||||||
|
end_date timestamptz DEFAULT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (history_id),
|
||||||
|
|
||||||
|
CONSTRAINT guacamole_user_history_ibfk_1
|
||||||
|
FOREIGN KEY (user_id)
|
||||||
|
REFERENCES guacamole_user (user_id) ON DELETE SET NULL
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_user_history_user_id
|
||||||
|
ON guacamole_user_history(user_id);
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_user_history_start_date
|
||||||
|
ON guacamole_user_history(start_date);
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_user_history_end_date
|
||||||
|
ON guacamole_user_history(end_date);
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_user_history_user_id_start_date
|
||||||
|
ON guacamole_user_history(user_id, start_date);
|
||||||
|
|
||||||
--
|
--
|
||||||
-- User password history
|
-- User password history
|
||||||
--
|
--
|
||||||
|
@@ -37,3 +37,43 @@ ALTER TABLE guacamole_connection
|
|||||||
|
|
||||||
ALTER TABLE guacamole_connection_history
|
ALTER TABLE guacamole_connection_history
|
||||||
ADD COLUMN remote_host VARCHAR(256) DEFAULT NULL;
|
ADD COLUMN remote_host VARCHAR(256) DEFAULT NULL;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Add covering index for connection history connection and start date
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_connection_history_connection_id_start_date
|
||||||
|
ON guacamole_connection_history(connection_id, start_date);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- User login/logout history
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE guacamole_user_history (
|
||||||
|
|
||||||
|
history_id serial NOT NULL,
|
||||||
|
user_id integer DEFAULT NULL,
|
||||||
|
username varchar(128) NOT NULL,
|
||||||
|
remote_host varchar(256) DEFAULT NULL,
|
||||||
|
start_date timestamptz NOT NULL,
|
||||||
|
end_date timestamptz DEFAULT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (history_id),
|
||||||
|
|
||||||
|
CONSTRAINT guacamole_user_history_ibfk_1
|
||||||
|
FOREIGN KEY (user_id)
|
||||||
|
REFERENCES guacamole_user (user_id) ON DELETE SET NULL
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_user_history_user_id
|
||||||
|
ON guacamole_user_history(user_id);
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_user_history_start_date
|
||||||
|
ON guacamole_user_history(start_date);
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_user_history_end_date
|
||||||
|
ON guacamole_user_history(end_date);
|
||||||
|
|
||||||
|
CREATE INDEX guacamole_user_history_user_id_start_date
|
||||||
|
ON guacamole_user_history(user_id, start_date);
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
|
javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
|
||||||
<result column="connection_weight" property="connectionWeight" jdbcType="INTEGER"/>
|
<result column="connection_weight" property="connectionWeight" jdbcType="INTEGER"/>
|
||||||
<result column="failover_only" property="failoverOnly" jdbcType="BOOLEAN"/>
|
<result column="failover_only" property="failoverOnly" jdbcType="BOOLEAN"/>
|
||||||
|
<result column="last_active" property="lastActive" jdbcType="TIMESTAMP"/>
|
||||||
|
|
||||||
<!-- Associated sharing profiles -->
|
<!-- Associated sharing profiles -->
|
||||||
<collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
|
<collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
|
||||||
@@ -89,8 +90,8 @@
|
|||||||
resultSets="connections,sharingProfiles">
|
resultSets="connections,sharingProfiles">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
connection_id,
|
guacamole_connection.connection_id,
|
||||||
connection_name,
|
guacamole_connection.connection_name,
|
||||||
parent_id,
|
parent_id,
|
||||||
protocol,
|
protocol,
|
||||||
max_connections,
|
max_connections,
|
||||||
@@ -99,13 +100,16 @@
|
|||||||
proxy_port,
|
proxy_port,
|
||||||
proxy_encryption_method,
|
proxy_encryption_method,
|
||||||
connection_weight,
|
connection_weight,
|
||||||
failover_only
|
failover_only,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_connection
|
FROM guacamole_connection
|
||||||
WHERE connection_id IN
|
LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
|
||||||
|
WHERE guacamole_connection.connection_id IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=INTEGER}::integer
|
#{identifier,jdbcType=INTEGER}::integer
|
||||||
</foreach>;
|
</foreach>
|
||||||
|
GROUP BY guacamole_connection.connection_id;
|
||||||
|
|
||||||
SELECT primary_connection_id, sharing_profile_id
|
SELECT primary_connection_id, sharing_profile_id
|
||||||
FROM guacamole_sharing_profile
|
FROM guacamole_sharing_profile
|
||||||
@@ -123,7 +127,7 @@
|
|||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
guacamole_connection.connection_id,
|
guacamole_connection.connection_id,
|
||||||
connection_name,
|
guacamole_connection.connection_name,
|
||||||
parent_id,
|
parent_id,
|
||||||
protocol,
|
protocol,
|
||||||
max_connections,
|
max_connections,
|
||||||
@@ -132,16 +136,19 @@
|
|||||||
proxy_port,
|
proxy_port,
|
||||||
proxy_encryption_method,
|
proxy_encryption_method,
|
||||||
connection_weight,
|
connection_weight,
|
||||||
failover_only
|
failover_only,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_connection
|
FROM guacamole_connection
|
||||||
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
|
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
|
||||||
|
LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
|
||||||
WHERE guacamole_connection.connection_id IN
|
WHERE guacamole_connection.connection_id IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=INTEGER}::integer
|
#{identifier,jdbcType=INTEGER}::integer
|
||||||
</foreach>
|
</foreach>
|
||||||
AND user_id = #{user.objectID,jdbcType=INTEGER}
|
AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
|
||||||
AND permission = 'READ';
|
AND permission = 'READ'
|
||||||
|
GROUP BY guacamole_connection.connection_id;
|
||||||
|
|
||||||
SELECT primary_connection_id, guacamole_sharing_profile.sharing_profile_id
|
SELECT primary_connection_id, guacamole_sharing_profile.sharing_profile_id
|
||||||
FROM guacamole_sharing_profile
|
FROM guacamole_sharing_profile
|
||||||
@@ -160,8 +167,8 @@
|
|||||||
<select id="selectOneByName" resultMap="ConnectionResultMap">
|
<select id="selectOneByName" resultMap="ConnectionResultMap">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
connection_id,
|
guacamole_connection.connection_id,
|
||||||
connection_name,
|
guacamole_connection.connection_name,
|
||||||
parent_id,
|
parent_id,
|
||||||
protocol,
|
protocol,
|
||||||
max_connections,
|
max_connections,
|
||||||
@@ -170,12 +177,15 @@
|
|||||||
proxy_port,
|
proxy_port,
|
||||||
proxy_encryption_method,
|
proxy_encryption_method,
|
||||||
connection_weight,
|
connection_weight,
|
||||||
failover_only
|
failover_only,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_connection
|
FROM guacamole_connection
|
||||||
|
LEFT JOIN guacamole_connection_history ON guacamole_connection_history.connection_id = guacamole_connection.connection_id
|
||||||
WHERE
|
WHERE
|
||||||
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
|
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
|
||||||
<if test="parentIdentifier == null">parent_id IS NULL</if>
|
<if test="parentIdentifier == null">parent_id IS NULL</if>
|
||||||
AND connection_name = #{name,jdbcType=VARCHAR}
|
AND guacamole_connection.connection_name = #{name,jdbcType=VARCHAR}
|
||||||
|
GROUP BY guacamole_connection.connection_id
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@@ -41,6 +41,7 @@
|
|||||||
<result column="email_address" property="emailAddress" jdbcType="VARCHAR"/>
|
<result column="email_address" property="emailAddress" jdbcType="VARCHAR"/>
|
||||||
<result column="organization" property="organization" jdbcType="VARCHAR"/>
|
<result column="organization" property="organization" jdbcType="VARCHAR"/>
|
||||||
<result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
|
<result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
|
||||||
|
<result column="last_active" property="lastActive" jdbcType="TIMESTAMP"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<!-- Select all usernames -->
|
<!-- Select all usernames -->
|
||||||
@@ -63,8 +64,8 @@
|
|||||||
<select id="select" resultMap="UserResultMap">
|
<select id="select" resultMap="UserResultMap">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
user_id,
|
guacamole_user.user_id,
|
||||||
username,
|
guacamole_user.username,
|
||||||
password_hash,
|
password_hash,
|
||||||
password_salt,
|
password_salt,
|
||||||
password_date,
|
password_date,
|
||||||
@@ -78,13 +79,16 @@
|
|||||||
full_name,
|
full_name,
|
||||||
email_address,
|
email_address,
|
||||||
organization,
|
organization,
|
||||||
organizational_role
|
organizational_role,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_user
|
FROM guacamole_user
|
||||||
WHERE username IN
|
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
|
||||||
|
WHERE guacamole_user.username IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=VARCHAR}
|
#{identifier,jdbcType=VARCHAR}
|
||||||
</foreach>
|
</foreach>
|
||||||
|
GROUP BY guacamole_user.user_id
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -93,7 +97,7 @@
|
|||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
guacamole_user.user_id,
|
guacamole_user.user_id,
|
||||||
username,
|
guacamole_user.username,
|
||||||
password_hash,
|
password_hash,
|
||||||
password_salt,
|
password_salt,
|
||||||
password_date,
|
password_date,
|
||||||
@@ -107,16 +111,19 @@
|
|||||||
full_name,
|
full_name,
|
||||||
email_address,
|
email_address,
|
||||||
organization,
|
organization,
|
||||||
organizational_role
|
organizational_role,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_user
|
FROM guacamole_user
|
||||||
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
|
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
|
||||||
WHERE username IN
|
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
|
||||||
|
WHERE guacamole_user.username IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=VARCHAR}
|
#{identifier,jdbcType=VARCHAR}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
|
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
|
||||||
AND permission = 'READ'
|
AND permission = 'READ'
|
||||||
|
GROUP BY guacamole_user.user_id
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -124,8 +131,8 @@
|
|||||||
<select id="selectOne" resultMap="UserResultMap">
|
<select id="selectOne" resultMap="UserResultMap">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
user_id,
|
guacamole_user.user_id,
|
||||||
username,
|
guacamole_user.username,
|
||||||
password_hash,
|
password_hash,
|
||||||
password_salt,
|
password_salt,
|
||||||
password_date,
|
password_date,
|
||||||
@@ -139,10 +146,13 @@
|
|||||||
full_name,
|
full_name,
|
||||||
email_address,
|
email_address,
|
||||||
organization,
|
organization,
|
||||||
organizational_role
|
organizational_role,
|
||||||
|
MAX(start_date) AS last_active
|
||||||
FROM guacamole_user
|
FROM guacamole_user
|
||||||
|
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
|
||||||
WHERE
|
WHERE
|
||||||
username = #{username,jdbcType=VARCHAR}
|
guacamole_user.username = #{username,jdbcType=VARCHAR}
|
||||||
|
GROUP BY guacamole_user.user_id
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@@ -0,0 +1,187 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserRecordMapper" >
|
||||||
|
|
||||||
|
<!-- Result mapper for system permissions -->
|
||||||
|
<resultMap id="UserRecordResultMap" type="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
|
||||||
|
<id column="history_id" property="recordID" jdbcType="INTEGER"/>
|
||||||
|
<result column="remote_host" property="remoteHost" jdbcType="VARCHAR"/>
|
||||||
|
<result column="user_id" property="userID" jdbcType="INTEGER"/>
|
||||||
|
<result column="username" property="username" jdbcType="VARCHAR"/>
|
||||||
|
<result column="start_date" property="startDate" jdbcType="TIMESTAMP"/>
|
||||||
|
<result column="end_date" property="endDate" jdbcType="TIMESTAMP"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- Select all user records from a given user -->
|
||||||
|
<select id="select" resultMap="UserRecordResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
guacamole_user_history.remote_host,
|
||||||
|
guacamole_user_history.user_id,
|
||||||
|
guacamole_user_history.username,
|
||||||
|
guacamole_user_history.start_date,
|
||||||
|
guacamole_user_history.end_date
|
||||||
|
FROM guacamole_user_history
|
||||||
|
JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id
|
||||||
|
WHERE
|
||||||
|
guacamole_user.username = #{username,jdbcType=VARCHAR}
|
||||||
|
ORDER BY
|
||||||
|
guacamole_user_history.start_date DESC,
|
||||||
|
guacamole_user_history.end_date DESC
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- Insert the given user record -->
|
||||||
|
<insert id="insert" useGeneratedKeys="true" keyProperty="record.recordID"
|
||||||
|
parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
|
||||||
|
|
||||||
|
INSERT INTO guacamole_user_history (
|
||||||
|
remote_host,
|
||||||
|
user_id,
|
||||||
|
username,
|
||||||
|
start_date,
|
||||||
|
end_date
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
#{record.remoteHost,jdbcType=VARCHAR},
|
||||||
|
(SELECT user_id FROM guacamole_user
|
||||||
|
WHERE username = #{record.username,jdbcType=VARCHAR}),
|
||||||
|
#{record.username,jdbcType=VARCHAR},
|
||||||
|
#{record.startDate,jdbcType=TIMESTAMP},
|
||||||
|
#{record.endDate,jdbcType=TIMESTAMP}
|
||||||
|
)
|
||||||
|
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<!-- Update the given user record -->
|
||||||
|
<update id="update" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
|
||||||
|
UPDATE guacamole_user_history
|
||||||
|
SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
|
||||||
|
user_id = (SELECT user_id FROM guacamole_user
|
||||||
|
WHERE username = #{record.username,jdbcType=VARCHAR}),
|
||||||
|
username = #{record.username,jdbcType=VARCHAR},
|
||||||
|
start_date = #{record.startDate,jdbcType=TIMESTAMP},
|
||||||
|
end_date = #{record.endDate,jdbcType=TIMESTAMP}
|
||||||
|
WHERE history_id = #{record.recordID,jdbcType=INTEGER}::integer
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- Search for specific user records -->
|
||||||
|
<select id="search" resultMap="UserRecordResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
guacamole_user_history.remote_host,
|
||||||
|
guacamole_user_history.user_id,
|
||||||
|
guacamole_user_history.username,
|
||||||
|
guacamole_user_history.start_date,
|
||||||
|
guacamole_user_history.end_date
|
||||||
|
FROM guacamole_user_history
|
||||||
|
|
||||||
|
<!-- Search terms -->
|
||||||
|
<foreach collection="terms" item="term"
|
||||||
|
open="WHERE " separator=" AND ">
|
||||||
|
(
|
||||||
|
|
||||||
|
guacamole_user_history.user_id IN (
|
||||||
|
SELECT user_id
|
||||||
|
FROM guacamole_user
|
||||||
|
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 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 name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
|
||||||
|
|
||||||
|
<!-- Sort predicates -->
|
||||||
|
<foreach collection="sortPredicates" item="sortPredicate"
|
||||||
|
open="ORDER BY " separator=", ">
|
||||||
|
<choose>
|
||||||
|
<when test="sortPredicate.property == START_DATE">guacamole_user_history.start_date</when>
|
||||||
|
<otherwise>1</otherwise>
|
||||||
|
</choose>
|
||||||
|
<if test="sortPredicate.descending">DESC</if>
|
||||||
|
</foreach>
|
||||||
|
|
||||||
|
LIMIT #{limit,jdbcType=INTEGER}
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- Search for specific user records -->
|
||||||
|
<select id="searchReadable" resultMap="UserRecordResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
guacamole_user_history.remote_host,
|
||||||
|
guacamole_user_history.user_id,
|
||||||
|
guacamole_user_history.username,
|
||||||
|
guacamole_user_history.start_date,
|
||||||
|
guacamole_user_history.end_date
|
||||||
|
FROM guacamole_user_history
|
||||||
|
|
||||||
|
<!-- Restrict to readable users -->
|
||||||
|
JOIN guacamole_user_permission ON
|
||||||
|
guacamole_user_history.user_id = guacamole_user_permission.affected_user_id
|
||||||
|
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
|
||||||
|
AND guacamole_user_permission.permission = 'READ'
|
||||||
|
|
||||||
|
<!-- Search terms -->
|
||||||
|
<foreach collection="terms" item="term"
|
||||||
|
open="WHERE " separator=" AND ">
|
||||||
|
(
|
||||||
|
|
||||||
|
guacamole_user_history.user_id IN (
|
||||||
|
SELECT user_id
|
||||||
|
FROM guacamole_user
|
||||||
|
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 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 name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
|
||||||
|
|
||||||
|
<!-- Sort predicates -->
|
||||||
|
<foreach collection="sortPredicates" item="sortPredicate"
|
||||||
|
open="ORDER BY " separator=", ">
|
||||||
|
<choose>
|
||||||
|
<when test="sortPredicate.property == START_DATE">guacamole_user_history.start_date</when>
|
||||||
|
<otherwise>1</otherwise>
|
||||||
|
</choose>
|
||||||
|
<if test="sortPredicate.descending">DESC</if>
|
||||||
|
</foreach>
|
||||||
|
|
||||||
|
LIMIT #{limit,jdbcType=INTEGER}
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
@@ -502,6 +502,43 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_connection_history_start_date]
|
|||||||
|
|
||||||
CREATE NONCLUSTERED INDEX [IX_guacamole_connection_history_end_date]
|
CREATE NONCLUSTERED INDEX [IX_guacamole_connection_history_end_date]
|
||||||
ON [guacamole_connection_history] ([end_date]);
|
ON [guacamole_connection_history] ([end_date]);
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_guacamole_connection_history_connection_id_start_date]
|
||||||
|
ON [guacamole_connection_history] ([connection_id], [start_date]);
|
||||||
|
GO
|
||||||
|
|
||||||
|
--
|
||||||
|
-- User login/logout history
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE [guacamole_user_history] (
|
||||||
|
|
||||||
|
[history_id] [int] IDENTITY(1,1) NOT NULL,
|
||||||
|
[user_id] [int] DEFAULT NULL,
|
||||||
|
[username] [nvarchar](128) NOT NULL,
|
||||||
|
[remote_host] [nvarchar](256) DEFAULT NULL,
|
||||||
|
[start_date] [datetime] NOT NULL,
|
||||||
|
[end_date] [datetime] DEFAULT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (history_id),
|
||||||
|
|
||||||
|
CONSTRAINT FK_guacamole_user_history_user_id
|
||||||
|
FOREIGN KEY (user_id)
|
||||||
|
REFERENCES guacamole_user (user_id) ON DELETE SET NULL
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_user_id]
|
||||||
|
ON [guacamole_user_history] ([user_id]);
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_start_date]
|
||||||
|
ON [guacamole_user_history] ([start_date]);
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_end_date]
|
||||||
|
ON [guacamole_user_history] ([end_date]);
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_guacamole_user_history_user_id_start_date]
|
||||||
|
ON [guacamole_user_history] ([user_id], [start_date]);
|
||||||
GO
|
GO
|
||||||
|
|
||||||
--
|
--
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
|
javaType="org.apache.guacamole.net.auth.GuacamoleProxyConfiguration$EncryptionMethod"/>
|
||||||
<result column="connection_weight" property="connectionWeight" jdbcType="INTEGER"/>
|
<result column="connection_weight" property="connectionWeight" jdbcType="INTEGER"/>
|
||||||
<result column="failover_only" property="failoverOnly" jdbcType="BOOLEAN"/>
|
<result column="failover_only" property="failoverOnly" jdbcType="BOOLEAN"/>
|
||||||
|
<result column="last_active" property="lastActive" jdbcType="TIMESTAMP"/>
|
||||||
|
|
||||||
<!-- Associated sharing profiles -->
|
<!-- Associated sharing profiles -->
|
||||||
<collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
|
<collection property="sharingProfileIdentifiers" resultSet="sharingProfiles" ofType="java.lang.String"
|
||||||
@@ -89,8 +90,8 @@
|
|||||||
resultSets="connections,sharingProfiles">
|
resultSets="connections,sharingProfiles">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
connection_id,
|
[guacamole_connection].connection_id,
|
||||||
connection_name,
|
[guacamole_connection].connection_name,
|
||||||
parent_id,
|
parent_id,
|
||||||
protocol,
|
protocol,
|
||||||
max_connections,
|
max_connections,
|
||||||
@@ -99,9 +100,14 @@
|
|||||||
proxy_port,
|
proxy_port,
|
||||||
proxy_encryption_method,
|
proxy_encryption_method,
|
||||||
connection_weight,
|
connection_weight,
|
||||||
failover_only
|
failover_only,
|
||||||
|
(
|
||||||
|
SELECT MAX(start_date)
|
||||||
|
FROM [guacamole_connection_history]
|
||||||
|
WHERE [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
|
||||||
|
) AS last_active
|
||||||
FROM [guacamole_connection]
|
FROM [guacamole_connection]
|
||||||
WHERE connection_id IN
|
WHERE [guacamole_connection].connection_id IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=INTEGER}
|
#{identifier,jdbcType=INTEGER}
|
||||||
@@ -123,7 +129,7 @@
|
|||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
[guacamole_connection].connection_id,
|
[guacamole_connection].connection_id,
|
||||||
connection_name,
|
[guacamole_connection].connection_name,
|
||||||
parent_id,
|
parent_id,
|
||||||
protocol,
|
protocol,
|
||||||
max_connections,
|
max_connections,
|
||||||
@@ -132,7 +138,12 @@
|
|||||||
proxy_port,
|
proxy_port,
|
||||||
proxy_encryption_method,
|
proxy_encryption_method,
|
||||||
connection_weight,
|
connection_weight,
|
||||||
failover_only
|
failover_only,
|
||||||
|
(
|
||||||
|
SELECT MAX(start_date)
|
||||||
|
FROM [guacamole_connection_history]
|
||||||
|
WHERE [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
|
||||||
|
) AS last_active
|
||||||
FROM [guacamole_connection]
|
FROM [guacamole_connection]
|
||||||
JOIN [guacamole_connection_permission] ON [guacamole_connection_permission].connection_id = [guacamole_connection].connection_id
|
JOIN [guacamole_connection_permission] ON [guacamole_connection_permission].connection_id = [guacamole_connection].connection_id
|
||||||
WHERE [guacamole_connection].connection_id IN
|
WHERE [guacamole_connection].connection_id IN
|
||||||
@@ -140,7 +151,7 @@
|
|||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=INTEGER}
|
#{identifier,jdbcType=INTEGER}
|
||||||
</foreach>
|
</foreach>
|
||||||
AND user_id = #{user.objectID,jdbcType=INTEGER}
|
AND [guacamole_connection_permission].user_id = #{user.objectID,jdbcType=INTEGER}
|
||||||
AND permission = 'READ';
|
AND permission = 'READ';
|
||||||
|
|
||||||
SELECT primary_connection_id, [guacamole_sharing_profile].sharing_profile_id
|
SELECT primary_connection_id, [guacamole_sharing_profile].sharing_profile_id
|
||||||
@@ -160,8 +171,8 @@
|
|||||||
<select id="selectOneByName" resultMap="ConnectionResultMap">
|
<select id="selectOneByName" resultMap="ConnectionResultMap">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
connection_id,
|
[guacamole_connection].connection_id,
|
||||||
connection_name,
|
[guacamole_connection].connection_name,
|
||||||
parent_id,
|
parent_id,
|
||||||
protocol,
|
protocol,
|
||||||
max_connections,
|
max_connections,
|
||||||
@@ -170,12 +181,17 @@
|
|||||||
proxy_port,
|
proxy_port,
|
||||||
proxy_encryption_method,
|
proxy_encryption_method,
|
||||||
connection_weight,
|
connection_weight,
|
||||||
failover_only
|
failover_only,
|
||||||
|
(
|
||||||
|
SELECT MAX(start_date)
|
||||||
|
FROM [guacamole_connection_history]
|
||||||
|
WHERE [guacamole_connection_history].connection_id = [guacamole_connection].connection_id
|
||||||
|
) AS last_active
|
||||||
FROM [guacamole_connection]
|
FROM [guacamole_connection]
|
||||||
WHERE
|
WHERE
|
||||||
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}</if>
|
<if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}</if>
|
||||||
<if test="parentIdentifier == null">parent_id IS NULL</if>
|
<if test="parentIdentifier == null">parent_id IS NULL</if>
|
||||||
AND connection_name = #{name,jdbcType=VARCHAR}
|
AND [guacamole_connection].connection_name = #{name,jdbcType=VARCHAR}
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@@ -41,6 +41,7 @@
|
|||||||
<result column="email_address" property="emailAddress" jdbcType="VARCHAR"/>
|
<result column="email_address" property="emailAddress" jdbcType="VARCHAR"/>
|
||||||
<result column="organization" property="organization" jdbcType="VARCHAR"/>
|
<result column="organization" property="organization" jdbcType="VARCHAR"/>
|
||||||
<result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
|
<result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
|
||||||
|
<result column="last_active" property="lastActive" jdbcType="TIMESTAMP"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<!-- Select all usernames -->
|
<!-- Select all usernames -->
|
||||||
@@ -63,8 +64,8 @@
|
|||||||
<select id="select" resultMap="UserResultMap">
|
<select id="select" resultMap="UserResultMap">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
user_id,
|
[guacamole_user].user_id,
|
||||||
username,
|
[guacamole_user].username,
|
||||||
password_hash,
|
password_hash,
|
||||||
password_salt,
|
password_salt,
|
||||||
password_date,
|
password_date,
|
||||||
@@ -78,13 +79,18 @@
|
|||||||
full_name,
|
full_name,
|
||||||
email_address,
|
email_address,
|
||||||
organization,
|
organization,
|
||||||
organizational_role
|
organizational_role,
|
||||||
|
(
|
||||||
|
SELECT MAX(start_date)
|
||||||
|
FROM [guacamole_user_history]
|
||||||
|
WHERE [guacamole_user_history].user_id = [guacamole_user].user_id
|
||||||
|
) AS last_active
|
||||||
FROM [guacamole_user]
|
FROM [guacamole_user]
|
||||||
WHERE username IN
|
WHERE [guacamole_user].username IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=VARCHAR}
|
#{identifier,jdbcType=VARCHAR}
|
||||||
</foreach>
|
</foreach>;
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -93,7 +99,7 @@
|
|||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
[guacamole_user].user_id,
|
[guacamole_user].user_id,
|
||||||
username,
|
[guacamole_user].username,
|
||||||
password_hash,
|
password_hash,
|
||||||
password_salt,
|
password_salt,
|
||||||
password_date,
|
password_date,
|
||||||
@@ -107,10 +113,15 @@
|
|||||||
full_name,
|
full_name,
|
||||||
email_address,
|
email_address,
|
||||||
organization,
|
organization,
|
||||||
organizational_role
|
organizational_role,
|
||||||
|
(
|
||||||
|
SELECT MAX(start_date)
|
||||||
|
FROM [guacamole_user_history]
|
||||||
|
WHERE [guacamole_user_history].user_id = [guacamole_user].user_id
|
||||||
|
) AS last_active
|
||||||
FROM [guacamole_user]
|
FROM [guacamole_user]
|
||||||
JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id
|
JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id
|
||||||
WHERE username IN
|
WHERE [guacamole_user].username IN
|
||||||
<foreach collection="identifiers" item="identifier"
|
<foreach collection="identifiers" item="identifier"
|
||||||
open="(" separator="," close=")">
|
open="(" separator="," close=")">
|
||||||
#{identifier,jdbcType=VARCHAR}
|
#{identifier,jdbcType=VARCHAR}
|
||||||
@@ -124,8 +135,8 @@
|
|||||||
<select id="selectOne" resultMap="UserResultMap">
|
<select id="selectOne" resultMap="UserResultMap">
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
user_id,
|
[guacamole_user].user_id,
|
||||||
username,
|
[guacamole_user].username,
|
||||||
password_hash,
|
password_hash,
|
||||||
password_salt,
|
password_salt,
|
||||||
password_date,
|
password_date,
|
||||||
@@ -139,10 +150,16 @@
|
|||||||
full_name,
|
full_name,
|
||||||
email_address,
|
email_address,
|
||||||
organization,
|
organization,
|
||||||
organizational_role
|
organizational_role,
|
||||||
|
(
|
||||||
|
SELECT MAX(start_date)
|
||||||
|
FROM [guacamole_user_history]
|
||||||
|
WHERE [guacamole_user_history].user_id = [guacamole_user].user_id
|
||||||
|
) AS last_active
|
||||||
FROM [guacamole_user]
|
FROM [guacamole_user]
|
||||||
|
LEFT JOIN [guacamole_user_history] ON [guacamole_user_history].user_id = [guacamole_user].user_id
|
||||||
WHERE
|
WHERE
|
||||||
username = #{username,jdbcType=VARCHAR}
|
[guacamole_user].username = #{username,jdbcType=VARCHAR}
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
@@ -0,0 +1,187 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserRecordMapper" >
|
||||||
|
|
||||||
|
<!-- Result mapper for system permissions -->
|
||||||
|
<resultMap id="UserRecordResultMap" type="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
|
||||||
|
<id column="history_id" property="recordID" jdbcType="INTEGER"/>
|
||||||
|
<result column="remote_host" property="remoteHost" jdbcType="VARCHAR"/>
|
||||||
|
<result column="user_id" property="userID" jdbcType="INTEGER"/>
|
||||||
|
<result column="username" property="username" jdbcType="VARCHAR"/>
|
||||||
|
<result column="start_date" property="startDate" jdbcType="TIMESTAMP"/>
|
||||||
|
<result column="end_date" property="endDate" jdbcType="TIMESTAMP"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<!-- Select all user records from a given user -->
|
||||||
|
<select id="select" resultMap="UserRecordResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
[guacamole_user_history].remote_host,
|
||||||
|
[guacamole_user_history].user_id,
|
||||||
|
[guacamole_user_history].username,
|
||||||
|
[guacamole_user_history].start_date,
|
||||||
|
[guacamole_user_history].end_date
|
||||||
|
FROM [guacamole_user_history]
|
||||||
|
JOIN [guacamole_user] ON [guacamole_user_history].user_id = [guacamole_user].user_id
|
||||||
|
WHERE
|
||||||
|
[guacamole_user].username = #{username,jdbcType=VARCHAR}
|
||||||
|
ORDER BY
|
||||||
|
[guacamole_user_history].start_date DESC,
|
||||||
|
[guacamole_user_history].end_date DESC
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- Insert the given user record -->
|
||||||
|
<insert id="insert" useGeneratedKeys="true" keyProperty="record.recordID"
|
||||||
|
parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
|
||||||
|
|
||||||
|
INSERT INTO [guacamole_user_history] (
|
||||||
|
remote_host,
|
||||||
|
user_id,
|
||||||
|
username,
|
||||||
|
start_date,
|
||||||
|
end_date
|
||||||
|
)
|
||||||
|
VALUES (
|
||||||
|
#{record.remoteHost,jdbcType=VARCHAR},
|
||||||
|
(SELECT user_id FROM [guacamole_user]
|
||||||
|
WHERE username = #{record.username,jdbcType=VARCHAR}),
|
||||||
|
#{record.username,jdbcType=VARCHAR},
|
||||||
|
#{record.startDate,jdbcType=TIMESTAMP},
|
||||||
|
#{record.endDate,jdbcType=TIMESTAMP}
|
||||||
|
)
|
||||||
|
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<!-- Update the given user record -->
|
||||||
|
<update id="update" parameterType="org.apache.guacamole.auth.jdbc.base.ActivityRecordModel">
|
||||||
|
UPDATE [guacamole_user_history]
|
||||||
|
SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
|
||||||
|
user_id = (SELECT user_id FROM [guacamole_user]
|
||||||
|
WHERE username = #{record.username,jdbcType=VARCHAR}),
|
||||||
|
username = #{record.username,jdbcType=VARCHAR},
|
||||||
|
start_date = #{record.startDate,jdbcType=TIMESTAMP},
|
||||||
|
end_date = #{record.endDate,jdbcType=TIMESTAMP}
|
||||||
|
WHERE history_id = #{record.recordID,jdbcType=INTEGER}
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<!-- Search for specific user records -->
|
||||||
|
<select id="search" resultMap="UserRecordResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
[guacamole_user_history].remote_host,
|
||||||
|
[guacamole_user_history].user_id,
|
||||||
|
[guacamole_user_history].username,
|
||||||
|
[guacamole_user_history].start_date,
|
||||||
|
[guacamole_user_history].end_date
|
||||||
|
FROM [guacamole_user_history]
|
||||||
|
|
||||||
|
<!-- Search terms -->
|
||||||
|
<foreach collection="terms" item="term"
|
||||||
|
open="WHERE " separator=" AND ">
|
||||||
|
(
|
||||||
|
|
||||||
|
[guacamole_user_history].user_id IN (
|
||||||
|
SELECT user_id
|
||||||
|
FROM [guacamole_user]
|
||||||
|
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 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 name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
|
||||||
|
|
||||||
|
<!-- Sort predicates -->
|
||||||
|
<foreach collection="sortPredicates" item="sortPredicate"
|
||||||
|
open="ORDER BY " separator=", ">
|
||||||
|
<choose>
|
||||||
|
<when test="sortPredicate.property == START_DATE">[guacamole_user_history].start_date</when>
|
||||||
|
<otherwise>1</otherwise>
|
||||||
|
</choose>
|
||||||
|
<if test="sortPredicate.descending">DESC</if>
|
||||||
|
</foreach>
|
||||||
|
|
||||||
|
LIMIT #{limit,jdbcType=INTEGER}
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- Search for specific user records -->
|
||||||
|
<select id="searchReadable" resultMap="UserRecordResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
[guacamole_user_history].remote_host,
|
||||||
|
[guacamole_user_history].user_id,
|
||||||
|
[guacamole_user_history].username,
|
||||||
|
[guacamole_user_history].start_date,
|
||||||
|
[guacamole_user_history].end_date
|
||||||
|
FROM [guacamole_user_history]
|
||||||
|
|
||||||
|
<!-- Restrict to readable users -->
|
||||||
|
JOIN [guacamole_user_permission] ON
|
||||||
|
[guacamole_user_history].user_id = [guacamole_user_permission].affected_user_id
|
||||||
|
AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
|
||||||
|
AND [guacamole_user_permission].permission = 'READ'
|
||||||
|
|
||||||
|
<!-- Search terms -->
|
||||||
|
<foreach collection="terms" item="term"
|
||||||
|
open="WHERE " separator=" AND ">
|
||||||
|
(
|
||||||
|
|
||||||
|
[guacamole_user_history].user_id IN (
|
||||||
|
SELECT user_id
|
||||||
|
FROM [guacamole_user]
|
||||||
|
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 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 name="START_DATE" value="@org.apache.guacamole.net.auth.ActivityRecordSet$SortableProperty@START_DATE"/>
|
||||||
|
|
||||||
|
<!-- Sort predicates -->
|
||||||
|
<foreach collection="sortPredicates" item="sortPredicate"
|
||||||
|
open="ORDER BY " separator=", ">
|
||||||
|
<choose>
|
||||||
|
<when test="sortPredicate.property == START_DATE">[guacamole_user_history].start_date</when>
|
||||||
|
<otherwise>1</otherwise>
|
||||||
|
</choose>
|
||||||
|
<if test="sortPredicate.descending">DESC</if>
|
||||||
|
</foreach>
|
||||||
|
|
||||||
|
LIMIT #{limit,jdbcType=INTEGER}
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
Reference in New Issue
Block a user