diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/AuthenticationProviderService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/AuthenticationProviderService.java index afdaf332b..5fedd23e9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/AuthenticationProviderService.java @@ -110,4 +110,34 @@ public interface AuthenticationProviderService { UserContext context, AuthenticatedUser authenticatedUser, Credentials credentials) throws GuacamoleException; + /** + * Decorates a UserContext instance for the given already-authenticated user. + * If no decoration is required, the original UserContext will be returned. + * + * @param authenticationProvider + * The AuthenticationProvider on behalf of which the UserContext is + * being decorated. + * + * @param context + * The UserContext to decorate. + * + * @param authenticatedUser + * The AuthenticatedUser associated with the UserContext being decorated. + * + * @param credentials + * The credentials most recently submitted by the user. These + * credentials are not guaranteed to be the same as the credentials + * already associated with the AuthenticatedUser. + * + * @return + * A decorated UserContext instance for the user identified by the given + * credentials, or the original user context if no decoration is required. + * + * @throws GuacamoleException + * If the an error occurs during decoration of the UserContext. + */ + public UserContext decorateUserContext(AuthenticationProvider authenticationProvider, + UserContext context, AuthenticatedUser authenticatedUser, + Credentials credentials) throws GuacamoleException; + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingConnection.java new file mode 100644 index 000000000..2a0bc3cc3 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingConnection.java @@ -0,0 +1,117 @@ +/* + * 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; + +import java.util.Date; +import java.util.Map; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordMapper; +import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordModel; +import org.apache.guacamole.net.GuacamoleTunnel; +import org.apache.guacamole.net.auth.Connection; +import org.apache.guacamole.net.auth.DelegatingConnection; +import org.apache.guacamole.net.auth.User; +import org.apache.guacamole.protocol.GuacamoleClientInformation; + +/** + * Connection implementation that creates a history record when the connection + * is established, and returns a HistoryTrackingTunnel to automatically set the + * end date when the connection is closed. + */ +public class HistoryTrackingConnection extends DelegatingConnection { + + /** + * The current Guacamole user. + */ + private final User currentUser; + + /** + * The remote host that the user connected from. + */ + private final String remoteHost; + + /** + * The connection record mapper to use when writing history entries for + * established connections. + */ + private final ConnectionRecordMapper connectionRecordMapper; + + /** + * Creates a new HistoryConnection that wraps the given connection, + * automatically creating a history record when the connection is + * established, and returning a HistoryTrackingTunnel to set the end + * date on the history entry when the connection is closed. + * + * @param currentUser + * The current Guacamole user. + * + * @param remoteHost + * The remote host that the user connected from. + * + * @param connection + * The connection to wrap. + * + * @param connectionRecordMapper + * The connection record mapper that will be used to write the connection history records. + */ + public HistoryTrackingConnection(User currentUser, String remoteHost, Connection connection, ConnectionRecordMapper connectionRecordMapper) { + super(connection); + + this.currentUser = currentUser; + this.remoteHost = remoteHost; + this.connectionRecordMapper = connectionRecordMapper; + } + + @Override + public GuacamoleTunnel connect(GuacamoleClientInformation info, + Map tokens) throws GuacamoleException { + + // Create a connection record model, starting at the current date/time + ConnectionRecordModel connectionRecordModel = new ConnectionRecordModel(); + connectionRecordModel.setStartDate(new Date()); + + // Set the user information + connectionRecordModel.setUsername(this.currentUser.getIdentifier()); + connectionRecordModel.setRemoteHost(this.remoteHost); + + // Set the connection information + connectionRecordModel.setConnectionName(this.getDelegateConnection().getName()); + + // Insert the connection history record to mark the start of this connection + connectionRecordMapper.insert(connectionRecordModel); + + // Connect, and wrap the tunnel for return + GuacamoleTunnel tunnel = super.connect(info, tokens); + return new HistoryTrackingTunnel( + tunnel, this.connectionRecordMapper, connectionRecordModel); + } + + /** + * Get the Connection wrapped by this HistoryTrackingConnection. + * + * @return + * The wrapped Connection. + */ + public Connection getWrappedConnection() { + return getDelegateConnection(); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingConnectionDirectory.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingConnectionDirectory.java new file mode 100644 index 000000000..ddc3afb19 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingConnectionDirectory.java @@ -0,0 +1,96 @@ +/* + * 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; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordMapper; +import org.apache.guacamole.net.auth.Connection; +import org.apache.guacamole.net.auth.DecoratingDirectory; +import org.apache.guacamole.net.auth.Directory; +import org.apache.guacamole.net.auth.User; + +/** + * A connection directory that returns HistoryTrackingConnection-wrapped connections + * when queried. + */ +public class HistoryTrackingConnectionDirectory extends DecoratingDirectory { + + /** + * The connection record mapper to use when writing history entries for + * established connections. + */ + private final ConnectionRecordMapper connectionRecordMapper; + + /** + * The user that directory operations are being performed for. + */ + private final User user; + + /** + * The remote host that the user connected from. + */ + private final String remoteHost; + + /** + * Create a new history tracking connection directory. Any connection retrieved from this + * directory will be wrapped in a HistoryTrackingConnection, enabling connection history + * records to be written with the provided connection record mapper. + * + * @param directory + * The connection directory to wrap. + * + * @param user + * The user associated with the connection directory. + * + * @param remoteHost + * The remote host that the user connected from. + * + * @param connectionRecordMapper + * The connection record mapper that will be used to write the connection history records. + */ + public HistoryTrackingConnectionDirectory(Directory directory, User user, String remoteHost, ConnectionRecordMapper connectionRecordMapper) { + super(directory); + + this.user = user; + this.remoteHost = remoteHost; + this.connectionRecordMapper = connectionRecordMapper; + } + + @Override + protected Connection decorate(Connection connection) throws GuacamoleException { + + // Wrap the connection in a history-tracking layer + return new HistoryTrackingConnection( + this.user, this.remoteHost, connection, this.connectionRecordMapper); + } + + @Override + protected Connection undecorate(Connection connection) throws GuacamoleException { + + // If the connection was wrapped, unwrap it + if (connection instanceof HistoryTrackingConnection) { + return ((HistoryTrackingConnection) connection).getWrappedConnection(); + } + + // Otherwise, return the unwrapped connection directly + return connection; + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingTunnel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingTunnel.java new file mode 100644 index 000000000..aeccc3a0b --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingTunnel.java @@ -0,0 +1,81 @@ +/* + * 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; + +import java.util.Date; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordMapper; +import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordModel; +import org.apache.guacamole.net.DelegatingGuacamoleTunnel; +import org.apache.guacamole.net.GuacamoleTunnel; + +/** + * Tunnel implementation which automatically writes an end date for the + * provided connection history record model using the provided connection + * history mapper, when the tunnel is closed. + */ +public class HistoryTrackingTunnel extends DelegatingGuacamoleTunnel { + + /** + * The connection for which this tunnel was established. + */ + private final ConnectionRecordMapper connectionRecordMapper; + + /** + * The user for which this tunnel was established. + */ + private final ConnectionRecordModel connectionRecordModel; + + /** + * Creates a new HistoryTrackingTunnel that wraps the given tunnel, + * automatically setting the end date for the provided connection history records, + * using the provided connection history record mapper. + * + * @param tunnel + * The tunnel to wrap. + * + * @param connectionRecordMapper + * The mapper to use when writing connection history records. + * + * @param connectionRecordModel + * The connection history record model representing the in-progress connection. + */ + public HistoryTrackingTunnel(GuacamoleTunnel tunnel, + ConnectionRecordMapper connectionRecordMapper, ConnectionRecordModel connectionRecordModel) { + + super(tunnel); + + // Store the connection record mapper and model for history tracking + this.connectionRecordMapper = connectionRecordMapper; + this.connectionRecordModel = connectionRecordModel; + } + + @Override + public void close() throws GuacamoleException { + + // Set the end date to complete the connection history record + this.connectionRecordModel.setEndDate(new Date()); + this.connectionRecordMapper.updateEndDate(this.connectionRecordModel); + + super.close(); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingUserContext.java new file mode 100644 index 000000000..2c13a7ec8 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/HistoryTrackingUserContext.java @@ -0,0 +1,75 @@ +/* + * 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; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordMapper; +import org.apache.guacamole.net.auth.Connection; +import org.apache.guacamole.net.auth.DelegatingUserContext; +import org.apache.guacamole.net.auth.Directory; +import org.apache.guacamole.net.auth.UserContext; + +/** + * DelegatingUserContext implementation which writes connection history records + * when connections are established and closed. + */ +public class HistoryTrackingUserContext extends DelegatingUserContext { + + /** + * The remote host that the user associated with the user context + * connected from. + */ + private final String remoteHost; + + /** + * The connection record mapper to use when writing history entries for + * established connections. + */ + private final ConnectionRecordMapper connectionRecordMapper; + + /** + * Creates a new HistoryTrackingUserContext which wraps the given + * UserContext, allowing for tracking of connection history external to + * this authentication provider. + * + * @param userContext + * The UserContext to wrap. + * + * @param remoteHost + * The host that the user associated with the given user context connected from. + * + * @param connectionRecordMapper + * The mapper to use when writing connection history entries to the DB. + */ + public HistoryTrackingUserContext(UserContext userContext, String remoteHost, ConnectionRecordMapper connectionRecordMapper) { + super(userContext); + + this.remoteHost = remoteHost; + this.connectionRecordMapper = connectionRecordMapper; + } + + @Override + public Directory getConnectionDirectory() throws GuacamoleException { + return new HistoryTrackingConnectionDirectory( + super.getConnectionDirectory(), self(), + this.remoteHost, this.connectionRecordMapper); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/InjectedAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/InjectedAuthenticationProvider.java index fddb20447..8ae2eea63 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/InjectedAuthenticationProvider.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/InjectedAuthenticationProvider.java @@ -90,4 +90,12 @@ public abstract class InjectedAuthenticationProvider extends AbstractAuthenticat authenticatedUser, credentials); } + @Override + public UserContext decorate(UserContext context, + AuthenticatedUser authenticatedUser, Credentials credentials) + throws GuacamoleException { + return authProviderService.decorateUserContext(this, context, + authenticatedUser, credentials); + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java index 2f38ebe23..d2576ec2b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderService.java @@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc; import com.google.inject.Inject; import com.google.inject.Provider; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordMapper; import org.apache.guacamole.auth.jdbc.security.PasswordPolicyService; import org.apache.guacamole.auth.jdbc.sharing.user.SharedAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; @@ -68,6 +69,12 @@ public class JDBCAuthenticationProviderService implements AuthenticationProvider @Inject private Provider userContextProvider; + /** + * Mapper for writing connection history. + */ + @Inject + private ConnectionRecordMapper connectionRecordMapper; + @Override public AuthenticatedUser authenticateUser(AuthenticationProvider authenticationProvider, Credentials credentials) throws GuacamoleException { @@ -99,7 +106,7 @@ public class JDBCAuthenticationProviderService implements AuthenticationProvider ModeledUser user = userService.retrieveUser(authenticationProvider, authenticatedUser); ModeledUserContext context = userContextProvider.get(); if (user != null && !user.isDisabled()) { - + // Enforce applicable account restrictions if (databaseRestrictionsApplicable) { @@ -125,18 +132,18 @@ public class JDBCAuthenticationProviderService implements AuthenticationProvider } } - + // If no user account is found, and database-specific account // restrictions do not apply, get a skeleton user. else if (!databaseRestrictionsApplicable) { user = userService.retrieveSkeletonUser(authenticationProvider, authenticatedUser); - + // If auto account creation is enabled, add user to DB. if (environment.autoCreateAbsentAccounts()) { ModeledUser createdUser = userService.createObject(new PrivilegedModeledAuthenticatedUser(user.getCurrentUser()), user); user.setModel(createdUser.getModel()); } - + } // Veto authentication result only if database-specific account @@ -144,7 +151,7 @@ public class JDBCAuthenticationProviderService implements AuthenticationProvider else throw new GuacamoleInvalidCredentialsException("Invalid login", CredentialsInfo.USERNAME_PASSWORD); - + // Initialize the UserContext with the user account and return it. context.init(user.getCurrentUser()); context.recordUserLogin(); @@ -162,4 +169,18 @@ public class JDBCAuthenticationProviderService implements AuthenticationProvider } + @Override + public UserContext decorateUserContext(AuthenticationProvider authenticationProvider, + UserContext context, AuthenticatedUser authenticatedUser, + Credentials credentials) throws GuacamoleException { + + // Track connection history only for external connections, and only if enabled in the config + if (environment.trackExternalConnectionHistory() && context.getAuthenticationProvider() != authenticationProvider) { + return new HistoryTrackingUserContext(context, credentials.getRemoteHostname(), connectionRecordMapper); + } + + return context; + + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java index 19544447d..763793d62 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java @@ -30,7 +30,7 @@ import org.apache.ibatis.session.SqlSession; * intended for use within JDBC based authentication providers. */ public abstract class JDBCEnvironment extends DelegatingEnvironment { - + /** * Constructs a new JDBCEnvironment using an underlying LocalEnviroment to * read properties from the file system. @@ -68,12 +68,12 @@ public abstract class JDBCEnvironment extends DelegatingEnvironment { public abstract int getAbsoluteMaxConnections() throws GuacamoleException; /** - * Returns the default maximum number of concurrent connections to allow to - * any one connection, unless specified differently on an individual + * Returns the default maximum number of concurrent connections to allow to + * any one connection, unless specified differently on an individual * connection. Zero denotes unlimited. - * + * * @return - * The default maximum allowable number of concurrent connections + * The default maximum allowable number of concurrent connections * to any connection. * * @throws GuacamoleException @@ -82,10 +82,10 @@ public abstract class JDBCEnvironment extends DelegatingEnvironment { public abstract int getDefaultMaxConnections() throws GuacamoleException; /** - * Returns the default maximum number of concurrent connections to allow to - * any one connection group, unless specified differently on an individual + * Returns the default maximum number of concurrent connections to allow to + * any one connection group, unless specified differently on an individual * connection group. Zero denotes unlimited. - * + * * @return * The default maximum allowable number of concurrent connections * to any connection group. @@ -95,12 +95,12 @@ public abstract class JDBCEnvironment extends DelegatingEnvironment { */ public abstract int getDefaultMaxGroupConnections() throws GuacamoleException; - + /** - * Returns the default maximum number of concurrent connections to allow to + * Returns the default maximum number of concurrent connections to allow to * any one connection by an individual user, unless specified differently on * an individual connection. Zero denotes unlimited. - * + * * @return * The default maximum allowable number of concurrent connections to * any connection by an individual user. @@ -110,12 +110,12 @@ public abstract class JDBCEnvironment extends DelegatingEnvironment { */ public abstract int getDefaultMaxConnectionsPerUser() throws GuacamoleException; - + /** - * Returns the default maximum number of concurrent connections to allow to - * any one connection group by an individual user, unless specified + * Returns the default maximum number of concurrent connections to allow to + * any one connection group by an individual user, unless specified * differently on an individual connection group. Zero denotes unlimited. - * + * * @return * The default maximum allowable number of concurrent connections to * any connection group by an individual user. @@ -149,19 +149,19 @@ public abstract class JDBCEnvironment extends DelegatingEnvironment { * true if the database supports recursive queries, false otherwise. */ public abstract boolean isRecursiveQuerySupported(SqlSession session); - + /** * Returns a boolean value representing whether or not the JDBC module * should automatically create accounts within the database for users that * are successfully authenticated via other extensions. Returns true if * accounts should be auto-created, otherwise returns false. - * + * * @return * true if user accounts should be automatically created within the * database when authentication succeeds from another extension; * otherwise false. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ public abstract boolean autoCreateAbsentAccounts() throws GuacamoleException; @@ -212,4 +212,19 @@ public abstract class JDBCEnvironment extends DelegatingEnvironment { } } + /** + * Returns a boolean value representing whether or not the JDBC module + * should automatically track connection history for external connections, + * i.e. connections not originated from within the JDBC auth provider + * itself. + * + * @return + * true if connection history should be tracked for connections that + * do not originate from within this JDBC auth provider, false otherwise. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public abstract boolean trackExternalConnectionHistory() throws GuacamoleException; + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedAuthenticationProviderService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedAuthenticationProviderService.java index 40df1e3d3..8cd6edc36 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedAuthenticationProviderService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedAuthenticationProviderService.java @@ -109,4 +109,13 @@ public class SharedAuthenticationProviderService implements AuthenticationProvid } + @Override + public UserContext decorateUserContext(AuthenticationProvider authenticationProvider, + UserContext context, AuthenticatedUser authenticatedUser, + Credentials credentials) { + + // There's no need to decorate the user context here + return context; + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java index ee3fd8aa1..d8344ec81 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java @@ -99,7 +99,7 @@ public class MySQLEnvironment extends JDBCEnvironment { * allowed to any one connection group. */ private final int DEFAULT_MAX_GROUP_CONNECTIONS = 0; - + /** * The default SSL mode for connecting to MySQL servers. */ @@ -108,8 +108,8 @@ public class MySQLEnvironment extends JDBCEnvironment { /** * Constructs a new MySQLEnvironment, providing access to MySQL-specific * configuration options. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If an error occurs while setting up the underlying JDBCEnvironment * or while parsing legacy MySQL configuration options. */ @@ -177,12 +177,12 @@ public class MySQLEnvironment extends JDBCEnvironment { * database server hosting the Guacamole database. If unspecified, the * installed MySQL driver will be automatically detected by inspecting the * classes available in the classpath. - * + * * @return * The MySQL driver that will be used to communicate with the MySQL- * compatible server. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If guacamole.properties cannot be parsed, or if no MySQL-compatible * JDBC driver is present. */ @@ -210,15 +210,15 @@ public class MySQLEnvironment extends JDBCEnvironment { throw new GuacamoleServerException("No JDBC driver for MySQL/MariaDB is installed."); } - + /** * Returns the hostname of the MySQL server hosting the Guacamole * authentication tables. If unspecified, this will be "localhost". - * + * * @return * The URL of the MySQL server. * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value. */ public String getMySQLHostname() throws GuacamoleException { @@ -227,30 +227,30 @@ public class MySQLEnvironment extends JDBCEnvironment { DEFAULT_HOSTNAME ); } - + /** * Returns the port number of the MySQL server hosting the Guacamole * authentication tables. If unspecified, this will be the default MySQL * port of 3306. - * + * * @return * The port number of the MySQL server. * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value. */ public int getMySQLPort() throws GuacamoleException { return getProperty(MySQLGuacamoleProperties.MYSQL_PORT, DEFAULT_PORT); } - + /** - * Returns the name of the MySQL database containing the Guacamole + * Returns the name of the MySQL database containing the Guacamole * authentication tables. - * + * * @return * The name of the MySQL database. * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value, or if the * value was not set, as this property is required. */ @@ -262,7 +262,7 @@ public class MySQLEnvironment extends JDBCEnvironment { public String getUsername() throws GuacamoleException { return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_USERNAME); } - + @Override public String getPassword() throws GuacamoleException { return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD); @@ -303,15 +303,15 @@ public class MySQLEnvironment extends JDBCEnvironment { } } - + /** * Return the MySQL SSL mode as configured in guacamole.properties, or the * default value of PREFERRED if not configured. - * + * * @return * The SSL mode to use when connecting to the MySQL server. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If an error occurs retrieving the property value. */ public MySQLSSLMode getMySQLSSLMode() throws GuacamoleException { @@ -319,71 +319,71 @@ public class MySQLEnvironment extends JDBCEnvironment { MySQLGuacamoleProperties.MYSQL_SSL_MODE, DEFAULT_SSL_MODE); } - + /** * Returns the File where the trusted certificate store is located as * configured in guacamole.properties, or null if no value has been * configured. The trusted certificate store is used to validate server * certificates when making SSL connections to MySQL servers. - * + * * @return * The File where the trusted certificate store is located, or null * if the value has not been configured. - * + * * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ public File getMySQLSSLTrustStore() throws GuacamoleException { return getProperty(MySQLGuacamoleProperties.MYSQL_SSL_TRUST_STORE); } - + /** * Returns the password used to access the trusted certificate store as * configured in guacamole.properties, or null if no password has been * specified. - * + * * @return * The password used to access the trusted certificate store. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ public String getMySQLSSLTrustPassword() throws GuacamoleException { return getProperty(MySQLGuacamoleProperties.MYSQL_SSL_TRUST_PASSWORD); } - + /** * Returns the File used to store the client SSL certificate as configured * in guacamole.properties, or null if no value has been specified. This * file will be used to load the client certificate used for SSL connections * to MySQL servers, if the SSL connection is so configured to require * client certificate authentication. - * + * * @return * The File where the client SSL certificate is stored. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ public File getMySQLSSLClientStore() throws GuacamoleException { return getProperty(MySQLGuacamoleProperties.MYSQL_SSL_CLIENT_STORE); } - + /** * Returns the password used to access the client certificate store as * configured in guacamole.properties, or null if no value has been * specified. - * + * * @return * The password used to access the client SSL certificate store. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ public String getMYSQLSSLClientPassword() throws GuacamoleException { return getProperty(MySQLGuacamoleProperties.MYSQL_SSL_CLIENT_PASSWORD); } - + @Override public boolean autoCreateAbsentAccounts() throws GuacamoleException { return getProperty(MySQLGuacamoleProperties.MYSQL_AUTO_CREATE_ACCOUNTS, @@ -393,15 +393,23 @@ public class MySQLEnvironment extends JDBCEnvironment { /** * Return the server timezone if configured in guacamole.properties, or * null if the configuration option is not present. - * + * * @return * The server timezone as configured in guacamole.properties. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If an error occurs retrieving the configuration value. */ public TimeZone getServerTimeZone() throws GuacamoleException { return getProperty(MySQLGuacamoleProperties.SERVER_TIMEZONE); } + @Override + public boolean trackExternalConnectionHistory() throws GuacamoleException { + + // Track external connection history unless explicitly disabled + return getProperty(MySQLGuacamoleProperties.MYSQL_TRACK_EXTERNAL_CONNECTION_HISTORY, + true); + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java index 925f82a72..6a5944fd3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLGuacamoleProperties.java @@ -35,7 +35,7 @@ public class MySQLGuacamoleProperties { * This class should not be instantiated. */ private MySQLGuacamoleProperties() {} - + /** * The JDBC driver that should be used to talk to MySQL-compatible servers. */ @@ -48,7 +48,7 @@ public class MySQLGuacamoleProperties { }; /** - * The hostname of the MySQL server hosting the Guacamole authentication + * The hostname of the MySQL server hosting the Guacamole authentication * tables. */ public static final StringGuacamoleProperty MYSQL_HOSTNAME = new StringGuacamoleProperty() { @@ -59,7 +59,7 @@ public class MySQLGuacamoleProperties { }; /** - * The port number of the MySQL server hosting the Guacamole authentication + * The port number of the MySQL server hosting the Guacamole authentication * tables. */ public static final IntegerGuacamoleProperty MYSQL_PORT = new IntegerGuacamoleProperty() { @@ -70,7 +70,7 @@ public class MySQLGuacamoleProperties { }; /** - * The name of the MySQL database containing the Guacamole authentication + * The name of the MySQL database containing the Guacamole authentication * tables. */ public static final StringGuacamoleProperty MYSQL_DATABASE = new StringGuacamoleProperty() { @@ -179,19 +179,19 @@ public class MySQLGuacamoleProperties { public String getName() { return "mysql-default-max-group-connections-per-user"; } }; - + /** * The SSL mode used to connect to the MySQL Server. By default the driver * will attempt SSL connections and fall back to plain-text if SSL fails. */ public static final EnumGuacamoleProperty MYSQL_SSL_MODE = new EnumGuacamoleProperty(MySQLSSLMode.class) { - + @Override public String getName() { return "mysql-ssl-mode" ; } - + }; - + /** * The File where trusted SSL certificate authorities and server certificates * are stored. By default no file is specified, and the default Java @@ -199,24 +199,24 @@ public class MySQLGuacamoleProperties { */ public static final FileGuacamoleProperty MYSQL_SSL_TRUST_STORE = new FileGuacamoleProperty() { - + @Override public String getName() { return "mysql-ssl-trust-store"; } - + }; - + /** * The password to use to access the mysql-ssl-trust-store, if required. By * default no password will be used to attempt to access the store. */ public static final StringGuacamoleProperty MYSQL_SSL_TRUST_PASSWORD = new StringGuacamoleProperty() { - + @Override public String getName() { return "mysql-ssl-trust-password"; } - + }; - + /** * The File used to store the client certificate for configurations where * a client certificate is required for authentication. By default no @@ -224,24 +224,24 @@ public class MySQLGuacamoleProperties { */ public static final FileGuacamoleProperty MYSQL_SSL_CLIENT_STORE = new FileGuacamoleProperty() { - + @Override public String getName() { return "mysql-ssl-client-store"; } - + }; - + /** * The password to use to access the mysql-ssl-client-store file. By * default no password will be used to attempt to access the file. */ public static final StringGuacamoleProperty MYSQL_SSL_CLIENT_PASSWORD = new StringGuacamoleProperty() { - + @Override public String getName() { return "mysql-ssl-client-password"; } - + }; - + /** * Whether or not to automatically create accounts in the MySQL database for * users who successfully authenticate through another extension. By default @@ -249,7 +249,7 @@ public class MySQLGuacamoleProperties { */ public static final BooleanGuacamoleProperty MYSQL_AUTO_CREATE_ACCOUNTS = new BooleanGuacamoleProperty() { - + @Override public String getName() { return "mysql-auto-create-accounts"; } }; @@ -259,10 +259,23 @@ public class MySQLGuacamoleProperties { */ public static final TimeZoneGuacamoleProperty SERVER_TIMEZONE = new TimeZoneGuacamoleProperty() { - + @Override public String getName() { return "mysql-server-timezone"; } - + + }; + + /** + * Whether or not to track connection history for connections that do not originate + * from within the MySQL database. By default, external connection history will be + * tracked. + */ + public static final BooleanGuacamoleProperty MYSQL_TRACK_EXTERNAL_CONNECTION_HISTORY = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "mysql-track-external-connection-history"; } + }; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java index 2ead15b6e..ac08e0ae0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java @@ -110,7 +110,7 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { * the values that should be used in the absence of the correct properties. */ private final int DEFAULT_MAX_GROUP_CONNECTIONS = 0; - + /** * The default value to use for SSL mode if none is explicitly configured. */ @@ -119,8 +119,8 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { /** * Constructs a new PostgreSQLEnvironment, providing access to PostgreSQL-specific * configuration options. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If an error occurs while setting up the underlying JDBCEnvironment * or while parsing legacy PostgreSQL configuration options. */ @@ -186,11 +186,11 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { /** * Returns the hostname of the PostgreSQL server hosting the Guacamole * authentication tables. If unspecified, this will be "localhost". - * + * * @return * The URL of the PostgreSQL server. * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value. */ public String getPostgreSQLHostname() throws GuacamoleException { @@ -199,16 +199,16 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { DEFAULT_HOSTNAME ); } - + /** * Returns the port number of the PostgreSQL server hosting the Guacamole * authentication tables. If unspecified, this will be the default * PostgreSQL port of 5432. - * + * * @return * The port number of the PostgreSQL server. * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value. */ public int getPostgreSQLPort() throws GuacamoleException { @@ -217,15 +217,15 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { DEFAULT_PORT ); } - + /** * Returns the name of the PostgreSQL database containing the Guacamole * authentication tables. - * + * * @return * The name of the PostgreSQL database. * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value, or if the * value was not set, as this property is required. */ @@ -242,16 +242,16 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { public String getPassword() throws GuacamoleException { return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD); } - + /** * Returns the defaultStatementTimeout set for PostgreSQL connections. * If unspecified, this will default to 0, * and should not be passed through to the backend. - * + * * @return * The statement timeout (in seconds) * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value. */ public int getPostgreSQLDefaultStatementTimeout() throws GuacamoleException { @@ -260,15 +260,15 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { DEFAULT_STATEMENT_TIMEOUT ); } - + /** * Returns the socketTimeout property to set on PostgreSQL connections. * If unspecified, this will default to 0 (no timeout) - * + * * @return * The socketTimeout to use when waiting on read operations (in seconds) * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value. */ public int getPostgreSQLSocketTimeout() throws GuacamoleException { @@ -282,85 +282,93 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { public boolean isRecursiveQuerySupported(SqlSession session) { return true; // All versions of PostgreSQL support recursive queries through CTEs } - + /** * Get the SSL mode to use to make the JDBC connection to the PostgreSQL * server. If unspecified this will default to PREFER, attempting SSL * and falling back to plain-text if SSL fails. - * + * * @return * The enum value of the SSL mode to use to make the JDBC connection * to the server. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If an error occurs retrieving the value from guacamole.properties. */ public PostgreSQLSSLMode getPostgreSQLSSLMode() throws GuacamoleException { return getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_SSL_MODE, DEFAULT_SSL_MODE); } - + /** * Return the SSL client certificate file to use to make the connection * to the PostgreSQL server. - * + * * @return * The SSL client certificate file to use for the PostgreSQL connection. - * + * * @throws GuacamoleException * If an error occurs retrieving the value from guacamole.properties. */ public File getPostgreSQLSSLClientCertFile() throws GuacamoleException { return getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_SSL_CERT_FILE); } - + /** * Return the SSL client private key file to use to make the connection to the * PostgreSQL server. - * + * * @return * The SSL client private key file to use for the PostgreSQL connection. - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs retrieving the value from guacamole.properties. */ public File getPostgreSQLSSLClientKeyFile() throws GuacamoleException { return getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_SSL_KEY_FILE); } - + /** * Return the SSL client root certificate file to use to make the connection * to the PostgreSQL server. - * + * * @return * The SSL client root certificate file to use to make the connection * to the PostgreSQL server. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If an error occurs retrieving the value from guacamole.properties. */ public File getPostgreSQLSSLClientRootCertFile() throws GuacamoleException { return getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_SSL_ROOT_CERT_FILE); } - + /** * Return the password to use to decrypt the private SSL key file when making * the connection to the PostgreSQL server. - * + * * @return * The password to use to decrypt the private SSL key file when making * the connection to the PostgreSQL server. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If an error occurs retrieving the value from guacamole.properties. */ public String getPostgreSQLSSLClientKeyPassword() throws GuacamoleException { return getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_SSL_KEY_PASSWORD); } - + @Override public boolean autoCreateAbsentAccounts() throws GuacamoleException { return getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_AUTO_CREATE_ACCOUNTS, false); } - + + @Override + public boolean trackExternalConnectionHistory() throws GuacamoleException { + + // Track external connection history unless explicitly disabled + return getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_TRACK_EXTERNAL_CONNECTION_HISTORY, + true); + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java index 271d9c0dd..dfa00b68c 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLGuacamoleProperties.java @@ -111,7 +111,7 @@ public class PostgreSQLGuacamoleProperties { * The number of seconds to wait for socket read operations. * If reading from the server takes longer than this value, the * connection will be closed. This can be used to handle network problems - * such as a dropped connection to the database. Similar to + * such as a dropped connection to the database. Similar to * postgresql-default-statement-timeout, it will have the effect of * aborting queries that take too long. * A value of 0 (the default) means the timeout is disabled. @@ -202,7 +202,7 @@ public class PostgreSQLGuacamoleProperties { public String getName() { return "postgresql-default-max-group-connections-per-user"; } }; - + /** * The SSL mode that should be used by the JDBC driver when making * connections to the remote server. By default SSL will be attempted but @@ -210,60 +210,60 @@ public class PostgreSQLGuacamoleProperties { */ public static final EnumGuacamoleProperty POSTGRESQL_SSL_MODE = new EnumGuacamoleProperty(PostgreSQLSSLMode.class) { - + @Override public String getName() { return "postgresql-ssl-mode"; } - + }; - + /** * The client SSL certificate file used by the JDBC driver to make the * SSL connection. */ public static final FileGuacamoleProperty POSTGRESQL_SSL_CERT_FILE = new FileGuacamoleProperty() { - + @Override public String getName() { return "postgresql-ssl-cert-file"; } - + }; - + /** * The client SSL private key file used by the JDBC driver to make the * SSL connection. */ public static final FileGuacamoleProperty POSTGRESQL_SSL_KEY_FILE = new FileGuacamoleProperty() { - + @Override public String getName() { return "postgresql-ssl-key-file"; } - + }; - + /** * The client SSL root certificate file used by the JDBC driver to validate * certificates when making the SSL connection. */ public static final FileGuacamoleProperty POSTGRESQL_SSL_ROOT_CERT_FILE = new FileGuacamoleProperty() { - + @Override public String getName() { return "postgresql-ssl-root-cert-file"; } - + }; - + /** * The password of the SSL private key used by the JDBC driver to make * the SSL connection to the PostgreSQL server. */ public static final StringGuacamoleProperty POSTGRESQL_SSL_KEY_PASSWORD = new StringGuacamoleProperty() { - + @Override public String getName() { return "postgresql-ssl-key-password"; } - + }; - + /** * Whether or not to automatically create accounts in the PostgreSQL * database for users who successfully authenticate through another @@ -271,10 +271,23 @@ public class PostgreSQLGuacamoleProperties { */ public static final BooleanGuacamoleProperty POSTGRESQL_AUTO_CREATE_ACCOUNTS = new BooleanGuacamoleProperty() { - + @Override public String getName() { return "postgresql-auto-create-accounts"; } - + }; - + + /** + * Whether or not to track connection history for connections that do not originate + * from within the Postgres database. By default, external connection history will be + * tracked. + */ + public static final BooleanGuacamoleProperty POSTGRESQL_TRACK_EXTERNAL_CONNECTION_HISTORY = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-track-external-connection-history"; } + + }; + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java index 0e1554371..0b6983691 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java @@ -91,8 +91,8 @@ public class SQLServerEnvironment extends JDBCEnvironment { /** * Constructs a new SQLServerEnvironment, providing access to SQLServer-specific * configuration options. - * - * @throws GuacamoleException + * + * @throws GuacamoleException * If an error occurs while setting up the underlying JDBCEnvironment * or while parsing legacy SQLServer configuration options. */ @@ -158,11 +158,11 @@ public class SQLServerEnvironment extends JDBCEnvironment { /** * Returns the hostname of the SQLServer server hosting the Guacamole * authentication tables. If unspecified, this will be "localhost". - * + * * @return * The URL of the SQLServer server. * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value. */ public String getSQLServerHostname() throws GuacamoleException { @@ -171,15 +171,15 @@ public class SQLServerEnvironment extends JDBCEnvironment { DEFAULT_HOSTNAME ); } - + /** * Returns the instance name of the SQL Server installation hosting the * Guacamole database, if any. If unspecified it will be null. - * + * * @return * The instance name of the SQL Server install hosting the Guacamole * database, or null if undefined. - * + * * @throws GuacamoleException * If an error occurs reading guacamole.properties. */ @@ -188,16 +188,16 @@ public class SQLServerEnvironment extends JDBCEnvironment { SQLServerGuacamoleProperties.SQLSERVER_INSTANCE ); } - + /** * Returns the port number of the SQLServer server hosting the Guacamole * authentication tables. If unspecified, this will be the default * SQLServer port of 5432. - * + * * @return * The port number of the SQLServer server. * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value. */ public int getSQLServerPort() throws GuacamoleException { @@ -206,15 +206,15 @@ public class SQLServerEnvironment extends JDBCEnvironment { DEFAULT_PORT ); } - + /** * Returns the name of the SQLServer database containing the Guacamole * authentication tables. - * + * * @return * The name of the SQLServer database. * - * @throws GuacamoleException + * @throws GuacamoleException * If an error occurs while retrieving the property value, or if the * value was not set, as this property is required. */ @@ -226,7 +226,7 @@ public class SQLServerEnvironment extends JDBCEnvironment { public String getUsername() throws GuacamoleException { return getRequiredProperty(SQLServerGuacamoleProperties.SQLSERVER_USERNAME); } - + @Override public String getPassword() throws GuacamoleException { return getRequiredProperty(SQLServerGuacamoleProperties.SQLSERVER_PASSWORD); @@ -253,11 +253,19 @@ public class SQLServerEnvironment extends JDBCEnvironment { public boolean isRecursiveQuerySupported(SqlSession session) { return true; // All versions of SQL Server support recursive queries through CTEs } - + @Override public boolean autoCreateAbsentAccounts() throws GuacamoleException { return getProperty(SQLServerGuacamoleProperties.SQLSERVER_AUTO_CREATE_ACCOUNTS, false); } + @Override + public boolean trackExternalConnectionHistory() throws GuacamoleException { + + // Track external connection history unless explicitly disabled + return getProperty(SQLServerGuacamoleProperties.SQLSERVER_TRACK_EXTERNAL_CONNECTION_HISTORY, + true); + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerGuacamoleProperties.java index df63c53e9..432454ed8 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerGuacamoleProperties.java @@ -44,7 +44,7 @@ public class SQLServerGuacamoleProperties { public String getName() { return "sqlserver-hostname"; } }; - + /** * The instance name of the SQL Server where the Guacamole database is running. */ @@ -53,7 +53,7 @@ public class SQLServerGuacamoleProperties { @Override public String getName() { return "sqlserver-instance"; } - + }; /** @@ -193,7 +193,7 @@ public class SQLServerGuacamoleProperties { public String getName() { return "sqlserver-driver"; } }; - + /** * Whether or not to automatically create accounts in the SQL Server * database for users who successfully authenticate through another @@ -201,10 +201,23 @@ public class SQLServerGuacamoleProperties { */ public static final BooleanGuacamoleProperty SQLSERVER_AUTO_CREATE_ACCOUNTS = new BooleanGuacamoleProperty() { - + @Override public String getName() { return "sqlserver-auto-create-accounts"; } - + + }; + + /** + * Whether or not to track connection history for connections that do not originate + * from within the SQL Server database. By default, external connection history will be + * tracked. + */ + public static final BooleanGuacamoleProperty SQLSERVER_TRACK_EXTERNAL_CONNECTION_HISTORY = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "sqlserver-track-external-connection-history"; } + }; }