Add .gitignore and .ratignore files for various directories
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
0
extensions/guacamole-auth-jdbc/.ratignore
Normal file
0
extensions/guacamole-auth-jdbc/.ratignore
Normal file
2
extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/.gitignore
vendored
Normal file
2
extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
target/
|
||||
*~
|
@@ -0,0 +1 @@
|
||||
src/main/resources/html/*.html
|
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.apache.guacamole</groupId>
|
||||
<artifactId>guacamole-auth-jdbc-base</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>guacamole-auth-jdbc-base</name>
|
||||
<url>http://guacamole.apache.org/</url>
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.guacamole</groupId>
|
||||
<artifactId>guacamole-auth-jdbc</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<relativePath>../../</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- Java servlet API -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Guacamole Extension API -->
|
||||
<dependency>
|
||||
<groupId>org.apache.guacamole</groupId>
|
||||
<artifactId>guacamole-ext</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- MyBatis -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
<version>3.5.19</version>
|
||||
</dependency>
|
||||
|
||||
<!-- MyBatis Guice -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-guice</artifactId>
|
||||
<version>3.18</version>
|
||||
<exclusions>
|
||||
|
||||
<!-- This dependency appears to be necessary only to provide an
|
||||
SLF4J bridge for the commons-logging (JCL) system used by DBCP2
|
||||
an optional dependency that is not being used here. See: https://github.com/mybatis/guice/commit/fbf655ed5bd7ecb00ec070ce20d4fe8aeb6fa9c1 -->
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</exclusion>
|
||||
|
||||
<!-- This dependency is LGPL-licensed and is listed in the
|
||||
mybatis-guice pom.xml as optional. Its only current use within
|
||||
mybatis-guice is to provide the "Nullable" annotation for a
|
||||
single member variable, and that annotation does not have
|
||||
runtime retention. -->
|
||||
<exclusion>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-annotations</artifactId>
|
||||
</exclusion>
|
||||
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Guice -->
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Guava - Utility Library -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.net.auth.AuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Credentials;
|
||||
import org.apache.guacamole.net.auth.UserContext;
|
||||
|
||||
/**
|
||||
* Service which authenticates users based on credentials and provides for
|
||||
* the creation of corresponding, new UserContext objects for authenticated
|
||||
* users.
|
||||
*/
|
||||
public interface AuthenticationProviderService {
|
||||
|
||||
/**
|
||||
* Authenticates the user having the given credentials, returning a new
|
||||
* AuthenticatedUser instance only if the credentials are valid. If the
|
||||
* credentials are invalid or expired, an appropriate GuacamoleException
|
||||
* will be thrown.
|
||||
*
|
||||
* @param authenticationProvider
|
||||
* The AuthenticationProvider on behalf of which the user is being
|
||||
* authenticated.
|
||||
*
|
||||
* @param credentials
|
||||
* The credentials to use to produce the AuthenticatedUser.
|
||||
*
|
||||
* @return
|
||||
* A new AuthenticatedUser instance for the user identified by the
|
||||
* given credentials.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs during authentication, or if the given
|
||||
* credentials are invalid or expired.
|
||||
*/
|
||||
public AuthenticatedUser authenticateUser(AuthenticationProvider authenticationProvider,
|
||||
Credentials credentials) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returning a new UserContext instance for the given already-authenticated
|
||||
* user.
|
||||
*
|
||||
* @param authenticationProvider
|
||||
* The AuthenticationProvider on behalf of which the UserContext is
|
||||
* being produced.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* The credentials to use to produce the UserContext.
|
||||
*
|
||||
* @return
|
||||
* A new UserContext instance for the user identified by the given
|
||||
* credentials, or null if no such user exists within the database.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs during authentication, or if the given
|
||||
* credentials are invalid or expired.
|
||||
*/
|
||||
public UserContext getUserContext(AuthenticationProvider authenticationProvider,
|
||||
AuthenticatedUser authenticatedUser) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns an updated UserContext instance for the given
|
||||
* already-authenticated user. If no changes need be made to the
|
||||
* UserContext, the original UserContext will be returned.
|
||||
*
|
||||
* @param authenticationProvider
|
||||
* The AuthenticationProvider on behalf of which the UserContext is
|
||||
* being updated.
|
||||
*
|
||||
* @param context
|
||||
* The UserContext to update.
|
||||
*
|
||||
* @param authenticatedUser
|
||||
* The AuthenticatedUser associated with the UserContext being updated.
|
||||
*
|
||||
* @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 new UserContext instance for the user identified by the given
|
||||
* credentials.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs during authentication, or if the given
|
||||
* credentials are invalid or expired.
|
||||
*/
|
||||
public UserContext updateUserContext(AuthenticationProvider authenticationProvider,
|
||||
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;
|
||||
|
||||
}
|
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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 com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.name.Named;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.ibatis.datasource.pooled.PooledDataSource;
|
||||
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Pooled DataSource implementation which dynamically retrieves the database
|
||||
* username and password from the Guacamole server environment each time a
|
||||
* new database connection is created.
|
||||
*/
|
||||
@Singleton
|
||||
public class DynamicallyAuthenticatedDataSource extends PooledDataSource {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(DynamicallyAuthenticatedDataSource.class);
|
||||
|
||||
/**
|
||||
* Creates a new DynamicallyAuthenticatedDataSource which dynamically
|
||||
* retrieves database credentials from the given JDBCEnvironment each time
|
||||
* a new database connection is needed.
|
||||
*
|
||||
* @param environment
|
||||
* The JDBCEnvironment that should be used to retrieve database
|
||||
* credentials.
|
||||
*
|
||||
* @param driverClassLoader
|
||||
* @param driver
|
||||
* @param url
|
||||
*/
|
||||
@Inject
|
||||
public DynamicallyAuthenticatedDataSource(JDBCEnvironment environment,
|
||||
@Named(value="JDBC.driverClassLoader") ClassLoader driverClassLoader,
|
||||
@Named(value="JDBC.driver") String driver,
|
||||
@Named(value="JDBC.url") String url) {
|
||||
|
||||
// Wrap unpooled DataSource, overriding the connection process such
|
||||
// that credentials are dynamically retrieved from the JDBCEnvironment
|
||||
super(new UnpooledDataSource(driverClassLoader, driver, url, null, null) {
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
try {
|
||||
logger.debug("Creating new database connection for pool.");
|
||||
return super.getConnection(environment.getUsername(), environment.getPassword());
|
||||
}
|
||||
catch (GuacamoleException e) {
|
||||
throw new SQLException("Retrieval of database credentials failed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Force recalculation of expectedConnectionTypeCode. The
|
||||
// PooledDataSource constructor accepting a single UnpooledDataSource
|
||||
// will otherwise leave this value uninitialized, resulting in all
|
||||
// connections failing to pass sanity checks and never being returned
|
||||
// to the pool.
|
||||
super.forceCloseAll();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setPoolPingConnectionsNotUsedFor(
|
||||
@Named("mybatis.pooled.pingConnectionsNotUsedFor") int milliseconds) {
|
||||
super.setPoolPingConnectionsNotUsedFor(milliseconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setPoolPingEnabled(@Named("mybatis.pooled.pingEnabled") boolean poolPingEnabled) {
|
||||
super.setPoolPingEnabled(poolPingEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setPoolPingQuery(@Named("mybatis.pooled.pingQuery") String poolPingQuery) {
|
||||
super.setPoolPingQuery(poolPingQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setPoolTimeToWait(@Named("mybatis.pooled.timeToWait") int poolTimeToWait) {
|
||||
super.setPoolTimeToWait(poolTimeToWait);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setPoolMaximumCheckoutTime(
|
||||
@Named("mybatis.pooled.maximumCheckoutTime") int poolMaximumCheckoutTime) {
|
||||
super.setPoolMaximumCheckoutTime(poolMaximumCheckoutTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setPoolMaximumIdleConnections(
|
||||
@Named("mybatis.pooled.maximumIdleConnections") int poolMaximumIdleConnections) {
|
||||
super.setPoolMaximumIdleConnections(poolMaximumIdleConnections);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setPoolMaximumActiveConnections(
|
||||
@Named("mybatis.pooled.maximumActiveConnections") int poolMaximumActiveConnections) {
|
||||
super.setPoolMaximumActiveConnections(poolMaximumActiveConnections);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setDriverProperties(@Named("JDBC.driverProperties") Properties driverProps) {
|
||||
super.setDriverProperties(driverProps);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setDefaultAutoCommit(@Named("JDBC.autoCommit") boolean defaultAutoCommit) {
|
||||
super.setDefaultAutoCommit(defaultAutoCommit);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Inject(optional=true)
|
||||
public void setLoginTimeout(@Named("JDBC.loginTimeout") int loginTimeout) {
|
||||
super.setLoginTimeout(loginTimeout);
|
||||
}
|
||||
|
||||
}
|
@@ -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;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
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.auth.jdbc.connection.ModeledConnectionRecord;
|
||||
import org.apache.guacamole.environment.Environment;
|
||||
import org.apache.guacamole.environment.LocalEnvironment;
|
||||
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;
|
||||
|
||||
/**
|
||||
* The environment in which Guacamole is running.
|
||||
*/
|
||||
private final Environment environment = LocalEnvironment.getInstance();
|
||||
|
||||
/**
|
||||
* 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<String, String> 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,
|
||||
environment.getCaseSensitivity());
|
||||
|
||||
// Include history record UUID as token
|
||||
ModeledConnectionRecord modeledRecord = new ModeledConnectionRecord(connectionRecordModel);
|
||||
Map<String, String> updatedTokens = new HashMap<>(tokens);
|
||||
updatedTokens.put("HISTORY_UUID", modeledRecord.getUUID().toString());
|
||||
|
||||
// Connect, and wrap the tunnel for return
|
||||
GuacamoleTunnel tunnel = super.connect(info, updatedTokens);
|
||||
return new HistoryTrackingTunnel(
|
||||
tunnel, this.connectionRecordMapper, connectionRecordModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Connection wrapped by this HistoryTrackingConnection.
|
||||
*
|
||||
* @return
|
||||
* The wrapped Connection.
|
||||
*/
|
||||
public Connection getWrappedConnection() {
|
||||
return getDelegateConnection();
|
||||
}
|
||||
|
||||
}
|
@@ -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<Connection> {
|
||||
|
||||
/**
|
||||
* 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<Connection> 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;
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
||||
}
|
@@ -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<Connection> getConnectionDirectory() throws GuacamoleException {
|
||||
return new HistoryTrackingConnectionDirectory(
|
||||
super.getConnectionDirectory(), self(),
|
||||
this.remoteHost, this.connectionRecordMapper);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 com.google.inject.Injector;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.net.auth.AbstractAuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Credentials;
|
||||
import org.apache.guacamole.net.auth.UserContext;
|
||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||
|
||||
/**
|
||||
* Provides a base implementation of an AuthenticationProvider which delegates
|
||||
* the various function calls to an underlying AuthenticationProviderService
|
||||
* implementation. As such a service is injectable by Guice, this provides a
|
||||
* means for Guice to (effectively) apply dependency injection to an
|
||||
* AuthenticationProvider, even though it is the AuthenticationProvider that
|
||||
* serves as the entry point.
|
||||
*/
|
||||
public abstract class InjectedAuthenticationProvider extends AbstractAuthenticationProvider {
|
||||
|
||||
/**
|
||||
* The AuthenticationProviderService to which all AuthenticationProvider
|
||||
* calls will be delegated.
|
||||
*/
|
||||
private final AuthenticationProviderService authProviderService;
|
||||
|
||||
/**
|
||||
* Creates a new AuthenticationProvider that delegates all calls to an
|
||||
* underlying AuthenticationProviderService. The behavior of the
|
||||
* AuthenticationProvider is defined by the given
|
||||
* AuthenticationProviderService implementation, which will be injected by
|
||||
* the Guice Injector provided by the given JDBCInjectorProvider.
|
||||
*
|
||||
* @param injectorProvider
|
||||
* A JDBCInjectorProvider instance which provides singleton instances
|
||||
* of a Guice Injector, pre-configured to set up all injections and
|
||||
* access to the underlying database via MyBatis.
|
||||
*
|
||||
* @param authProviderServiceClass
|
||||
* The AuthenticationProviderService implementation which defines the
|
||||
* behavior of this AuthenticationProvider.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the Injector cannot be created due to an error.
|
||||
*/
|
||||
public InjectedAuthenticationProvider(JDBCInjectorProvider injectorProvider,
|
||||
Class<? extends AuthenticationProviderService> authProviderServiceClass)
|
||||
throws GuacamoleException {
|
||||
|
||||
Injector injector = injectorProvider.get();
|
||||
authProviderService = injector.getInstance(authProviderServiceClass);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatedUser authenticateUser(Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
return authProviderService.authenticateUser(this, credentials);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext getUserContext(AuthenticatedUser authenticatedUser)
|
||||
throws GuacamoleException {
|
||||
return authProviderService.getUserContext(this, authenticatedUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext updateUserContext(UserContext context,
|
||||
AuthenticatedUser authenticatedUser, Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
return authProviderService.updateUserContext(this, context,
|
||||
authenticatedUser, credentials);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext decorate(UserContext context,
|
||||
AuthenticatedUser authenticatedUser, Credentials credentials)
|
||||
throws GuacamoleException {
|
||||
return authProviderService.decorateUserContext(this, context,
|
||||
authenticatedUser, credentials);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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 com.google.inject.Scopes;
|
||||
import javax.sql.DataSource;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledUserContext;
|
||||
import org.apache.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup;
|
||||
import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
||||
import org.apache.guacamole.auth.jdbc.connectiongroup.ConnectionGroupDirectory;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ConnectionDirectory;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ModeledGuacamoleConfiguration;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SystemPermissionSet;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserDirectory;
|
||||
import org.apache.guacamole.auth.jdbc.connectiongroup.ConnectionGroupMapper;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ConnectionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SystemPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserMapper;
|
||||
import org.apache.guacamole.auth.jdbc.connectiongroup.ConnectionGroupService;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ConnectionService;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService;
|
||||
import org.apache.guacamole.auth.jdbc.security.SHA256PasswordEncryptionService;
|
||||
import org.apache.guacamole.auth.jdbc.security.SaltService;
|
||||
import org.apache.guacamole.auth.jdbc.security.SecureRandomSaltService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SystemPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserService;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionSet;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionSet;
|
||||
import org.apache.guacamole.auth.jdbc.permission.UserPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.UserPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.UserPermissionSet;
|
||||
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionDirectory;
|
||||
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionSet;
|
||||
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionService;
|
||||
import org.apache.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityMapper;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityService;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionSet;
|
||||
import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionSet;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordPolicyService;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.HashSharedConnectionMap;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.SecureRandomShareKeyGenerator;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.ShareKeyGenerator;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.SharedConnectionMap;
|
||||
import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
|
||||
import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileDirectory;
|
||||
import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileMapper;
|
||||
import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileParameterMapper;
|
||||
import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileService;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.RestrictedGuacamoleTunnelService;
|
||||
import org.apache.guacamole.auth.jdbc.user.PasswordRecordMapper;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserRecordMapper;
|
||||
import org.apache.guacamole.auth.jdbc.usergroup.ModeledUserGroup;
|
||||
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory;
|
||||
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper;
|
||||
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper;
|
||||
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper;
|
||||
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper;
|
||||
import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService;
|
||||
import org.mybatis.guice.MyBatisModule;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper;
|
||||
|
||||
/**
|
||||
* Guice module which configures the injections used by the JDBC authentication
|
||||
* provider base. This module MUST be included in the Guice injector, or
|
||||
* authentication providers based on JDBC will not function.
|
||||
*/
|
||||
public class JDBCAuthenticationProviderModule extends MyBatisModule {
|
||||
|
||||
/**
|
||||
* The environment of the Guacamole server.
|
||||
*/
|
||||
private final JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Creates a new JDBC authentication provider module that configures the
|
||||
* various injected base classes using the given environment, and provides
|
||||
* connections using the given socket service.
|
||||
*
|
||||
* @param environment
|
||||
* The environment to use to configure injected classes.
|
||||
*/
|
||||
public JDBCAuthenticationProviderModule(JDBCEnvironment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize() {
|
||||
|
||||
// Datasource
|
||||
bind(DataSource.class).to(DynamicallyAuthenticatedDataSource.class);
|
||||
|
||||
// Transaction factory
|
||||
bindTransactionFactoryType(JdbcTransactionFactory.class);
|
||||
|
||||
// Set the JDBC Auth provider to use batch execution if enabled
|
||||
if (environment.shouldUseBatchExecutor())
|
||||
bindConfigurationSetting(configuration -> {
|
||||
configuration.setDefaultExecutorType(ExecutorType.BATCH);
|
||||
});
|
||||
|
||||
// Add MyBatis mappers
|
||||
addMapperClass(ConnectionMapper.class);
|
||||
addMapperClass(ConnectionGroupMapper.class);
|
||||
addMapperClass(ConnectionGroupPermissionMapper.class);
|
||||
addMapperClass(ConnectionPermissionMapper.class);
|
||||
addMapperClass(ConnectionRecordMapper.class);
|
||||
addMapperClass(ConnectionParameterMapper.class);
|
||||
addMapperClass(EntityMapper.class);
|
||||
addMapperClass(PasswordRecordMapper.class);
|
||||
addMapperClass(SystemPermissionMapper.class);
|
||||
addMapperClass(SharingProfileMapper.class);
|
||||
addMapperClass(SharingProfileParameterMapper.class);
|
||||
addMapperClass(SharingProfilePermissionMapper.class);
|
||||
addMapperClass(UserGroupMapper.class);
|
||||
addMapperClass(UserGroupMemberUserGroupMapper.class);
|
||||
addMapperClass(UserGroupMemberUserMapper.class);
|
||||
addMapperClass(UserGroupParentUserGroupMapper.class);
|
||||
addMapperClass(UserGroupPermissionMapper.class);
|
||||
addMapperClass(UserMapper.class);
|
||||
addMapperClass(UserParentUserGroupMapper.class);
|
||||
addMapperClass(UserPermissionMapper.class);
|
||||
addMapperClass(UserRecordMapper.class);
|
||||
|
||||
// Bind core implementations of guacamole-ext classes
|
||||
bind(ActiveConnectionDirectory.class);
|
||||
bind(ActiveConnectionPermissionSet.class);
|
||||
bind(JDBCEnvironment.class).toInstance(environment);
|
||||
bind(ConnectionDirectory.class);
|
||||
bind(ConnectionGroupDirectory.class);
|
||||
bind(ConnectionGroupPermissionSet.class);
|
||||
bind(ConnectionPermissionSet.class);
|
||||
bind(ModeledConnection.class);
|
||||
bind(ModeledConnectionGroup.class);
|
||||
bind(ModeledGuacamoleConfiguration.class);
|
||||
bind(ModeledSharingProfile.class);
|
||||
bind(ModeledUser.class);
|
||||
bind(ModeledUserContext.class);
|
||||
bind(ModeledUserGroup.class);
|
||||
bind(RootConnectionGroup.class);
|
||||
bind(SharingProfileDirectory.class);
|
||||
bind(SharingProfilePermissionSet.class);
|
||||
bind(SystemPermissionSet.class);
|
||||
bind(TrackedActiveConnection.class);
|
||||
bind(UserDirectory.class);
|
||||
bind(UserGroupDirectory.class);
|
||||
bind(UserGroupPermissionSet.class);
|
||||
bind(UserPermissionSet.class);
|
||||
|
||||
// Bind services
|
||||
bind(ActiveConnectionService.class);
|
||||
bind(ActiveConnectionPermissionService.class);
|
||||
bind(ConnectionGroupPermissionService.class);
|
||||
bind(ConnectionGroupService.class);
|
||||
bind(ConnectionPermissionService.class);
|
||||
bind(ConnectionSharingService.class);
|
||||
bind(ConnectionService.class);
|
||||
bind(EntityService.class);
|
||||
bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class);
|
||||
bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
|
||||
bind(PasswordPolicyService.class);
|
||||
bind(SaltService.class).to(SecureRandomSaltService.class);
|
||||
bind(SharedConnectionMap.class).to(HashSharedConnectionMap.class).in(Scopes.SINGLETON);
|
||||
bind(ShareKeyGenerator.class).to(SecureRandomShareKeyGenerator.class).in(Scopes.SINGLETON);
|
||||
bind(SharingProfilePermissionService.class);
|
||||
bind(SharingProfileService.class);
|
||||
bind(SystemPermissionService.class);
|
||||
bind(UserGroupService.class);
|
||||
bind(UserGroupPermissionService.class);
|
||||
bind(UserPermissionService.class);
|
||||
bind(UserService.class);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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 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;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledUserContext;
|
||||
import org.apache.guacamole.auth.jdbc.user.PrivilegedModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserService;
|
||||
import org.apache.guacamole.language.TranslatableGuacamoleClientException;
|
||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Credentials;
|
||||
import org.apache.guacamole.net.auth.UserContext;
|
||||
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
|
||||
|
||||
/**
|
||||
* AuthenticationProviderService implementation which authenticates users with
|
||||
* a username/password pair, producing new UserContext objects which are backed
|
||||
* by an underlying, arbitrary database.
|
||||
*/
|
||||
public class JDBCAuthenticationProviderService implements AuthenticationProviderService {
|
||||
|
||||
/**
|
||||
* The environment of the Guacamole server.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Service for accessing users.
|
||||
*/
|
||||
@Inject
|
||||
private UserService userService;
|
||||
|
||||
/**
|
||||
* Service for enforcing password complexity policies.
|
||||
*/
|
||||
@Inject
|
||||
private PasswordPolicyService passwordPolicyService;
|
||||
|
||||
/**
|
||||
* Provider for retrieving UserContext instances.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<ModeledUserContext> userContextProvider;
|
||||
|
||||
/**
|
||||
* Mapper for writing connection history.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionRecordMapper connectionRecordMapper;
|
||||
|
||||
@Override
|
||||
public AuthenticatedUser authenticateUser(AuthenticationProvider authenticationProvider,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
// Authenticate user
|
||||
AuthenticatedUser user = userService.retrieveAuthenticatedUser(authenticationProvider, credentials);
|
||||
if (user != null)
|
||||
return user;
|
||||
|
||||
// Otherwise, unauthorized
|
||||
throw new GuacamoleInvalidCredentialsException("Invalid login", CredentialsInfo.USERNAME_PASSWORD);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModeledUserContext getUserContext(AuthenticationProvider authenticationProvider,
|
||||
AuthenticatedUser authenticatedUser) throws GuacamoleException {
|
||||
|
||||
// Always allow but provide no data for users authenticated via our own
|
||||
// connection sharing links
|
||||
if (authenticatedUser instanceof SharedAuthenticatedUser)
|
||||
return null;
|
||||
|
||||
// Set semantic flags based on context
|
||||
boolean databaseCredentialsUsed = (authenticatedUser instanceof ModeledAuthenticatedUser);
|
||||
boolean databaseRestrictionsApplicable = (databaseCredentialsUsed || environment.isUserRequired());
|
||||
|
||||
// Retrieve user account for already-authenticated user
|
||||
ModeledUser user = userService.retrieveUser(authenticationProvider, authenticatedUser);
|
||||
ModeledUserContext context = userContextProvider.get();
|
||||
if (user != null && !user.isDisabled()) {
|
||||
|
||||
// Enforce applicable account restrictions
|
||||
if (databaseRestrictionsApplicable) {
|
||||
|
||||
// Verify user account is still valid as of today
|
||||
if (!user.isAccountValid())
|
||||
throw new TranslatableGuacamoleClientException("User "
|
||||
+ "account is no longer valid.",
|
||||
"LOGIN.ERROR_NOT_VALID");
|
||||
|
||||
// Verify user account is allowed to be used at the current time
|
||||
if (!user.isAccountAccessible())
|
||||
throw new TranslatableGuacamoleClientException("User "
|
||||
+ "account may not be used at this time.",
|
||||
"LOGIN.ERROR_NOT_ACCESSIBLE");
|
||||
|
||||
}
|
||||
|
||||
// Update password if password is expired AND the password was
|
||||
// actually involved in the authentication process
|
||||
if (databaseCredentialsUsed) {
|
||||
if (user.isExpired() || passwordPolicyService.isPasswordExpired(user))
|
||||
userService.resetExpiredPassword(user, authenticatedUser.getCredentials());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
// restrictions apply in this situation
|
||||
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();
|
||||
return context;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserContext updateUserContext(AuthenticationProvider authenticationProvider,
|
||||
UserContext context, AuthenticatedUser authenticatedUser,
|
||||
Credentials credentials) throws GuacamoleException {
|
||||
|
||||
// Refresh the user context
|
||||
return getUserContext(authenticationProvider, authenticatedUser);
|
||||
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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.security.PasswordPolicy;
|
||||
import org.apache.guacamole.environment.DelegatingEnvironment;
|
||||
import org.apache.guacamole.environment.LocalEnvironment;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
|
||||
/**
|
||||
* A JDBC-specific implementation of Environment that defines generic properties
|
||||
* 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.
|
||||
*/
|
||||
public JDBCEnvironment() {
|
||||
super(LocalEnvironment.getInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a database user account is required for authentication to
|
||||
* succeed, even if another authentication provider has already
|
||||
* authenticated the user.
|
||||
*
|
||||
* @return
|
||||
* true if database user accounts are required for absolutely all
|
||||
* authentication attempts, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the property.
|
||||
*/
|
||||
public abstract boolean isUserRequired() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the maximum number of concurrent connections to allow overall.
|
||||
* As this limit applies globally (independent of which connection is in
|
||||
* use or which user is using it), this setting cannot be overridden at the
|
||||
* connection level. Zero denotes unlimited.
|
||||
*
|
||||
* @return
|
||||
* The maximum allowable number of concurrent connections.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the property.
|
||||
*/
|
||||
public abstract int getAbsoluteMaxConnections() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the maximum number of identifiers/parameters to be
|
||||
* included in a single batch when executing SQL statements.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of identifiers/parameters to be included
|
||||
* in a single batch.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the property.
|
||||
*/
|
||||
public abstract int getBatchSize() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* to any connection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the property.
|
||||
*/
|
||||
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
|
||||
* connection group. Zero denotes unlimited.
|
||||
*
|
||||
* @return
|
||||
* The default maximum allowable number of concurrent connections
|
||||
* to any connection group.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the property.
|
||||
*/
|
||||
public abstract int getDefaultMaxGroupConnections()
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the property.
|
||||
*/
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the property.
|
||||
*/
|
||||
public abstract int getDefaultMaxGroupConnectionsPerUser()
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the policy which applies to newly-set passwords. Passwords which
|
||||
* apply to Guacamole user accounts will be required to conform to this
|
||||
* policy.
|
||||
*
|
||||
* @return
|
||||
* The password policy which applies to Guacamole user accounts.
|
||||
*/
|
||||
public abstract PasswordPolicy getPasswordPolicy();
|
||||
|
||||
/**
|
||||
* Returns whether the database supports recursive queries. Many database
|
||||
* engines support recursive queries through CTEs. If recursive queries are
|
||||
* not supported, queries that are intended to be recursive may need to be
|
||||
* invoked multiple times to retrieve the same data.
|
||||
*
|
||||
* @param session
|
||||
* The SqlSession provided by MyBatis for the current transaction.
|
||||
*
|
||||
* @return
|
||||
* 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
|
||||
* If guacamole.properties cannot be parsed.
|
||||
*/
|
||||
public abstract boolean autoCreateAbsentAccounts() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the username that should be used when authenticating with the
|
||||
* database containing the Guacamole authentication tables.
|
||||
*
|
||||
* @return
|
||||
* The username for the database.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the property value, or if the
|
||||
* value was not set, as this property is required.
|
||||
*/
|
||||
public abstract String getUsername() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the password that should be used authenticating with the
|
||||
* database containing the Guacamole authentication tables.
|
||||
*
|
||||
* @return
|
||||
* The password for the database.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the property value, or if the
|
||||
* value was not set, as this property is required.
|
||||
*/
|
||||
public abstract String getPassword() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns whether the given Java class is defined within the classpath.
|
||||
*
|
||||
* @param classname
|
||||
* The name of the Java class to check.
|
||||
*
|
||||
* @return
|
||||
* true if the given Java class is present within the classpath, false
|
||||
* otherwise.
|
||||
*/
|
||||
public static boolean isClassDefined(String classname) {
|
||||
try {
|
||||
Class.forName(classname, false, JDBCEnvironment.class.getClassLoader());
|
||||
return true;
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Returns a boolean value representing whether access time windows should
|
||||
* be enforced for active connections - i.e. whether a currently-connected
|
||||
* user should be disconnected upon the closure of an access window.
|
||||
*
|
||||
* @return
|
||||
* true if a connected user should be disconnected upon an access time
|
||||
* window closing, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed.
|
||||
*/
|
||||
public abstract boolean enforceAccessWindowsForActiveSessions() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns true if the JDBC batch executor should be used by default, false
|
||||
* otherwise. The batch executor allows repeated updates to be batched
|
||||
* together for improved performance.
|
||||
* See https://mybatis.org/mybatis-3/java-api.html#sqlSessions
|
||||
*
|
||||
* @return
|
||||
* true if the batch executor should be used by default, false otherwise.
|
||||
*/
|
||||
public boolean shouldUseBatchExecutor() {
|
||||
|
||||
// Unless otherwise overwritten due to implementation-specific problems,
|
||||
// all JDBC extensions should use the batch executor if possible to
|
||||
// ensure the best performance for repetitive queries
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 com.google.inject.Injector;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
|
||||
/**
|
||||
* A caching provider of singleton Guice Injector instances. The first call to
|
||||
* get() will return a new instance of the Guice Injector, while all subsequent
|
||||
* calls will return that same instance. It is up to implementations of this
|
||||
* class to define how the Guice Injector will be created through defining the
|
||||
* create() function.
|
||||
*
|
||||
* IMPORTANT: Because the Injector returned by get() is cached statically, only
|
||||
* ONE implementation of this class may be used within any individual
|
||||
* classloader. Within the context of the JDBC extension, as long as each built
|
||||
* extension only provides one subclass of this class, things should work
|
||||
* properly, as each extension is given its own classloader by Guacamole.
|
||||
*/
|
||||
public abstract class JDBCInjectorProvider {
|
||||
|
||||
/**
|
||||
* An AtomicReference wrapping the cached Guice Injector. If the Injector
|
||||
* has not yet been created, null will be wrapped instead.
|
||||
*/
|
||||
private static final AtomicReference<Injector> injector = new AtomicReference<Injector>(null);
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Guice Injector which should be used
|
||||
* across the entire JDBC authentication extension. This function will
|
||||
* generally only be called once, but multiple invocations are possible if
|
||||
* get() is invoked several times concurrently prior to the Injector being
|
||||
* cached.
|
||||
*
|
||||
* @return
|
||||
* @throws GuacamoleException
|
||||
*/
|
||||
protected abstract Injector create() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns a common, singleton instance of a Guice Injector, configured for
|
||||
* the injections required by the JDBC authentication extension. The result
|
||||
* of the first call to this function will be cached statically within this
|
||||
* class, and will be returned for all subsequent calls.
|
||||
*
|
||||
* @return
|
||||
* A singleton instance of the Guice Injector used across the entire
|
||||
* JDBC authentication extension.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the Injector cannot be created due to an error.
|
||||
*/
|
||||
public Injector get() throws GuacamoleException {
|
||||
|
||||
// Return existing Injector if already created
|
||||
Injector value = injector.get();
|
||||
if (value != null)
|
||||
return value;
|
||||
|
||||
// Explicitly create and store new Injector only if necessary
|
||||
injector.compareAndSet(null, create());
|
||||
|
||||
// Consistently return the same Injector, even if two create operations
|
||||
// happen concurrently
|
||||
return injector.get();
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.activeconnection;
|
||||
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.JDBCDirectory;
|
||||
import org.apache.guacamole.net.auth.ActiveConnection;
|
||||
|
||||
/**
|
||||
* Implementation of a Directory which contains all currently-active
|
||||
* connections.
|
||||
*/
|
||||
public class ActiveConnectionDirectory extends JDBCDirectory<ActiveConnection> {
|
||||
|
||||
/**
|
||||
* Service for retrieving and manipulating active connections.
|
||||
*/
|
||||
@Inject
|
||||
private ActiveConnectionService activeConnectionService;
|
||||
|
||||
@Override
|
||||
public ActiveConnection get(String identifier) throws GuacamoleException {
|
||||
return activeConnectionService.retrieveObject(getCurrentUser(), identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ActiveConnection> getAll(Collection<String> identifiers)
|
||||
throws GuacamoleException {
|
||||
Collection<TrackedActiveConnection> objects = activeConnectionService.retrieveObjects(getCurrentUser(), identifiers);
|
||||
return Collections.<ActiveConnection>unmodifiableCollection(objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getIdentifiers() throws GuacamoleException {
|
||||
return activeConnectionService.getIdentifiers(getCurrentUser());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(ActiveConnection object) throws GuacamoleException {
|
||||
activeConnectionService.createObject(getCurrentUser(), object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(ActiveConnection object) throws GuacamoleException {
|
||||
TrackedActiveConnection connection = (TrackedActiveConnection) object;
|
||||
activeConnectionService.updateObject(getCurrentUser(), connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String identifier) throws GuacamoleException {
|
||||
activeConnectionService.deleteObject(getCurrentUser(), identifier);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.activeconnection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.auth.jdbc.permission.AbstractPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* manipulating active connections.
|
||||
*/
|
||||
public class ActiveConnectionPermissionService
|
||||
extends AbstractPermissionService<ObjectPermissionSet, ObjectPermission>
|
||||
implements ObjectPermissionService {
|
||||
|
||||
/**
|
||||
* Service for creating and tracking tunnels.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleTunnelService tunnelService;
|
||||
|
||||
/**
|
||||
* Provider for active connection permission sets.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<ActiveConnectionPermissionSet> activeConnectionPermissionSetProvider;
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
ObjectPermission.Type type, String identifier,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Retrieve permissions
|
||||
Set<ObjectPermission> permissions = retrievePermissions(user,
|
||||
targetEntity, effectiveGroups);
|
||||
|
||||
// Permission is granted if retrieved permissions contains the
|
||||
// requested permission
|
||||
ObjectPermission permission = new ObjectPermission(type, identifier);
|
||||
return permissions.contains(permission);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ObjectPermission> retrievePermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Retrieve permissions only if allowed
|
||||
if (canReadPermissions(user, targetEntity)) {
|
||||
|
||||
// Privileged accounts (such as administrators or UserContexts
|
||||
// returned by getPrivileged()) may always access active connections
|
||||
boolean isPrivileged = targetEntity.isPrivileged();
|
||||
|
||||
// Get all active connections
|
||||
Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
|
||||
|
||||
// We have READ, and possibly DELETE, on all active connections
|
||||
Set<ObjectPermission> permissions = new HashSet<>();
|
||||
for (ActiveConnectionRecord record : records) {
|
||||
|
||||
// Add implicit READ
|
||||
String identifier = record.getUUID().toString();
|
||||
permissions.add(new ObjectPermission(ObjectPermission.Type.READ, identifier));
|
||||
|
||||
// If the target user is privileged, or the connection belongs
|
||||
// to the target user, then they can DELETE
|
||||
if (isPrivileged || targetEntity.isUser(record.getUsername()))
|
||||
permissions.add(new ObjectPermission(ObjectPermission.Type.DELETE, identifier));
|
||||
|
||||
}
|
||||
|
||||
return permissions;
|
||||
|
||||
}
|
||||
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<ObjectPermission.Type> permissionTypes,
|
||||
Collection<String> identifiers, Set<String> effectiveGroups)
|
||||
throws GuacamoleException {
|
||||
|
||||
Set<ObjectPermission> permissions = retrievePermissions(user, targetEntity, effectiveGroups);
|
||||
Collection<String> accessibleObjects = new ArrayList<String>(permissions.size());
|
||||
|
||||
// For each identifier/permission combination
|
||||
for (String identifier : identifiers) {
|
||||
for (ObjectPermission.Type permissionType : permissionTypes) {
|
||||
|
||||
// Add identifier if at least one requested permission is granted
|
||||
ObjectPermission permission = new ObjectPermission(permissionType, identifier);
|
||||
if (permissions.contains(permission)) {
|
||||
accessibleObjects.add(identifier);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return accessibleObjects;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Create permission set for requested entity
|
||||
ActiveConnectionPermissionSet permissionSet = activeConnectionPermissionSetProvider.get();
|
||||
permissionSet.init(user, targetEntity, effectiveGroups);
|
||||
|
||||
return permissionSet;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createPermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<ObjectPermission> permissions)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Creating active connection permissions is not implemented
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<ObjectPermission> permissions)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Deleting active connection permissions is not implemented
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.activeconnection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionSet;
|
||||
|
||||
/**
|
||||
* An implementation of ObjectPermissionSet which uses an injected service to
|
||||
* query and manipulate the permissions associated with active connections.
|
||||
*/
|
||||
public class ActiveConnectionPermissionSet extends ObjectPermissionSet {
|
||||
|
||||
/**
|
||||
* Service for querying and manipulating active connection permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ActiveConnectionPermissionService activeConnectionPermissionService;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionService getObjectPermissionService() {
|
||||
return activeConnectionPermissionService;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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.activeconnection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.base.DirectoryObjectService;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.ActiveConnection;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* manipulating active connections.
|
||||
*/
|
||||
public class ActiveConnectionService
|
||||
implements DirectoryObjectService<TrackedActiveConnection, ActiveConnection> {
|
||||
|
||||
/**
|
||||
* Service for creating and tracking tunnels.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleTunnelService tunnelService;
|
||||
|
||||
/**
|
||||
* Provider for active connections.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<TrackedActiveConnection> trackedActiveConnectionProvider;
|
||||
|
||||
@Override
|
||||
public TrackedActiveConnection retrieveObject(ModeledAuthenticatedUser user,
|
||||
String identifier) throws GuacamoleException {
|
||||
|
||||
// Pull objects having given identifier
|
||||
Collection<TrackedActiveConnection> objects = retrieveObjects(user, Collections.singleton(identifier));
|
||||
|
||||
// If no such object, return null
|
||||
if (objects.isEmpty())
|
||||
return null;
|
||||
|
||||
// The object collection will have exactly one element unless the
|
||||
// database has seriously lost integrity
|
||||
assert(objects.size() == 1);
|
||||
|
||||
// Return first and only object
|
||||
return objects.iterator().next();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<TrackedActiveConnection> retrieveObjects(ModeledAuthenticatedUser user,
|
||||
Collection<String> identifiers) throws GuacamoleException {
|
||||
|
||||
String username = user.getIdentifier();
|
||||
boolean isPrivileged = user.isPrivileged();
|
||||
Set<String> identifierSet = new HashSet<String>(identifiers);
|
||||
|
||||
// Retrieve all visible connections (permissions enforced by tunnel service)
|
||||
Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
|
||||
|
||||
// Restrict to subset of records which match given identifiers
|
||||
Collection<TrackedActiveConnection> activeConnections = new ArrayList<TrackedActiveConnection>(identifiers.size());
|
||||
for (ActiveConnectionRecord record : records) {
|
||||
|
||||
// The current user should have access to sensitive information and
|
||||
// be able to connect to (join) the active connection if they are
|
||||
// the user that started the connection OR the user is an admin
|
||||
boolean hasPrivilegedAccess =
|
||||
isPrivileged || username.equals(record.getUsername());
|
||||
|
||||
// Add connection if within requested identifiers
|
||||
if (identifierSet.contains(record.getUUID().toString())) {
|
||||
TrackedActiveConnection activeConnection = trackedActiveConnectionProvider.get();
|
||||
activeConnection.init(user, record, hasPrivilegedAccess, hasPrivilegedAccess);
|
||||
activeConnections.add(activeConnection);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return activeConnections;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(ModeledAuthenticatedUser user, String identifier)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Close connection, if it exists and we have permission
|
||||
ActiveConnection activeConnection = retrieveObject(user, identifier);
|
||||
if (activeConnection == null)
|
||||
return;
|
||||
|
||||
if (hasObjectPermissions(user, identifier, ObjectPermission.Type.DELETE)) {
|
||||
|
||||
// Close connection if not already closed
|
||||
GuacamoleTunnel tunnel = activeConnection.getTunnel();
|
||||
if (tunnel != null && tunnel.isOpen())
|
||||
tunnel.close();
|
||||
|
||||
}
|
||||
else
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getIdentifiers(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Retrieve all visible connections (permissions enforced by tunnel service)
|
||||
Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
|
||||
|
||||
// Build list of identifiers
|
||||
Set<String> identifiers = new HashSet<String>(records.size());
|
||||
for (ActiveConnectionRecord record : records)
|
||||
identifiers.add(record.getUUID().toString());
|
||||
|
||||
return identifiers;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackedActiveConnection createObject(ModeledAuthenticatedUser user,
|
||||
ActiveConnection object) throws GuacamoleException {
|
||||
|
||||
// Updating active connections is not implemented
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateObject(ModeledAuthenticatedUser user, TrackedActiveConnection object)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Updating active connections is not implemented
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the permission set for the specified user that relates
|
||||
* to access to active connections.
|
||||
*
|
||||
* @param user
|
||||
* The user for which to retrieve the permission set.
|
||||
*
|
||||
* @return
|
||||
* A permission set associated with the given user that specifies
|
||||
* the permissions available for active connection objects.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to read permissions for the user is denied.
|
||||
*/
|
||||
private ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
return user.getUser().getActiveConnectionPermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean value representing whether or not a user has the given
|
||||
* permission available to them on the active connection with the given
|
||||
* identifier.
|
||||
*
|
||||
* @param user
|
||||
* The user for which the permissions are being queried.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the active connection we are wondering about.
|
||||
*
|
||||
* @param type
|
||||
* The type of permission being requested.
|
||||
*
|
||||
* @return
|
||||
* True if the user has the necessary permission; otherwise false.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the user does not have access to read permissions.
|
||||
*/
|
||||
private boolean hasObjectPermissions(ModeledAuthenticatedUser user,
|
||||
String identifier, ObjectPermission.Type type)
|
||||
throws GuacamoleException {
|
||||
|
||||
ObjectPermissionSet permissionSet = getPermissionSet(user);
|
||||
|
||||
return user.isPrivileged()
|
||||
|| permissionSet.hasPermission(type, identifier);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* 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.activeconnection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.connection.SharedConnectionDefinition;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.ActiveConnection;
|
||||
import org.apache.guacamole.net.auth.credentials.UserCredentials;
|
||||
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
/**
|
||||
* An implementation of the ActiveConnection object which has an associated
|
||||
* ActiveConnectionRecord.
|
||||
*/
|
||||
public class TrackedActiveConnection extends RestrictedObject implements ActiveConnection {
|
||||
|
||||
/**
|
||||
* Service for managing shared connections.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionSharingService sharingService;
|
||||
|
||||
/**
|
||||
* Service for creating and tracking tunnels.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleTunnelService tunnelService;
|
||||
|
||||
/**
|
||||
* The identifier of this active connection.
|
||||
*/
|
||||
private String identifier;
|
||||
|
||||
/**
|
||||
* The actual connection record from which this ActiveConnection derives its
|
||||
* data.
|
||||
*/
|
||||
private ActiveConnectionRecord connectionRecord;
|
||||
|
||||
/**
|
||||
* The connection being actively used or shared.
|
||||
*/
|
||||
private ModeledConnection connection;
|
||||
|
||||
/**
|
||||
* The identifier of the associated sharing profile.
|
||||
*/
|
||||
private String sharingProfileIdentifier;
|
||||
|
||||
/**
|
||||
* The date and time this active connection began.
|
||||
*/
|
||||
private Date startDate;
|
||||
|
||||
/**
|
||||
* The remote host that initiated this connection.
|
||||
*/
|
||||
private String remoteHost;
|
||||
|
||||
/**
|
||||
* The username of the user that initiated this connection.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* The underlying GuacamoleTunnel.
|
||||
*/
|
||||
private GuacamoleTunnel tunnel;
|
||||
|
||||
/**
|
||||
* Whether connections to this TrackedActiveConnection are allowed.
|
||||
*/
|
||||
private boolean connectable;
|
||||
|
||||
/**
|
||||
* Initializes this TrackedActiveConnection, copying the data associated
|
||||
* with the given active connection record. At a minimum, the identifier
|
||||
* of this active connection will be set, the start date, and the
|
||||
* identifier of the associated connection will be copied. If requested,
|
||||
* sensitive information like the associated username will be copied, as
|
||||
* well.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user that created or retrieved this object.
|
||||
*
|
||||
* @param activeConnectionRecord
|
||||
* The active connection record to copy.
|
||||
*
|
||||
* @param includeSensitiveInformation
|
||||
* Whether sensitive data should be copied from the connection record
|
||||
* as well. This includes the remote host, associated tunnel, and
|
||||
* username.
|
||||
*
|
||||
* @param connectable
|
||||
* Whether the user that retrieved this object should be allowed to
|
||||
* join the active connection.
|
||||
*/
|
||||
public void init(ModeledAuthenticatedUser currentUser,
|
||||
ActiveConnectionRecord activeConnectionRecord,
|
||||
boolean includeSensitiveInformation,
|
||||
boolean connectable) {
|
||||
|
||||
super.init(currentUser);
|
||||
this.connectionRecord = activeConnectionRecord;
|
||||
this.connectable = connectable;
|
||||
|
||||
// Copy all non-sensitive data from given record
|
||||
this.connection = activeConnectionRecord.getConnection();
|
||||
this.sharingProfileIdentifier = activeConnectionRecord.getSharingProfileIdentifier();
|
||||
this.identifier = activeConnectionRecord.getUUID().toString();
|
||||
this.startDate = activeConnectionRecord.getStartDate();
|
||||
|
||||
// Include sensitive data, too, if requested
|
||||
if (includeSensitiveInformation) {
|
||||
this.remoteHost = activeConnectionRecord.getRemoteHost();
|
||||
this.tunnel = activeConnectionRecord.getTunnel();
|
||||
this.username = activeConnectionRecord.getUsername();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection being actively used. If this active connection is
|
||||
* not the primary connection, this will be the connection being actively
|
||||
* shared.
|
||||
*
|
||||
* @return
|
||||
* The connection being actively used.
|
||||
*/
|
||||
public ModeledConnection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectionIdentifier() {
|
||||
return connection.getIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConnectionIdentifier(String connnectionIdentifier) {
|
||||
throw new UnsupportedOperationException("The connection identifier of "
|
||||
+ "TrackedActiveConnection is inherited from the underlying "
|
||||
+ "connection.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSharingProfileIdentifier() {
|
||||
return sharingProfileIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSharingProfileIdentifier(String sharingProfileIdentifier) {
|
||||
this.sharingProfileIdentifier = sharingProfileIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shares this active connection with the user that retrieved it, returning
|
||||
* a SharedConnectionDefinition that can be used to establish a tunnel to
|
||||
* the shared connection. If provided, access within the shared connection
|
||||
* will be restricted by the sharing profile with the given identifier.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the sharing profile that defines the restrictions
|
||||
* applying to the shared connection, or null if no such restrictions
|
||||
* apply.
|
||||
*
|
||||
* @return
|
||||
* A new SharedConnectionDefinition which can be used to establish a
|
||||
* tunnel to the shared connection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to share this active connection is denied.
|
||||
*/
|
||||
private SharedConnectionDefinition share(String identifier) throws GuacamoleException {
|
||||
return sharingService.shareConnection(getCurrentUser(), connectionRecord, identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserCredentials getSharingCredentials(String identifier)
|
||||
throws GuacamoleException {
|
||||
return sharingService.getSharingCredentials(share(identifier));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getStartDate() {
|
||||
return startDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartDate(Date startDate) {
|
||||
this.startDate = startDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteHost() {
|
||||
return remoteHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoteHost(String remoteHost) {
|
||||
this.remoteHost = remoteHost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleTunnel getTunnel() {
|
||||
return tunnel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTunnel(GuacamoleTunnel tunnel) {
|
||||
this.tunnel = tunnel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectable() {
|
||||
return connectable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleTunnel connect(GuacamoleClientInformation info,
|
||||
Map<String, String> tokens) throws GuacamoleException {
|
||||
|
||||
// Establish connection only if connecting is allowed
|
||||
if (isConnectable())
|
||||
return tunnelService.getGuacamoleTunnel(getCurrentUser(), share(null), info, tokens);
|
||||
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActiveConnections() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes related to currently-active connections.
|
||||
*/
|
||||
package org.apache.guacamole.auth.jdbc.activeconnection;
|
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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.Collection;
|
||||
import java.util.List;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserModel;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Common interface for mapping activity records.
|
||||
*
|
||||
* @param <ModelType>
|
||||
* The type of model object representing the activity records mapped by
|
||||
* this mapper.
|
||||
*/
|
||||
public interface ActivityRecordMapper<ModelType> {
|
||||
|
||||
/**
|
||||
* Inserts the given activity record.
|
||||
*
|
||||
* @param record
|
||||
* The activity record to insert.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The object that contains current configuration for case sensitivity
|
||||
* for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* The number of rows inserted.
|
||||
*/
|
||||
int insert(@Param("record") ModelType record,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Updates the given activity record in the database, assigning an end
|
||||
* date. No column of the existing activity record is updated except for
|
||||
* the end date. If the record does not actually exist, this operation has
|
||||
* no effect.
|
||||
*
|
||||
* @param record
|
||||
* The activity record to update.
|
||||
*
|
||||
* @return
|
||||
* The number of rows updated.
|
||||
*/
|
||||
int updateEndDate(@Param("record") ModelType record);
|
||||
|
||||
/**
|
||||
* Searches for up to <code>limit</code> activity records that contain
|
||||
* the given terms, sorted by the given predicates, regardless of whether
|
||||
* the data they are associated with 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 {@link searchReadable()} instead.
|
||||
*
|
||||
* @param identifier
|
||||
* The optional identifier of the object whose history is being
|
||||
* retrieved, or null if records related to any such object should be
|
||||
* retrieved.
|
||||
*
|
||||
* @param recordIdentifier
|
||||
* The identifier of the specific history record to retrieve, if not
|
||||
* all matching records. Search terms, etc. will still be applied to
|
||||
* the single record.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The object that contains current configuration for case sensitivity
|
||||
* for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* The results of the search performed with the given parameters.
|
||||
*/
|
||||
List<ModelType> search(@Param("identifier") String identifier,
|
||||
@Param("recordIdentifier") String recordIdentifier,
|
||||
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
|
||||
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
|
||||
@Param("limit") int limit,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Searches for up to <code>limit</code> activity 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 {@link search()}
|
||||
* instead.
|
||||
*
|
||||
* @param identifier
|
||||
* The optional identifier of the object whose history is being
|
||||
* retrieved, or null if records related to any such object should be
|
||||
* retrieved.
|
||||
*
|
||||
* @param user
|
||||
* The user whose permissions should determine whether a record is
|
||||
* returned.
|
||||
*
|
||||
* @param recordIdentifier
|
||||
* The identifier of the specific history record to retrieve, if not
|
||||
* all matching records. Search terms, etc. will still be applied to
|
||||
* the single record.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the user. If
|
||||
* no groups are given, only permissions directly granted to the user
|
||||
* will be used.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The object that contains current configuration for case sensitivity
|
||||
* for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* The results of the search performed with the given parameters.
|
||||
*/
|
||||
List<ModelType> searchReadable(@Param("identifier") String identifier,
|
||||
@Param("user") UserModel user,
|
||||
@Param("recordIdentifier") String recordIdentifier,
|
||||
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
|
||||
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
|
||||
@Param("limit") int limit,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* 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.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A search term for querying historical records of arbitrary activities. This
|
||||
* will contain a the search term in string form and, if that string appears to
|
||||
* be a date. a corresponding date range.
|
||||
*/
|
||||
public class ActivityRecordSearchTerm {
|
||||
|
||||
/**
|
||||
* A pattern that can match a year, year and month, or year and month and
|
||||
* day.
|
||||
*/
|
||||
private static final Pattern DATE_PATTERN =
|
||||
Pattern.compile("(\\d+)(?:-(\\d+)?(?:-(\\d+)?)?)?");
|
||||
|
||||
/**
|
||||
* The index of the group within <code>DATE_PATTERN</code> containing the
|
||||
* year number.
|
||||
*/
|
||||
private static final int YEAR_GROUP = 1;
|
||||
|
||||
/**
|
||||
* The index of the group within <code>DATE_PATTERN</code> containing the
|
||||
* month number, if any.
|
||||
*/
|
||||
private static final int MONTH_GROUP = 2;
|
||||
|
||||
/**
|
||||
* The index of the group within <code>DATE_PATTERN</code> containing the
|
||||
* day number, if any.
|
||||
*/
|
||||
private static final int DAY_GROUP = 3;
|
||||
|
||||
/**
|
||||
* The start of the date range for records that should be retrieved, if the
|
||||
* provided search term appears to be a date.
|
||||
*/
|
||||
private final Date startDate;
|
||||
|
||||
/**
|
||||
* The end of the date range for records that should be retrieved, if the
|
||||
* provided search term appears to be a date.
|
||||
*/
|
||||
private final Date endDate;
|
||||
|
||||
/**
|
||||
* The string that should be searched for.
|
||||
*/
|
||||
private final String term;
|
||||
|
||||
/**
|
||||
* Parse the given string as an integer, returning the provided default
|
||||
* value if the string is null.
|
||||
*
|
||||
* @param str
|
||||
* The string to parse as an integer.
|
||||
*
|
||||
* @param defaultValue
|
||||
* The value to return if <code>str</code> is null.
|
||||
*
|
||||
* @return
|
||||
* The parsed value, or the provided default value if <code>str</code>
|
||||
* is null.
|
||||
*/
|
||||
private static int parseInt(String str, int defaultValue) {
|
||||
|
||||
if (str == null)
|
||||
return defaultValue;
|
||||
|
||||
return Integer.parseInt(str);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new calendar representing the last millisecond of the same
|
||||
* year as <code>calendar</code>.
|
||||
*
|
||||
* @param calendar
|
||||
* The calendar defining the year whose end (last millisecond) is to be
|
||||
* returned.
|
||||
*
|
||||
* @return
|
||||
* A new calendar representing the last millisecond of the same year as
|
||||
* <code>calendar</code>.
|
||||
*/
|
||||
private static Calendar getEndOfYear(Calendar calendar) {
|
||||
|
||||
// Get first day of next year
|
||||
Calendar endOfYear = Calendar.getInstance();
|
||||
endOfYear.clear();
|
||||
endOfYear.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
|
||||
|
||||
// Transform into the last millisecond of the given year
|
||||
endOfYear.add(Calendar.MILLISECOND, -1);
|
||||
|
||||
return endOfYear;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new calendar representing the last millisecond of the same
|
||||
* month and year as <code>calendar</code>.
|
||||
*
|
||||
* @param calendar
|
||||
* The calendar defining the month and year whose end (last millisecond)
|
||||
* is to be returned.
|
||||
*
|
||||
* @return
|
||||
* A new calendar representing the last millisecond of the same month
|
||||
* and year as <code>calendar</code>.
|
||||
*/
|
||||
private static Calendar getEndOfMonth(Calendar calendar) {
|
||||
|
||||
// Copy given calender only up to given month
|
||||
Calendar endOfMonth = Calendar.getInstance();
|
||||
endOfMonth.clear();
|
||||
endOfMonth.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
|
||||
endOfMonth.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
|
||||
|
||||
// Advance to the last millisecond of the given month
|
||||
endOfMonth.add(Calendar.MONTH, 1);
|
||||
endOfMonth.add(Calendar.MILLISECOND, -1);
|
||||
|
||||
return endOfMonth;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new calendar representing the last millisecond of the same
|
||||
* year, month, and day as <code>calendar</code>.
|
||||
*
|
||||
* @param calendar
|
||||
* The calendar defining the year, month, and day whose end
|
||||
* (last millisecond) is to be returned.
|
||||
*
|
||||
* @return
|
||||
* A new calendar representing the last millisecond of the same year,
|
||||
* month, and day as <code>calendar</code>.
|
||||
*/
|
||||
private static Calendar getEndOfDay(Calendar calendar) {
|
||||
|
||||
// Copy given calender only up to given month
|
||||
Calendar endOfMonth = Calendar.getInstance();
|
||||
endOfMonth.clear();
|
||||
endOfMonth.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
|
||||
endOfMonth.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
|
||||
endOfMonth.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));
|
||||
|
||||
// Advance to the last millisecond of the given day
|
||||
endOfMonth.add(Calendar.DAY_OF_MONTH, 1);
|
||||
endOfMonth.add(Calendar.MILLISECOND, -1);
|
||||
|
||||
return endOfMonth;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActivityRecordSearchTerm representing the given string.
|
||||
* 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
|
||||
* via getStartDate() and getEndDate() respectively.
|
||||
*
|
||||
* @param term
|
||||
* The string that should be searched for.
|
||||
*/
|
||||
public ActivityRecordSearchTerm(String term) {
|
||||
|
||||
// Search terms absolutely must not be null
|
||||
if (term == null)
|
||||
throw new NullPointerException("Search terms may not be null");
|
||||
|
||||
this.term = term;
|
||||
|
||||
// Parse start/end of date range if term appears to be a date
|
||||
Matcher matcher = DATE_PATTERN.matcher(term);
|
||||
if (matcher.matches()) {
|
||||
|
||||
// Retrieve date components from term
|
||||
String year = matcher.group(YEAR_GROUP);
|
||||
String month = matcher.group(MONTH_GROUP);
|
||||
String day = matcher.group(DAY_GROUP);
|
||||
|
||||
// Parse start date from term
|
||||
Calendar startCalendar = Calendar.getInstance();
|
||||
startCalendar.clear();
|
||||
startCalendar.set(
|
||||
Integer.parseInt(year),
|
||||
parseInt(month, 1) - 1,
|
||||
parseInt(day, 1)
|
||||
);
|
||||
|
||||
Calendar endCalendar;
|
||||
|
||||
// Derive end date from start date
|
||||
if (month == null) {
|
||||
endCalendar = getEndOfYear(startCalendar);
|
||||
}
|
||||
else if (day == null) {
|
||||
endCalendar = getEndOfMonth(startCalendar);
|
||||
}
|
||||
else {
|
||||
endCalendar = getEndOfDay(startCalendar);
|
||||
}
|
||||
|
||||
// Convert results back into dates
|
||||
this.startDate = startCalendar.getTime();
|
||||
this.endDate = endCalendar.getTime();
|
||||
|
||||
}
|
||||
|
||||
// The search term doesn't look like a date
|
||||
else {
|
||||
this.startDate = null;
|
||||
this.endDate = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start of the date range for records that should be retrieved,
|
||||
* if the provided search term appears to be a date.
|
||||
*
|
||||
* @return
|
||||
* The start of the date range.
|
||||
*/
|
||||
public Date getStartDate() {
|
||||
return startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end of the date range for records that should be retrieved,
|
||||
* if the provided search term appears to be a date.
|
||||
*
|
||||
* @return
|
||||
* The end of the date range.
|
||||
*/
|
||||
public Date getEndDate() {
|
||||
return endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string that should be searched for.
|
||||
*
|
||||
* @return
|
||||
* The search term.
|
||||
*/
|
||||
public String getTerm() {
|
||||
return term;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return term.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (obj == null || !(obj instanceof ActivityRecordSearchTerm))
|
||||
return false;
|
||||
|
||||
return ((ActivityRecordSearchTerm) obj).getTerm().equals(getTerm());
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 org.apache.guacamole.net.auth.ActivityRecordSet;
|
||||
|
||||
/**
|
||||
* A sort predicate which species the property to use when sorting activity
|
||||
* records, along with the sort order.
|
||||
*/
|
||||
public class ActivityRecordSortPredicate {
|
||||
|
||||
/**
|
||||
* The property to use when sorting ActivityRecords.
|
||||
*/
|
||||
private final ActivityRecordSet.SortableProperty property;
|
||||
|
||||
/**
|
||||
* Whether the sort order is descending (true) or ascending (false).
|
||||
*/
|
||||
private final boolean descending;
|
||||
|
||||
/**
|
||||
* Creates a new ActivityRecordSortPredicate with the given sort property
|
||||
* and sort order.
|
||||
*
|
||||
* @param property
|
||||
* The property to use when sorting ActivityRecords.
|
||||
*
|
||||
* @param descending
|
||||
* Whether the sort order is descending (true) or ascending (false).
|
||||
*/
|
||||
public ActivityRecordSortPredicate(ActivityRecordSet.SortableProperty property,
|
||||
boolean descending) {
|
||||
this.property = property;
|
||||
this.descending = descending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property that should be used when sorting ActivityRecords.
|
||||
*
|
||||
* @return
|
||||
* The property that should be used when sorting ActivityRecords.
|
||||
*/
|
||||
public ActivityRecordSet.SortableProperty getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the sort order is descending.
|
||||
*
|
||||
* @return
|
||||
* true if the sort order is descending, false if the sort order is
|
||||
* ascending.
|
||||
*/
|
||||
public boolean isDescending() {
|
||||
return descending;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Map of arbitrary attribute name/value pairs which can alternatively be
|
||||
* exposed as a collection of model objects.
|
||||
*/
|
||||
public class ArbitraryAttributeMap extends HashMap<String, String> {
|
||||
|
||||
/**
|
||||
* Creates a new ArbitraryAttributeMap containing the name/value pairs
|
||||
* within the given collection of model objects.
|
||||
*
|
||||
* @param models
|
||||
* The model objects of all attributes which should be stored in the
|
||||
* new map as name/value pairs.
|
||||
*
|
||||
* @return
|
||||
* A new ArbitraryAttributeMap containing the name/value pairs within
|
||||
* the given collection of model objects.
|
||||
*/
|
||||
public static ArbitraryAttributeMap fromModelCollection(Collection<ArbitraryAttributeModel> models) {
|
||||
|
||||
// Add all name/value pairs from the given collection to the map
|
||||
ArbitraryAttributeMap map = new ArbitraryAttributeMap();
|
||||
for (ArbitraryAttributeModel model : models)
|
||||
map.put(model.getName(), model.getValue());
|
||||
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of model objects which mirrors the contents of this
|
||||
* ArbitraryAttributeMap. Each name/value pair within the map is reflected
|
||||
* by a corresponding model object within the returned collection. Removing
|
||||
* a model object from the collection removes the corresponding name/value
|
||||
* pair from the map. Adding a new model object to the collection adds a
|
||||
* corresponding name/value pair to the map. Changes to a model object
|
||||
* within the collection are NOT reflected on the map, however.
|
||||
*
|
||||
* @return
|
||||
* A collection of model objects which mirrors the contents of this
|
||||
* ArbitraryAttributeMap.
|
||||
*/
|
||||
public Collection<ArbitraryAttributeModel> toModelCollection() {
|
||||
return new AbstractCollection<ArbitraryAttributeModel>() {
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
ArbitraryAttributeMap.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
|
||||
// The Collection view of an ArbitraryAttributeMap can contain
|
||||
// only ArbitraryAttributeModel objects
|
||||
if (!(o instanceof ArbitraryAttributeModel))
|
||||
return false;
|
||||
|
||||
// Remove only if key is actually present
|
||||
ArbitraryAttributeModel model = (ArbitraryAttributeModel) o;
|
||||
if (!ArbitraryAttributeMap.this.containsKey(model.getName()))
|
||||
return false;
|
||||
|
||||
// The attribute should be removed only if the value matches
|
||||
String currentValue = ArbitraryAttributeMap.this.get(model.getName());
|
||||
if (currentValue == null) {
|
||||
if (model.getValue() != null)
|
||||
return false;
|
||||
}
|
||||
else if (!currentValue.equals(model.getValue()))
|
||||
return false;
|
||||
|
||||
ArbitraryAttributeMap.this.remove(model.getName());
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(ArbitraryAttributeModel e) {
|
||||
|
||||
String newValue = e.getValue();
|
||||
String oldValue = put(e.getName(), newValue);
|
||||
|
||||
// If null value is being added, collection changed only if
|
||||
// old value was non-null
|
||||
if (newValue == null)
|
||||
return oldValue != null;
|
||||
|
||||
// Collection changed if value changed
|
||||
return !newValue.equals(oldValue);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
|
||||
// The Collection view of an ArbitraryAttributeMap can contain
|
||||
// only ArbitraryAttributeModel objects
|
||||
if (!(o instanceof ArbitraryAttributeModel))
|
||||
return false;
|
||||
|
||||
// No need to check the value of the attribute if the attribute
|
||||
// is not even present
|
||||
ArbitraryAttributeModel model = (ArbitraryAttributeModel) o;
|
||||
String value = get(model.getName());
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// The name/value pair is present only if the value matches
|
||||
return value.equals(model.getValue());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ArbitraryAttributeModel> iterator() {
|
||||
|
||||
// Get iterator over all string name/value entries
|
||||
final Iterator<Map.Entry<String, String>> iterator = entrySet().iterator();
|
||||
|
||||
// Dynamically translate each string name/value entry into a
|
||||
// corresponding attribute model object as iteration continues
|
||||
return new Iterator<ArbitraryAttributeModel>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArbitraryAttributeModel next() {
|
||||
Map.Entry<String, String> entry = iterator.next();
|
||||
return new ArbitraryAttributeModel(entry.getKey(),
|
||||
entry.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return ArbitraryAttributeMap.this.size();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* A single attribute name/value pair belonging to a object which implements
|
||||
* the Attributes interface, such as a Connection or User. Attributes stored
|
||||
* as raw name/value pairs are the attributes which are given to the database
|
||||
* authentication extension for storage by other extensions. Attributes which
|
||||
* are directly supported by the database authentication extension have defined
|
||||
* columns and properties with proper types, constraints, etc.
|
||||
*/
|
||||
public class ArbitraryAttributeModel {
|
||||
|
||||
/**
|
||||
* The name of the attribute.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The value the attribute is set to.
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Creates a new ArbitraryAttributeModel with its name and value both set
|
||||
* to null.
|
||||
*/
|
||||
public ArbitraryAttributeModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ArbitraryAttributeModel with its name and value
|
||||
* initialized to the given values.
|
||||
*
|
||||
* @param name
|
||||
* The name of the attribute.
|
||||
*
|
||||
* @param value
|
||||
* The value the attribute is set to.
|
||||
*/
|
||||
public ArbitraryAttributeModel(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this attribute.
|
||||
*
|
||||
* @return
|
||||
* The name of this attribute.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this attribute.
|
||||
*
|
||||
* @param name
|
||||
* The name of this attribute.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this attribute.
|
||||
*
|
||||
* @return
|
||||
* The value of this attribute.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this attribute.
|
||||
*
|
||||
* @param value
|
||||
* The value of this attribute.
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Object representation of a Guacamole object which can be the child of another
|
||||
* object, such as a connection or sharing profile, as represented in the
|
||||
* database.
|
||||
*/
|
||||
public abstract class ChildObjectModel extends ObjectModel {
|
||||
|
||||
/**
|
||||
* The unique identifier which identifies the parent of this object.
|
||||
*/
|
||||
private String parentIdentifier;
|
||||
|
||||
/**
|
||||
* Creates a new, empty object.
|
||||
*/
|
||||
public ChildObjectModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of the parent connection group, or null if the
|
||||
* parent connection group is the root connection group.
|
||||
*
|
||||
* @return
|
||||
* The identifier of the parent connection group, or null if the parent
|
||||
* connection group is the root connection group.
|
||||
*/
|
||||
public String getParentIdentifier() {
|
||||
return parentIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifier of the parent connection group.
|
||||
*
|
||||
* @param parentIdentifier
|
||||
* The identifier of the parent connection group, or null if the parent
|
||||
* connection group is the root connection group.
|
||||
*/
|
||||
public void setParentIdentifier(String parentIdentifier) {
|
||||
this.parentIdentifier = parentIdentifier;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* manipulating objects that have unique identifiers, such as the objects
|
||||
* within directories. This service will automatically enforce the permissions
|
||||
* of the current user.
|
||||
*
|
||||
* @param <InternalType>
|
||||
* The specific internal implementation of the type of object this service
|
||||
* provides access to.
|
||||
*
|
||||
* @param <ExternalType>
|
||||
* The external interface or implementation of the type of object this
|
||||
* service provides access to, as defined by the guacamole-ext API.
|
||||
*/
|
||||
public interface DirectoryObjectService<InternalType, ExternalType> {
|
||||
|
||||
/**
|
||||
* Retrieves the single object that has the given identifier, if it exists
|
||||
* and the user has permission to read it.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the object.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the object to retrieve.
|
||||
*
|
||||
* @return
|
||||
* The object having the given identifier, or null if no such object
|
||||
* exists.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the requested object.
|
||||
*/
|
||||
InternalType retrieveObject(ModeledAuthenticatedUser user, String identifier)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Retrieves all objects that have the identifiers in the given collection.
|
||||
* Only objects that the user has permission to read will be returned.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the objects.
|
||||
*
|
||||
* @param identifiers
|
||||
* The identifiers of the objects to retrieve.
|
||||
*
|
||||
* @return
|
||||
* The objects having the given identifiers.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the requested objects.
|
||||
*/
|
||||
Collection<InternalType> retrieveObjects(ModeledAuthenticatedUser user,
|
||||
Collection<String> identifiers) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Creates the given object. If the object already exists, an error will be
|
||||
* thrown.
|
||||
*
|
||||
* @param user
|
||||
* The user creating the object.
|
||||
*
|
||||
* @param object
|
||||
* The object to create.
|
||||
*
|
||||
* @return
|
||||
* The newly-created object.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the user lacks permission to create the object, or an error
|
||||
* occurs while creating the object.
|
||||
*/
|
||||
InternalType createObject(ModeledAuthenticatedUser user, ExternalType object)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Deletes the object having the given identifier. If no such object
|
||||
* exists, this function has no effect.
|
||||
*
|
||||
* @param user
|
||||
* The user deleting the object.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the object to delete.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the user lacks permission to delete the object, or an error
|
||||
* occurs while deleting the object.
|
||||
*/
|
||||
void deleteObject(ModeledAuthenticatedUser user, String identifier)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Updates the given object, applying any changes that have been made. If
|
||||
* no such object exists, this function has no effect.
|
||||
*
|
||||
* @param user
|
||||
* The user updating the object.
|
||||
*
|
||||
* @param object
|
||||
* The object to update.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the user lacks permission to update the object, or an error
|
||||
* occurs while updating the object.
|
||||
*/
|
||||
void updateObject(ModeledAuthenticatedUser user, InternalType object)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the set of all identifiers for all objects that the user has
|
||||
* read access to.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the identifiers.
|
||||
*
|
||||
* @return
|
||||
* The set of all identifiers for all objects.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while reading identifiers.
|
||||
*/
|
||||
Set<String> getIdentifiers(ModeledAuthenticatedUser user) throws GuacamoleException;
|
||||
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Mapper for entities. An entity is the base concept behind a user or user
|
||||
* group, and serves as a common point for granting permissions and defining
|
||||
* group membership.
|
||||
*/
|
||||
public interface EntityMapper {
|
||||
|
||||
/**
|
||||
* Inserts the given entity into the database. If the entity already
|
||||
* exists, this will result in an error.
|
||||
*
|
||||
* @param entity
|
||||
* The entity to insert.
|
||||
*
|
||||
* @return
|
||||
* The number of rows inserted.
|
||||
*/
|
||||
int insert(@Param("entity") EntityModel entity);
|
||||
|
||||
/**
|
||||
* Returns the set of all group identifiers of which the given entity is a
|
||||
* member, taking into account the given collection of known group
|
||||
* memberships which are not necessarily defined within the database.
|
||||
*
|
||||
* NOTE: This query is expected to handle recursion through the membership
|
||||
* graph on its own. If the database engine does not support recursive
|
||||
* queries (isRecursiveQuerySupported() of JDBCEnvironment returns false),
|
||||
* then this query will only return one level of depth past the effective
|
||||
* groups given and will need to be invoked multiple times.
|
||||
*
|
||||
* @param entity
|
||||
* The entity whose effective groups should be returned.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of any known effective groups that should be taken
|
||||
* into account, such as those defined externally to the database.
|
||||
*
|
||||
* @param recursive
|
||||
* Whether the query should leverage database engine features to return
|
||||
* absolutely all effective groups, including those inherited through
|
||||
* group membership. If false, this query will return only one level of
|
||||
* depth and may need to be executed multiple times. If it is known
|
||||
* that the database engine in question will always support (or always
|
||||
* not support) recursive queries, this parameter may be ignored.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The object that contains current configuration for case sensitivity
|
||||
* for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* The set of identifiers of all groups that the given entity is a
|
||||
* member of, including those where membership is inherited through
|
||||
* membership in other groups.
|
||||
*/
|
||||
Set<String> selectEffectiveGroupIdentifiers(@Param("entity") EntityModel entity,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("recursive") boolean recursive,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Base representation of a Guacamole object that can be granted permissions
|
||||
* (an "entity"), such as a user or user group, as represented in the database.
|
||||
* Each entity has three base properties:
|
||||
*
|
||||
* 1. The "entityID", which points to the common entry in the
|
||||
* guacamole_entity table and is common to any type of entity.
|
||||
*
|
||||
* 2. The "objectID", which points to the type-specific entry for the object
|
||||
* in question (ie: an entry in guacamole_user or guacamole_user_group).
|
||||
*
|
||||
* 3. The "identifier", which contains the unique "name" value defined for
|
||||
* the entity within the guacamole_entity table.
|
||||
*/
|
||||
public abstract class EntityModel extends ObjectModel {
|
||||
|
||||
/**
|
||||
* The ID of the entity entry which corresponds to this object in the
|
||||
* database, if any. Note that this is distinct from the objectID,
|
||||
* inherited from ObjectModel, which is specific to the actual type of
|
||||
* object represented by the entity.
|
||||
*/
|
||||
private Integer entityID;
|
||||
|
||||
/**
|
||||
* The type of object represented by the entity (user or user group).
|
||||
*/
|
||||
private EntityType type;
|
||||
|
||||
/**
|
||||
* Creates a new, empty entity.
|
||||
*/
|
||||
public EntityModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new entity of the given type which is otherwise empty.
|
||||
*
|
||||
* @param type
|
||||
* The type to assign to the new entity.
|
||||
*/
|
||||
public EntityModel(EntityType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the entity entry which corresponds to this object in
|
||||
* the database, if it exists. Note that this is distinct from the objectID,
|
||||
* inherited from ObjectModel, which is specific to the actual type of
|
||||
* object represented by the entity.
|
||||
*
|
||||
* @return
|
||||
* The ID of this entity in the database, or null if this entity was
|
||||
* not retrieved from the database.
|
||||
*/
|
||||
public Integer getEntityID() {
|
||||
return entityID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID of this entity to the given value.
|
||||
*
|
||||
* @param entityID
|
||||
* The ID to assign to this entity.
|
||||
*/
|
||||
public void setEntityID(Integer entityID) {
|
||||
this.entityID = entityID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of object represented by the entity. Each entity may be
|
||||
* either a user or a user group.
|
||||
*
|
||||
* @return
|
||||
* The type of object represented by the entity.
|
||||
*/
|
||||
public EntityType getEntityType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of object represented by the entity. Each entity may be
|
||||
* either a user or a user group.
|
||||
*
|
||||
* @param type
|
||||
* The type of object represented by the entity.
|
||||
*/
|
||||
public void setEntityType(EntityType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 com.google.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.mybatis.guice.transactional.Transactional;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* manipulating entities.
|
||||
*/
|
||||
public class EntityService {
|
||||
|
||||
/**
|
||||
* The Guacamole server environment.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Mapper for Entity model objects.
|
||||
*/
|
||||
@Inject
|
||||
private EntityMapper entityMapper;
|
||||
|
||||
/**
|
||||
* The current SQL session used by MyBatis.
|
||||
*/
|
||||
@Inject
|
||||
private SqlSession sqlSession;
|
||||
|
||||
/**
|
||||
* Returns the set of all group identifiers of which the given entity is a
|
||||
* member, taking into account the given collection of known group
|
||||
* memberships which are not necessarily defined within the database.
|
||||
*
|
||||
* Note that group visibility with respect to the queried entity is NOT
|
||||
* taken into account. If the entity is a member of a group, the identifier
|
||||
* of that group will be included in the returned set even if the current
|
||||
* user lacks "READ" permission for that group.
|
||||
*
|
||||
* @param entity
|
||||
* The entity whose effective groups should be returned.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of any known effective groups that should be taken
|
||||
* into account, such as those defined externally to the database.
|
||||
*
|
||||
* @return
|
||||
* The set of identifiers of all groups that the given entity is a
|
||||
* member of, including those where membership is inherited through
|
||||
* membership in other groups.
|
||||
*/
|
||||
@Transactional
|
||||
public Set<String> retrieveEffectiveGroups(ModeledPermissions<? extends EntityModel> entity,
|
||||
Collection<String> effectiveGroups) {
|
||||
|
||||
CaseSensitivity caseSensitivity = environment.getCaseSensitivity();
|
||||
|
||||
// Retrieve the effective user groups of the given entity, recursively if possible
|
||||
boolean recursive = environment.isRecursiveQuerySupported(sqlSession);
|
||||
Set<String> identifiers = entityMapper.selectEffectiveGroupIdentifiers(
|
||||
entity.getModel(), effectiveGroups, recursive, caseSensitivity);
|
||||
|
||||
// If the set of user groups retrieved was not produced recursively,
|
||||
// manually repeat the query to expand the set until all effective
|
||||
// groups have been found
|
||||
if (!recursive && !identifiers.isEmpty()) {
|
||||
Set<String> previousIdentifiers;
|
||||
do {
|
||||
previousIdentifiers = identifiers;
|
||||
identifiers = entityMapper.selectEffectiveGroupIdentifiers(
|
||||
entity.getModel(), previousIdentifiers, false,
|
||||
caseSensitivity);
|
||||
} while (identifiers.size() > previousIdentifiers.size());
|
||||
}
|
||||
|
||||
return identifiers;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The type of object represented by an entity. Each entity may represent
|
||||
* either a user or a user group.
|
||||
*/
|
||||
public enum EntityType {
|
||||
|
||||
/**
|
||||
* An individual user.
|
||||
*/
|
||||
USER,
|
||||
|
||||
/**
|
||||
* A group of users and/or other groups.
|
||||
*/
|
||||
USER_GROUP
|
||||
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.net.auth.AtomicDirectoryOperation;
|
||||
import org.apache.guacamole.net.auth.Directory;
|
||||
import org.apache.guacamole.net.auth.Identifiable;
|
||||
import org.mybatis.guice.transactional.Transactional;
|
||||
|
||||
/**
|
||||
* An implementation of Directory that uses database transactions to guarantee
|
||||
* atomicity for any operations supplied to tryAtomically().
|
||||
*/
|
||||
public abstract class JDBCDirectory<ObjectType extends Identifiable>
|
||||
extends RestrictedObject implements Directory<ObjectType> {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void tryAtomically(AtomicDirectoryOperation<ObjectType> operation)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Execute the operation atomically - the @Transactional annotation
|
||||
// specifies that the entire operation will be performed in a transaction
|
||||
operation.executeOperation(true, this);
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.nio.ByteBuffer;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
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;
|
||||
|
||||
/**
|
||||
* The UUID namespace of the type 3 name UUID to generate for the record.
|
||||
* This namespace should correspond to the source of IDs for the model such
|
||||
* that the combination of this namespace with the numeric record ID will
|
||||
* always be unique and deterministic across all activity records,
|
||||
* regardless of record type.
|
||||
*/
|
||||
private final UUID namespace;
|
||||
|
||||
/**
|
||||
* 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 namespace
|
||||
* The UUID namespace of the type 3 name UUID to generate for the
|
||||
* record. This namespace should correspond to the source of IDs for
|
||||
* the model such that the combination of this namespace with the
|
||||
* numeric record ID will always be unique and deterministic across all
|
||||
* activity records, regardless of record type.
|
||||
*
|
||||
* @param model
|
||||
* The model object to use to back this activity record.
|
||||
*/
|
||||
public ModeledActivityRecord(UUID namespace, ActivityRecordModel model) {
|
||||
this.model = model;
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the backing model object. Changes to this record will affect the
|
||||
* backing model object, and changes to the backing model object will
|
||||
* affect this record.
|
||||
*
|
||||
* @return
|
||||
* The backing model object.
|
||||
*/
|
||||
public ActivityRecordModel getModel() {
|
||||
return 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
|
||||
Integer id = model.getRecordID();
|
||||
if (id == null)
|
||||
return null;
|
||||
|
||||
return id.toString();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
|
||||
Integer id = model.getRecordID();
|
||||
if (id == null)
|
||||
return null;
|
||||
|
||||
// Convert record ID to a name UUID in the given namespace
|
||||
return UUID.nameUUIDFromBytes(ByteBuffer.allocate(24)
|
||||
.putLong(namespace.getMostSignificantBits())
|
||||
.putLong(namespace.getLeastSignificantBits())
|
||||
.putLong(id)
|
||||
.array());
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 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> {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(ModeledActivityRecordSet.class);
|
||||
|
||||
/**
|
||||
* 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<>();
|
||||
|
||||
/**
|
||||
* 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<>();
|
||||
|
||||
/**
|
||||
* 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 recordIdentifier
|
||||
* The identifier of the specific history record to retrieve, if not
|
||||
* all matching records. Search terms, etc. will still be applied to
|
||||
* the single record.
|
||||
*
|
||||
* @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 List<RecordType> retrieveHistory(
|
||||
AuthenticatedUser user, String recordIdentifier,
|
||||
Set<ActivityRecordSearchTerm> requiredContents,
|
||||
List<ActivityRecordSortPredicate> sortPredicates,
|
||||
int limit) throws GuacamoleException;
|
||||
|
||||
@Override
|
||||
public RecordType get(String identifier) throws GuacamoleException {
|
||||
|
||||
List<RecordType> records = retrieveHistory(getCurrentUser(),
|
||||
identifier, requiredContents, sortPredicates, limit);
|
||||
|
||||
if (records.isEmpty())
|
||||
return null;
|
||||
|
||||
if (records.size() == 1)
|
||||
return records.get(0);
|
||||
|
||||
logger.warn("Multiple history records match ID \"{}\"! This should "
|
||||
+ "not be possible and may indicate a bug or database "
|
||||
+ "corruption.", identifier);
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RecordType> asCollection()
|
||||
throws GuacamoleException {
|
||||
return retrieveHistory(getCurrentUser(), null, 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 org.apache.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup;
|
||||
|
||||
/**
|
||||
* Common base class for objects that will ultimately be made available through
|
||||
* the Directory class. All such objects will need the same base set of queries
|
||||
* to fulfill the needs of the Directory class.
|
||||
*
|
||||
* @param <ModelType>
|
||||
* The type of model object that corresponds to this object.
|
||||
*/
|
||||
public abstract class ModeledChildDirectoryObject<ModelType extends ChildObjectModel>
|
||||
extends ModeledDirectoryObject<ModelType> {
|
||||
|
||||
/**
|
||||
* Returns the identifier of the parent connection group, which cannot be
|
||||
* null. If the parent is the root connection group, this will be
|
||||
* RootConnectionGroup.IDENTIFIER.
|
||||
*
|
||||
* @return
|
||||
* The identifier of the parent connection group.
|
||||
*/
|
||||
public String getParentIdentifier() {
|
||||
|
||||
// Translate null parent to proper identifier
|
||||
String parentIdentifier = getModel().getParentIdentifier();
|
||||
if (parentIdentifier == null)
|
||||
return RootConnectionGroup.IDENTIFIER;
|
||||
|
||||
return parentIdentifier;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifier of the associated parent connection group. If the
|
||||
* parent is the root connection group, this should be
|
||||
* RootConnectionGroup.IDENTIFIER.
|
||||
*
|
||||
* @param parentIdentifier
|
||||
* The identifier of the connection group to associate as this object's
|
||||
* parent.
|
||||
*/
|
||||
public void setParentIdentifier(String parentIdentifier) {
|
||||
|
||||
// Translate root identifier back into null
|
||||
if (parentIdentifier != null
|
||||
&& parentIdentifier.equals(RootConnectionGroup.IDENTIFIER))
|
||||
parentIdentifier = null;
|
||||
|
||||
getModel().setParentIdentifier(parentIdentifier);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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.Collections;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.Identifiable;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* manipulating objects that can be children of other objects. This service will
|
||||
* automatically enforce the permissions of the current user.
|
||||
*
|
||||
* @param <InternalType>
|
||||
* The specific internal implementation of the type of object this service
|
||||
* provides access to.
|
||||
*
|
||||
* @param <ExternalType>
|
||||
* The external interface or implementation of the type of object this
|
||||
* service provides access to, as defined by the guacamole-ext API.
|
||||
*
|
||||
* @param <ModelType>
|
||||
* The underlying model object used to represent InternalType in the
|
||||
* database.
|
||||
*/
|
||||
public abstract class ModeledChildDirectoryObjectService<InternalType extends ModeledChildDirectoryObject<ModelType>,
|
||||
ExternalType extends Identifiable, ModelType extends ChildObjectModel>
|
||||
extends ModeledDirectoryObjectService<InternalType, ExternalType, ModelType> {
|
||||
|
||||
/**
|
||||
* Returns the permission set associated with the given user and related
|
||||
* to the type of objects which can be parents of the child objects handled
|
||||
* by this directory object service, taking into account permission
|
||||
* inheritance via user groups.
|
||||
*
|
||||
* @param user
|
||||
* The user whose permissions are being retrieved.
|
||||
*
|
||||
* @return
|
||||
* A permission set which contains the permissions associated with the
|
||||
* given user and related to the type of objects which can be parents
|
||||
* of the child objects handled by this directory object service.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to read the user's permissions is denied.
|
||||
*/
|
||||
protected abstract ObjectPermissionSet getParentEffectivePermissionSet(
|
||||
ModeledAuthenticatedUser user) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the set of parent objects that are modified by the given model
|
||||
* object (by virtue of the object changing parents). If the model is not
|
||||
* changing parents, the resulting collection will be empty.
|
||||
*
|
||||
* @param user
|
||||
* The user making the given changes to the model.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the object that has been modified, if it exists.
|
||||
* If the object is being created, this will be null.
|
||||
*
|
||||
* @param model
|
||||
* The model that has been modified, if any. If the object is being
|
||||
* deleted, this will be null.
|
||||
*
|
||||
* @return
|
||||
* A collection of the identifiers of all parents that will be affected
|
||||
* (updated) by the change.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while determining which parents are affected.
|
||||
*/
|
||||
protected Collection<String> getModifiedParents(ModeledAuthenticatedUser user,
|
||||
String identifier, ModelType model) throws GuacamoleException {
|
||||
|
||||
// Get old parent identifier
|
||||
String oldParentIdentifier = null;
|
||||
if (identifier != null) {
|
||||
ModelType current = retrieveObject(user, identifier).getModel();
|
||||
oldParentIdentifier = current.getParentIdentifier();
|
||||
}
|
||||
|
||||
// Get new parent identifier
|
||||
String parentIdentifier = null;
|
||||
if (model != null) {
|
||||
|
||||
parentIdentifier = model.getParentIdentifier();
|
||||
|
||||
// If both parents have the same identifier, nothing has changed
|
||||
if (parentIdentifier != null && parentIdentifier.equals(oldParentIdentifier))
|
||||
return Collections.<String>emptyList();
|
||||
|
||||
}
|
||||
|
||||
// Return collection of all non-root parents involved
|
||||
Collection<String> parents = new ArrayList<String>(2);
|
||||
if (oldParentIdentifier != null) parents.add(oldParentIdentifier);
|
||||
if (parentIdentifier != null) parents.add(parentIdentifier);
|
||||
return parents;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given user has permission to modify the parents
|
||||
* affected by the modifications made to the given model object.
|
||||
*
|
||||
* @param user
|
||||
* The user who changed the model object.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the object that has been modified, if it exists.
|
||||
* If the object is being created, this will be null.
|
||||
*
|
||||
* @param model
|
||||
* The model that has been modified, if any. If the object is being
|
||||
* deleted, this will be null.
|
||||
*
|
||||
* @return
|
||||
* true if the user has update permission for all modified parents,
|
||||
* false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while determining which parents are affected.
|
||||
*/
|
||||
protected boolean canUpdateModifiedParents(ModeledAuthenticatedUser user,
|
||||
String identifier, ModelType model) throws GuacamoleException {
|
||||
|
||||
// If user is privileged, no need to check
|
||||
if (user.isPrivileged())
|
||||
return true;
|
||||
|
||||
// Verify that we have permission to modify any modified parents
|
||||
Collection<String> modifiedParents = getModifiedParents(user, identifier, model);
|
||||
if (!modifiedParents.isEmpty()) {
|
||||
|
||||
ObjectPermissionSet permissionSet = getParentEffectivePermissionSet(user);
|
||||
Collection<String> updateableParents = permissionSet.getAccessibleObjects(
|
||||
Collections.singleton(ObjectPermission.Type.UPDATE),
|
||||
modifiedParents
|
||||
);
|
||||
|
||||
return updateableParents.size() == modifiedParents.size();
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user,
|
||||
ExternalType object, ModelType model) throws GuacamoleException {
|
||||
|
||||
super.beforeCreate(user, object, model);
|
||||
|
||||
// Validate that we can update all applicable parents
|
||||
if (!canUpdateModifiedParents(user, null, model))
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
InternalType object, ModelType model) throws GuacamoleException {
|
||||
|
||||
super.beforeUpdate(user, object, model);
|
||||
|
||||
// Validate that we can update all applicable parents
|
||||
if (!canUpdateModifiedParents(user, model.getIdentifier(), model))
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeDelete(ModeledAuthenticatedUser user,
|
||||
String identifier) throws GuacamoleException {
|
||||
|
||||
super.beforeDelete(user, identifier);
|
||||
|
||||
// Validate that we can update all applicable parents
|
||||
if (!canUpdateModifiedParents(user, identifier, null))
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.net.auth.Attributes;
|
||||
import org.apache.guacamole.net.auth.Identifiable;
|
||||
|
||||
/**
|
||||
* Common base class for objects that will ultimately be made available through
|
||||
* the Directory class and are persisted to an underlying database model. All
|
||||
* such objects will need the same base set of queries to fulfill the needs of
|
||||
* the Directory class.
|
||||
*
|
||||
* @param <ModelType>
|
||||
* The type of model object that corresponds to this object.
|
||||
*/
|
||||
public abstract class ModeledDirectoryObject<ModelType extends ObjectModel>
|
||||
extends ModeledObject<ModelType> implements Identifiable, Attributes {
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return getModel().getIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(String identifier) {
|
||||
getModel().setIdentifier(identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of all attributes explicitly supported by this object.
|
||||
* Attributes named here have associated mappings within the backing model
|
||||
* object, and thus should not be included in the arbitrary attribute
|
||||
* storage. Any attributes set which do not match these names, such as those
|
||||
* set via other extensions, will be added to arbitrary attribute storage.
|
||||
*
|
||||
* @return
|
||||
* A read-only Set of the names of all attributes explicitly supported
|
||||
* (mapped to a property of the backing model) by this object.
|
||||
*/
|
||||
public Set<String> getSupportedAttributeNames() {
|
||||
return Collections.<String>emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
return new HashMap<String, String>(getModel().getArbitraryAttributeMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttributes(Map<String, String> attributes) {
|
||||
|
||||
ArbitraryAttributeMap arbitraryAttributes = getModel().getArbitraryAttributeMap();
|
||||
|
||||
// Get set of all supported attribute names
|
||||
Set<String> supportedAttributes = getSupportedAttributeNames();
|
||||
|
||||
// Store remaining attributes only if not directly mapped to model
|
||||
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
|
||||
|
||||
String name = attribute.getKey();
|
||||
String value = attribute.getValue();
|
||||
|
||||
// Handle null attributes as explicit removal of that attribute,
|
||||
// as the underlying model cannot store null attribute values
|
||||
if (!supportedAttributes.contains(name)) {
|
||||
if (value == null)
|
||||
arbitraryAttributes.remove(name);
|
||||
else
|
||||
arbitraryAttributes.put(name, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserModel;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Common interface for objects that will ultimately be made available through
|
||||
* the Directory class. All such objects will need the same base set of queries
|
||||
* to fulfill the needs of the Directory class.
|
||||
*
|
||||
* @param <ModelType>
|
||||
* The type of object contained within the directory whose objects are
|
||||
* mapped by this mapper.
|
||||
*/
|
||||
public interface ModeledDirectoryObjectMapper<ModelType> {
|
||||
|
||||
/**
|
||||
* Selects the identifiers of all objects, regardless of whether they
|
||||
* are readable by any particular user. This should only be called on
|
||||
* behalf of a system administrator. If identifiers are needed by a non-
|
||||
* administrative user who must have explicit read rights, use
|
||||
* selectReadableIdentifiers() instead.
|
||||
*
|
||||
* @return
|
||||
* A Set containing all identifiers of all objects.
|
||||
*/
|
||||
Set<String> selectIdentifiers();
|
||||
|
||||
/**
|
||||
* Selects the identifiers of all objects that are explicitly readable by
|
||||
* the given user. If identifiers are needed by a system administrator
|
||||
* (who, by definition, does not need explicit read rights), use
|
||||
* selectIdentifiers() instead.
|
||||
*
|
||||
* @param user
|
||||
* The user whose permissions should determine whether an identifier
|
||||
* is returned.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of any known effective groups that should be taken
|
||||
* into account, such as those defined externally to the database.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The object that contains current configuration for case sensitivity
|
||||
* for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* A Set containing all identifiers of all readable objects.
|
||||
*/
|
||||
Set<String> selectReadableIdentifiers(@Param("user") UserModel user,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Selects all objects which have the given identifiers. If an identifier
|
||||
* has no corresponding object, it will be ignored. This should only be
|
||||
* called on behalf of a system administrator. If objects are needed by a
|
||||
* non-administrative user who must have explicit read rights, use
|
||||
* selectReadable() instead.
|
||||
*
|
||||
* @param identifiers
|
||||
* The identifiers of the objects to return.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The object that contains current configuration for case sensitivity
|
||||
* for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* A Collection of all objects having the given identifiers.
|
||||
*/
|
||||
Collection<ModelType> select(@Param("identifiers") Collection<String> identifiers,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Selects all objects which have the given identifiers and are explicitly
|
||||
* readably by the given user. If an identifier has no corresponding
|
||||
* object, or the corresponding object is unreadable, it will be ignored.
|
||||
* If objects are needed by a system administrator (who, by definition,
|
||||
* does not need explicit read rights), use select() instead.
|
||||
*
|
||||
* @param user
|
||||
* The user whose permissions should determine whether an object
|
||||
* is returned.
|
||||
*
|
||||
* @param identifiers
|
||||
* The identifiers of the objects to return.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of any known effective groups that should be taken
|
||||
* into account, such as those defined externally to the database.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The object that contains current configuration for case sensitivity
|
||||
* for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* A Collection of all objects having the given identifiers.
|
||||
*/
|
||||
Collection<ModelType> selectReadable(@Param("user") UserModel user,
|
||||
@Param("identifiers") Collection<String> identifiers,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Inserts the given object into the database. If the object already
|
||||
* exists, this will result in an error.
|
||||
*
|
||||
* @param object
|
||||
* The object to insert.
|
||||
*
|
||||
* @return
|
||||
* The number of rows inserted.
|
||||
*/
|
||||
int insert(@Param("object") ModelType object);
|
||||
|
||||
/**
|
||||
* Deletes the given object into the database. If the object does not
|
||||
* exist, this operation has no effect.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the object to delete.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The case sensitivity configuration that contains information on
|
||||
* whether usernames and/or group names will be treated as case-sensitive.
|
||||
*
|
||||
* @return
|
||||
* The number of rows deleted.
|
||||
*/
|
||||
int delete(@Param("identifier") String identifier,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Updates the given existing object in the database. If the object does
|
||||
* not actually exist, this operation has no effect.
|
||||
*
|
||||
* @param object
|
||||
* The object to update.
|
||||
*
|
||||
* @return
|
||||
* The number of rows updated.
|
||||
*/
|
||||
int update(@Param("object") ModelType object);
|
||||
|
||||
/**
|
||||
* Deletes any arbitrary attributes currently associated with the given
|
||||
* object in the database.
|
||||
*
|
||||
* @param object
|
||||
* The object whose arbitrary attributes should be deleted.
|
||||
*
|
||||
* @return
|
||||
* The number of rows deleted.
|
||||
*/
|
||||
int deleteAttributes(@Param("object") ModelType object);
|
||||
|
||||
/**
|
||||
* Inserts all arbitrary attributes associated with the given object.
|
||||
*
|
||||
* @param object
|
||||
* The object whose arbitrary attributes should be inserted.
|
||||
*
|
||||
* @return
|
||||
* The number of rows inserted.
|
||||
*/
|
||||
int insertAttributes(@Param("object") ModelType object);
|
||||
|
||||
}
|
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* 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 com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserModel;
|
||||
import org.apache.guacamole.net.auth.Identifiable;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.mybatis.guice.transactional.Transactional;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* manipulating objects within directories. This service will automatically
|
||||
* enforce the permissions of the current user.
|
||||
*
|
||||
* @param <InternalType>
|
||||
* The specific internal implementation of the type of object this service
|
||||
* provides access to.
|
||||
*
|
||||
* @param <ExternalType>
|
||||
* The external interface or implementation of the type of object this
|
||||
* service provides access to, as defined by the guacamole-ext API.
|
||||
*
|
||||
* @param <ModelType>
|
||||
* The underlying model object used to represent InternalType in the
|
||||
* database.
|
||||
*/
|
||||
public abstract class ModeledDirectoryObjectService<InternalType extends ModeledDirectoryObject<ModelType>,
|
||||
ExternalType extends Identifiable, ModelType extends ObjectModel>
|
||||
implements DirectoryObjectService<InternalType, ExternalType> {
|
||||
|
||||
/**
|
||||
* All object permissions which are implicitly granted upon creation to the
|
||||
* creator of the object.
|
||||
*/
|
||||
private static final ObjectPermission.Type[] IMPLICIT_OBJECT_PERMISSIONS = {
|
||||
ObjectPermission.Type.READ,
|
||||
ObjectPermission.Type.UPDATE,
|
||||
ObjectPermission.Type.DELETE,
|
||||
ObjectPermission.Type.ADMINISTER
|
||||
};
|
||||
|
||||
/**
|
||||
* The environment of the Guacamole server.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Returns an instance of a mapper for the type of object used by this
|
||||
* service.
|
||||
*
|
||||
* @return
|
||||
* A mapper which provides access to the model objects associated with
|
||||
* the objects used by this service.
|
||||
*/
|
||||
protected abstract ModeledDirectoryObjectMapper<ModelType> getObjectMapper();
|
||||
|
||||
/**
|
||||
* Returns an instance of a mapper for the type of permissions that affect
|
||||
* the type of object used by this service.
|
||||
*
|
||||
* @return
|
||||
* A mapper which provides access to the model objects associated with
|
||||
* the permissions that affect the objects used by this service.
|
||||
*/
|
||||
protected abstract ObjectPermissionMapper getPermissionMapper();
|
||||
|
||||
/**
|
||||
* Returns an instance of an object which is backed by the given model
|
||||
* object.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user for whom this object is being created.
|
||||
*
|
||||
* @param model
|
||||
* The model object to use to back the returned object.
|
||||
*
|
||||
* @return
|
||||
* An object which is backed by the given model object.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the object instance cannot be created.
|
||||
*/
|
||||
protected abstract InternalType getObjectInstance(ModeledAuthenticatedUser currentUser,
|
||||
ModelType model) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the case sensitivity configuration for this service, which will
|
||||
* be used to determine whether usernames and/or group names will be treated
|
||||
* as case-sensitive.
|
||||
*
|
||||
* @return
|
||||
* The case sensitivity configuration for this service.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs retrieving relevant configuration information.
|
||||
*/
|
||||
protected CaseSensitivity getCaseSensitivity() throws GuacamoleException {
|
||||
|
||||
// Retrieve the Guacamole setting.
|
||||
return environment.getCaseSensitivity();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of a model object which is based on the given
|
||||
* object.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user for whom this model object is being created.
|
||||
*
|
||||
* @param object
|
||||
* The object to use to produce the returned model object.
|
||||
*
|
||||
* @return
|
||||
* A model object which is based on the given object.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the model object instance cannot be created.
|
||||
*/
|
||||
protected abstract ModelType getModelInstance(ModeledAuthenticatedUser currentUser,
|
||||
ExternalType object) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns whether the given user has permission to create the type of
|
||||
* objects that this directory object service manages, taking into account
|
||||
* permission inheritance through user groups.
|
||||
*
|
||||
* @param user
|
||||
* The user being checked.
|
||||
*
|
||||
* @return
|
||||
* true if the user has object creation permission relevant to this
|
||||
* directory object service, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to read the user's permissions is denied.
|
||||
*/
|
||||
protected abstract boolean hasCreatePermission(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns whether the given user has permission to perform a certain
|
||||
* action on a specific object managed by this directory object service,
|
||||
* taking into account permission inheritance through user groups.
|
||||
*
|
||||
* @param user
|
||||
* The user being checked.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the object to check.
|
||||
*
|
||||
* @param type
|
||||
* The type of action that will be performed.
|
||||
*
|
||||
* @return
|
||||
* true if the user has object permission relevant described, false
|
||||
* otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to read the user's permissions is denied.
|
||||
*/
|
||||
protected boolean hasObjectPermission(ModeledAuthenticatedUser user,
|
||||
String identifier, ObjectPermission.Type type)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Get object permissions
|
||||
ObjectPermissionSet permissionSet = getEffectivePermissionSet(user);
|
||||
|
||||
// Return whether permission is granted
|
||||
return user.isPrivileged()
|
||||
|| permissionSet.hasPermission(type, identifier);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the permission set associated with the given user and related
|
||||
* to the type of objects handled by this directory object service, taking
|
||||
* into account permission inheritance via user groups.
|
||||
*
|
||||
* @param user
|
||||
* The user whose permissions are being retrieved.
|
||||
*
|
||||
* @return
|
||||
* A permission set which contains the permissions associated with the
|
||||
* given user and related to the type of objects handled by this
|
||||
* directory object service.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to read the user's permissions is denied.
|
||||
*/
|
||||
protected abstract ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns a collection of objects which are backed by the models in the
|
||||
* given collection.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user for whom these objects are being created.
|
||||
*
|
||||
* @param models
|
||||
* The model objects to use to back the objects within the returned
|
||||
* collection.
|
||||
*
|
||||
* @return
|
||||
* A collection of objects which are backed by the models in the given
|
||||
* collection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If any of the object instances cannot be created.
|
||||
*/
|
||||
protected Collection<InternalType> getObjectInstances(ModeledAuthenticatedUser currentUser,
|
||||
Collection<ModelType> models) throws GuacamoleException {
|
||||
|
||||
// Create new collection of objects by manually converting each model
|
||||
Collection<InternalType> objects = new ArrayList<>(models.size());
|
||||
for (ModelType model : models)
|
||||
objects.add(getObjectInstance(currentUser, model));
|
||||
|
||||
return objects;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before any object is created through this directory object
|
||||
* service. This function serves as a final point of validation before
|
||||
* the create operation occurs. In its default implementation,
|
||||
* beforeCreate() performs basic permissions checks.
|
||||
*
|
||||
* @param user
|
||||
* The user creating the object.
|
||||
*
|
||||
* @param object
|
||||
* The object being created.
|
||||
*
|
||||
* @param model
|
||||
* The model of the object being created.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the object is invalid, or an error prevents validating the given
|
||||
* object.
|
||||
*/
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user,
|
||||
ExternalType object, ModelType model) throws GuacamoleException {
|
||||
|
||||
// Verify permission to create objects
|
||||
if (!user.isPrivileged() && !hasCreatePermission(user))
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before any object is updated through this directory object
|
||||
* service. This function serves as a final point of validation before
|
||||
* the update operation occurs. In its default implementation,
|
||||
* beforeUpdate() performs basic permissions checks.
|
||||
*
|
||||
* @param user
|
||||
* The user updating the existing object.
|
||||
*
|
||||
* @param object
|
||||
* The object being updated.
|
||||
*
|
||||
* @param model
|
||||
* The model of the object being updated.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the object is invalid, or an error prevents validating the given
|
||||
* object.
|
||||
*/
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
InternalType object, ModelType model) throws GuacamoleException {
|
||||
|
||||
// By default, do nothing.
|
||||
if (!hasObjectPermission(user, model.getIdentifier(), ObjectPermission.Type.UPDATE))
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before any object is deleted through this directory object
|
||||
* service. This function serves as a final point of validation before
|
||||
* the delete operation occurs. In its default implementation,
|
||||
* beforeDelete() performs basic permissions checks.
|
||||
*
|
||||
* @param user
|
||||
* The user deleting the existing object.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the object being deleted.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the object is invalid, or an error prevents validating the given
|
||||
* object.
|
||||
*/
|
||||
protected void beforeDelete(ModeledAuthenticatedUser user,
|
||||
String identifier) throws GuacamoleException {
|
||||
|
||||
// Verify permission to delete objects
|
||||
if (!hasObjectPermission(user, identifier, ObjectPermission.Type.DELETE))
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given string is a valid identifier within the JDBC
|
||||
* authentication extension. Invalid identifiers may result in SQL errors
|
||||
* from the underlying database when used in queries.
|
||||
*
|
||||
* @param identifier
|
||||
* The string to check for validity.
|
||||
*
|
||||
* @return
|
||||
* true if the given string is a valid identifier, false otherwise.
|
||||
*/
|
||||
protected boolean isValidIdentifier(String identifier) {
|
||||
|
||||
// Empty identifiers are invalid
|
||||
if (identifier.isEmpty())
|
||||
return false;
|
||||
|
||||
// Identifier is invalid if any non-numeric characters are present
|
||||
for (int i = 0; i < identifier.length(); i++) {
|
||||
if (!Character.isDigit(identifier.charAt(i)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Identifier is valid - contains only numeric characters
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the given collection of strings, returning a new collection
|
||||
* containing only those strings which are valid identifiers. If no strings
|
||||
* within the collection are valid identifiers, the returned collection will
|
||||
* simply be empty.
|
||||
*
|
||||
* @param identifiers
|
||||
* The collection of strings to filter.
|
||||
*
|
||||
* @return
|
||||
* A new collection containing only the strings within the provided
|
||||
* collection which are valid identifiers.
|
||||
*/
|
||||
protected List<String> filterIdentifiers(Collection<String> identifiers) {
|
||||
|
||||
// Obtain enough space for a full copy of the given identifiers
|
||||
List<String> validIdentifiers = new ArrayList<>(identifiers.size());
|
||||
|
||||
// Add only valid identifiers to the copy
|
||||
for (String identifier : identifiers) {
|
||||
if (isValidIdentifier(identifier))
|
||||
validIdentifiers.add(identifier);
|
||||
}
|
||||
|
||||
return validIdentifiers;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalType retrieveObject(ModeledAuthenticatedUser user,
|
||||
String identifier) throws GuacamoleException {
|
||||
|
||||
// Pull objects having given identifier
|
||||
Collection<InternalType> objects = retrieveObjects(user, Collections.singleton(identifier));
|
||||
|
||||
// If no such object, return null
|
||||
if (objects.isEmpty())
|
||||
return null;
|
||||
|
||||
// The object collection will have exactly one element unless the
|
||||
// database has seriously lost integrity
|
||||
assert(objects.size() == 1);
|
||||
|
||||
// Return first and only object
|
||||
return objects.iterator().next();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<InternalType> retrieveObjects(ModeledAuthenticatedUser user,
|
||||
Collection<String> identifiers) throws GuacamoleException {
|
||||
|
||||
// Ignore invalid identifiers
|
||||
List<String> filteredIdentifiers = filterIdentifiers(identifiers);
|
||||
|
||||
// Do not query if no identifiers given
|
||||
if (filteredIdentifiers.isEmpty())
|
||||
return Collections.<InternalType>emptyList();
|
||||
|
||||
int batchSize = environment.getBatchSize();
|
||||
|
||||
boolean userIsPrivileged = user.isPrivileged();
|
||||
|
||||
CaseSensitivity caseSensitivity = getCaseSensitivity();
|
||||
|
||||
// Process the filteredIdentifiers in batches using Lists.partition() and flatMap
|
||||
Collection<ModelType> allObjects = Lists.partition(filteredIdentifiers, batchSize).stream()
|
||||
.flatMap(chunk -> {
|
||||
Collection<ModelType> objects;
|
||||
|
||||
// Bypass permission checks if the user is privileged
|
||||
if (userIsPrivileged)
|
||||
objects = getObjectMapper().select(chunk, caseSensitivity);
|
||||
|
||||
// Otherwise only return explicitly readable identifiers
|
||||
else
|
||||
objects = getObjectMapper().selectReadable(user.getUser().getModel(),
|
||||
chunk, user.getEffectiveUserGroups(), caseSensitivity);
|
||||
|
||||
return objects.stream();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Return collection of requested objects
|
||||
return getObjectInstances(user, allObjects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable collection of permissions that should be granted due
|
||||
* to the creation of the given object. These permissions need not be
|
||||
* granted solely to the user creating the object.
|
||||
*
|
||||
* @param user
|
||||
* The user creating the object.
|
||||
*
|
||||
* @param model
|
||||
* The object being created.
|
||||
*
|
||||
* @return
|
||||
* The collection of implicit permissions that should be granted due to
|
||||
* the creation of the given object.
|
||||
*/
|
||||
protected Collection<ObjectPermissionModel> getImplicitPermissions(ModeledAuthenticatedUser user,
|
||||
ModelType model) {
|
||||
|
||||
// Check to see if the user granting permissions is a skeleton user,
|
||||
// thus lacking database backing.
|
||||
if (user.getUser().isSkeleton())
|
||||
return Collections.emptyList();
|
||||
|
||||
// Build list of implicit permissions
|
||||
Collection<ObjectPermissionModel> implicitPermissions =
|
||||
new ArrayList<>(IMPLICIT_OBJECT_PERMISSIONS.length);
|
||||
|
||||
|
||||
UserModel userModel = user.getUser().getModel();
|
||||
for (ObjectPermission.Type permission : IMPLICIT_OBJECT_PERMISSIONS) {
|
||||
|
||||
// Create model which grants this permission to the current user
|
||||
ObjectPermissionModel permissionModel = new ObjectPermissionModel();
|
||||
permissionModel.setEntityID(userModel.getEntityID());
|
||||
permissionModel.setType(permission);
|
||||
permissionModel.setObjectIdentifier(model.getIdentifier());
|
||||
|
||||
// Add permission
|
||||
implicitPermissions.add(permissionModel);
|
||||
|
||||
}
|
||||
|
||||
return Collections.unmodifiableCollection(implicitPermissions);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public InternalType createObject(ModeledAuthenticatedUser user, ExternalType object)
|
||||
throws GuacamoleException {
|
||||
|
||||
ModelType model = getModelInstance(user, object);
|
||||
beforeCreate(user, object, model);
|
||||
|
||||
// Create object
|
||||
getObjectMapper().insert(model);
|
||||
|
||||
// Set identifier on original object
|
||||
object.setIdentifier(model.getIdentifier());
|
||||
|
||||
// Add implicit permissions
|
||||
Collection<ObjectPermissionModel> implicitPermissions = getImplicitPermissions(user, model);
|
||||
if (!implicitPermissions.isEmpty())
|
||||
getPermissionMapper().insert(implicitPermissions, getCaseSensitivity());
|
||||
|
||||
// Add any arbitrary attributes
|
||||
if (model.hasArbitraryAttributes())
|
||||
getObjectMapper().insertAttributes(model);
|
||||
|
||||
return getObjectInstance(user, model);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(ModeledAuthenticatedUser user, String identifier)
|
||||
throws GuacamoleException {
|
||||
|
||||
beforeDelete(user, identifier);
|
||||
|
||||
// Delete object
|
||||
getObjectMapper().delete(identifier, getCaseSensitivity());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateObject(ModeledAuthenticatedUser user, InternalType object)
|
||||
throws GuacamoleException {
|
||||
|
||||
ModelType model = object.getModel();
|
||||
beforeUpdate(user, object, model);
|
||||
|
||||
// Update object
|
||||
getObjectMapper().update(model);
|
||||
|
||||
// Replace any existing arbitrary attributes
|
||||
getObjectMapper().deleteAttributes(model);
|
||||
if (model.hasArbitraryAttributes())
|
||||
getObjectMapper().insertAttributes(model);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getIdentifiers(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Bypass permission checks if the user is privileged
|
||||
if (user.isPrivileged())
|
||||
return getObjectMapper().selectIdentifiers();
|
||||
|
||||
// Otherwise only return explicitly readable identifiers
|
||||
else
|
||||
return getObjectMapper().selectReadableIdentifiers(
|
||||
user.getUser().getModel(),
|
||||
user.getEffectiveUserGroups(),
|
||||
getCaseSensitivity()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
|
||||
/**
|
||||
* Common base class for objects have an underlying model. For the purposes of
|
||||
* JDBC-driven authentication providers, all modeled objects are also
|
||||
* restricted.
|
||||
*
|
||||
* @param <ModelType>
|
||||
* The type of model object which corresponds to this object.
|
||||
*/
|
||||
public abstract class ModeledObject<ModelType> extends RestrictedObject {
|
||||
|
||||
/**
|
||||
* The internal model object containing the values which represent this
|
||||
* object in the database.
|
||||
*/
|
||||
private ModelType model;
|
||||
|
||||
/**
|
||||
* Initializes this object, associating it with the current authenticated
|
||||
* user and populating it with data from the given model object
|
||||
*
|
||||
* @param currentUser
|
||||
* The user that created or retrieved this object.
|
||||
*
|
||||
* @param model
|
||||
* The backing model object.
|
||||
*/
|
||||
public void init(ModeledAuthenticatedUser currentUser, ModelType model) {
|
||||
super.init(currentUser);
|
||||
setModel(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the backing model object. Changes to the model object will
|
||||
* affect this object, and changes to this object will affect the model
|
||||
* object.
|
||||
*
|
||||
* @return
|
||||
* The backing model object.
|
||||
*/
|
||||
public ModelType getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the backing model object. This will effectively replace all data
|
||||
* contained within this object.
|
||||
*
|
||||
* @param model
|
||||
* The backing model object.
|
||||
*/
|
||||
public void setModel(ModelType model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* 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 com.google.inject.Inject;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SystemPermissionService;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.UserPermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.Permissions;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
|
||||
|
||||
/**
|
||||
* An implementation of the base Permissions interface which is common to both
|
||||
* Users and UserGroups, backed by a database model.
|
||||
*
|
||||
* @param <ModelType>
|
||||
* The type of model object that corresponds to this object.
|
||||
*/
|
||||
public abstract class ModeledPermissions<ModelType extends EntityModel>
|
||||
extends ModeledDirectoryObject<ModelType> implements Permissions {
|
||||
|
||||
/**
|
||||
* Service for retrieving entity details.
|
||||
*/
|
||||
@Inject
|
||||
private EntityService entityService;
|
||||
|
||||
/**
|
||||
* Service for retrieving system permissions.
|
||||
*/
|
||||
@Inject
|
||||
private SystemPermissionService systemPermissionService;
|
||||
|
||||
/**
|
||||
* Service for retrieving connection permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionPermissionService connectionPermissionService;
|
||||
|
||||
/**
|
||||
* Service for retrieving connection group permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionGroupPermissionService connectionGroupPermissionService;
|
||||
|
||||
/**
|
||||
* Service for retrieving sharing profile permissions.
|
||||
*/
|
||||
@Inject
|
||||
private SharingProfilePermissionService sharingProfilePermissionService;
|
||||
|
||||
/**
|
||||
* Service for retrieving active connection permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ActiveConnectionPermissionService activeConnectionPermissionService;
|
||||
|
||||
/**
|
||||
* Service for retrieving user permissions.
|
||||
*/
|
||||
@Inject
|
||||
private UserPermissionService userPermissionService;
|
||||
|
||||
/**
|
||||
* Service for retrieving user group permissions.
|
||||
*/
|
||||
@Inject
|
||||
private UserGroupPermissionService userGroupPermissionService;
|
||||
|
||||
/**
|
||||
* Returns whether the underlying entity is a user. Entities may be either
|
||||
* users or user groups.
|
||||
*
|
||||
* @return
|
||||
* true if the underlying entity is a user, false otherwise.
|
||||
*/
|
||||
public boolean isUser() {
|
||||
return getModel().getEntityType() == EntityType.USER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the underlying entity represents a specific user having
|
||||
* the given username.
|
||||
*
|
||||
* @param username
|
||||
* The username of a user.
|
||||
*
|
||||
* @return
|
||||
* true if the underlying entity is a user that has the given username,
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean isUser(String username) {
|
||||
return isUser() && getIdentifier().equals(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the underlying entity is a user group. Entities may be
|
||||
* either users or user groups.
|
||||
*
|
||||
* @return
|
||||
* true if the underlying entity is a user group, false otherwise.
|
||||
*/
|
||||
public boolean isUserGroup() {
|
||||
return getModel().getEntityType() == EntityType.USER_GROUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this entity is effectively unrestricted by permissions,
|
||||
* such as a system administrator or an internal user operating via a
|
||||
* privileged UserContext. Permission inheritance via user groups is taken
|
||||
* into account.
|
||||
*
|
||||
* @return
|
||||
* true if this entity should be unrestricted by permissions, false
|
||||
* otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while determining whether permission restrictions
|
||||
* apply to the entity.
|
||||
*/
|
||||
public boolean isPrivileged() throws GuacamoleException {
|
||||
SystemPermissionSet systemPermissionSet = getEffective().getSystemPermissions();
|
||||
return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemPermissionSet getSystemPermissions()
|
||||
throws GuacamoleException {
|
||||
return systemPermissionService.getPermissionSet(getCurrentUser(), this,
|
||||
Collections.<String>emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getConnectionPermissions()
|
||||
throws GuacamoleException {
|
||||
return connectionPermissionService.getPermissionSet(getCurrentUser(),
|
||||
this, Collections.<String>emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getConnectionGroupPermissions()
|
||||
throws GuacamoleException {
|
||||
return connectionGroupPermissionService.getPermissionSet(
|
||||
getCurrentUser(), this, Collections.<String>emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getSharingProfilePermissions()
|
||||
throws GuacamoleException {
|
||||
return sharingProfilePermissionService.getPermissionSet(
|
||||
getCurrentUser(), this, Collections.<String>emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getActiveConnectionPermissions()
|
||||
throws GuacamoleException {
|
||||
return activeConnectionPermissionService.getPermissionSet(
|
||||
getCurrentUser(), this, Collections.<String>emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getUserPermissions()
|
||||
throws GuacamoleException {
|
||||
return userPermissionService.getPermissionSet(getCurrentUser(), this,
|
||||
Collections.<String>emptySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException {
|
||||
return userGroupPermissionService.getPermissionSet(getCurrentUser(),
|
||||
this, Collections.<String>emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifiers of all user groups defined within the database
|
||||
* which apply to this user, including any groups inherited through
|
||||
* membership in yet more groups.
|
||||
*
|
||||
* @return
|
||||
* The identifiers of all user groups defined within the database which
|
||||
* apply to this user.
|
||||
*/
|
||||
public Set<String> getEffectiveUserGroups() {
|
||||
return entityService.retrieveEffectiveGroups(this,
|
||||
Collections.<String>emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Permissions object which represents all permissions granted to
|
||||
* this entity, including any permissions inherited through group
|
||||
* membership.
|
||||
*
|
||||
* @return
|
||||
* A Permissions object which represents all permissions granted to
|
||||
* this entity.
|
||||
*/
|
||||
public Permissions getEffective() {
|
||||
|
||||
final ModeledAuthenticatedUser authenticatedUser = getCurrentUser();
|
||||
final Set<String> effectiveGroups;
|
||||
|
||||
// If this user is the currently-authenticated user, include any
|
||||
// additional effective groups declared by the authentication system
|
||||
if (authenticatedUser.getIdentifier().equals(getIdentifier()))
|
||||
effectiveGroups = entityService.retrieveEffectiveGroups(this,
|
||||
authenticatedUser.getEffectiveUserGroups());
|
||||
|
||||
// Otherwise, just include effective groups from the database
|
||||
else
|
||||
effectiveGroups = getEffectiveUserGroups();
|
||||
|
||||
// Return a permissions object which describes all effective
|
||||
// permissions, including any permissions inherited via user groups
|
||||
return new Permissions() {
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getActiveConnectionPermissions()
|
||||
throws GuacamoleException {
|
||||
return activeConnectionPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getConnectionGroupPermissions()
|
||||
throws GuacamoleException {
|
||||
return connectionGroupPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getConnectionPermissions()
|
||||
throws GuacamoleException {
|
||||
return connectionPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getSharingProfilePermissions()
|
||||
throws GuacamoleException {
|
||||
return sharingProfilePermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemPermissionSet getSystemPermissions()
|
||||
throws GuacamoleException {
|
||||
return systemPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getUserPermissions()
|
||||
throws GuacamoleException {
|
||||
return userPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getUserGroupPermissions()
|
||||
throws GuacamoleException {
|
||||
return userGroupPermissionService.getPermissionSet(getCurrentUser(), ModeledPermissions.this, effectiveGroups);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.Collection;
|
||||
|
||||
/**
|
||||
* Object representation of a Guacamole object, such as a user or connection,
|
||||
* as represented in the database.
|
||||
*/
|
||||
public abstract class ObjectModel {
|
||||
|
||||
/**
|
||||
* The ID of this object in the database, if any.
|
||||
*/
|
||||
private Integer objectID;
|
||||
|
||||
/**
|
||||
* The unique identifier which identifies this object.
|
||||
*/
|
||||
private String identifier;
|
||||
|
||||
/**
|
||||
* Map of all arbitrary attributes associated with this object but not
|
||||
* directly mapped to a particular column.
|
||||
*/
|
||||
private ArbitraryAttributeMap arbitraryAttributes =
|
||||
new ArbitraryAttributeMap();
|
||||
|
||||
/**
|
||||
* Creates a new, empty object.
|
||||
*/
|
||||
public ObjectModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier that uniquely identifies this object.
|
||||
*
|
||||
* @return
|
||||
* The identifier that uniquely identifies this object.
|
||||
*/
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifier that uniquely identifies this object.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier that uniquely identifies this object.
|
||||
*/
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of this object in the database, if it exists.
|
||||
*
|
||||
* @return
|
||||
* The ID of this object in the database, or null if this object was
|
||||
* not retrieved from the database.
|
||||
*/
|
||||
public Integer getObjectID() {
|
||||
return objectID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID of this object to the given value.
|
||||
*
|
||||
* @param objectID
|
||||
* The ID to assign to this object.
|
||||
*/
|
||||
public void setObjectID(Integer objectID) {
|
||||
this.objectID = objectID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of attribute name/value pairs for all attributes associated
|
||||
* with this model which do not have explicit mappings to actual model
|
||||
* properties. All other attributes (those which are explicitly supported
|
||||
* by the model) should instead be mapped to properties with corresponding
|
||||
* and properly-typed columns.
|
||||
*
|
||||
* @return
|
||||
* A map of attribute name/value pairs for all attributes associated
|
||||
* with this model which do not otherwise have explicit mappings to
|
||||
* properties.
|
||||
*/
|
||||
public ArbitraryAttributeMap getArbitraryAttributeMap() {
|
||||
return arbitraryAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether at least one arbitrary attribute name/value pair has
|
||||
* been associated with this object.
|
||||
*
|
||||
* @return
|
||||
* true if this object has at least one arbitrary attribute set, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean hasArbitraryAttributes() {
|
||||
return !arbitraryAttributes.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Collection view of the equivalent attribute model objects
|
||||
* which make up the map of arbitrary attribute name/value pairs returned
|
||||
* by getArbitraryAttributeMap(). Additions and removals on the returned
|
||||
* Collection directly affect the attribute map.
|
||||
*
|
||||
* @return
|
||||
* A Collection view of the map returned by
|
||||
* getArbitraryAttributeMap().
|
||||
*/
|
||||
public Collection<ArbitraryAttributeModel> getArbitraryAttributes() {
|
||||
return arbitraryAttributes.toModelCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all arbitrary attributes associated with this object with the
|
||||
* attribute name/value pairs within the given collection of model objects.
|
||||
*
|
||||
* @param arbitraryAttributes
|
||||
* The Collection of model objects containing the attribute name/value
|
||||
* pairs which should replace all currently-stored arbitrary attributes,
|
||||
* if any.
|
||||
*/
|
||||
public void setArbitraryAttributes(Collection<ArbitraryAttributeModel> arbitraryAttributes) {
|
||||
this.arbitraryAttributes = ArbitraryAttributeMap.fromModelCollection(arbitraryAttributes);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserModel;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Mapper for the relations represented by a particular RelatedObjectSet
|
||||
* implementation.
|
||||
*
|
||||
* @param <ParentModelType>
|
||||
* The underlying database model of the object on the parent side of the
|
||||
* one-to-many relationship represented by the RelatedObjectSet mapped by
|
||||
* this ObjectRelationMapper.
|
||||
*/
|
||||
public interface ObjectRelationMapper<ParentModelType extends ObjectModel> {
|
||||
|
||||
/**
|
||||
* Inserts rows as necessary to establish the one-to-many relationship
|
||||
* represented by the RelatedObjectSet between the given parent and
|
||||
* children. If the relation for any parent/child pair is already present,
|
||||
* no attempt is made to insert a new row for that relation.
|
||||
*
|
||||
* @param parent
|
||||
* The model of the object on the parent side of the one-to-many
|
||||
* relationship represented by the RelatedObjectSet.
|
||||
*
|
||||
* @param children
|
||||
* The identifiers of the objects on the child side of the one-to-many
|
||||
* relationship represented by the RelatedObjectSet.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The case sensitivity configuration, used to determine whether
|
||||
* usernames and/or group names will be treated as case-sensitive.
|
||||
*
|
||||
* @return
|
||||
* The number of rows inserted.
|
||||
*/
|
||||
int insert(@Param("parent") ParentModelType parent,
|
||||
@Param("children") Collection<String> children,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Deletes rows as necessary to modify the one-to-many relationship
|
||||
* represented by the RelatedObjectSet between the given parent and
|
||||
* children. If the relation for any parent/child pair does not exist,
|
||||
* that specific relation is ignored, and deletion proceeds with the
|
||||
* remaining relations.
|
||||
*
|
||||
* @param parent
|
||||
* The model of the object on the parent side of the one-to-many
|
||||
* relationship represented by the RelatedObjectSet.
|
||||
*
|
||||
* @param children
|
||||
* The identifiers of the objects on the child side of the one-to-many
|
||||
* relationship represented by the RelatedObjectSet.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The case sensitivity configuration, used to determine whether
|
||||
* usernames and/or group names will be treated as case-sensitive.
|
||||
*
|
||||
* @return
|
||||
* The number of rows deleted.
|
||||
*/
|
||||
int delete(@Param("parent") ParentModelType parent,
|
||||
@Param("children") Collection<String> children,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Retrieves the identifiers of all objects on the child side of the
|
||||
* one-to-many relationship represented by the RelatedObjectSet mapped by
|
||||
* this ObjectRelationMapper. This should only be called on behalf of a
|
||||
* system administrator. If identifiers are needed by a non-administrative
|
||||
* user who must have explicit read rights, use
|
||||
* selectReadableChildIdentifiers() instead.
|
||||
*
|
||||
* @param parent
|
||||
* The model of the object on the parent side of the one-to-many
|
||||
* relationship represented by the RelatedObjectSet.
|
||||
*
|
||||
* @return
|
||||
* A Set containing the identifiers of all objects on the child side
|
||||
* of the one-to-many relationship.
|
||||
*/
|
||||
Set<String> selectChildIdentifiers(@Param("parent") ParentModelType parent);
|
||||
|
||||
/**
|
||||
* Retrieves the identifiers of all objects on the child side of the
|
||||
* one-to-many relationship represented by the RelatedObjectSet mapped by
|
||||
* this ObjectRelationMapper, including only those objects which are
|
||||
* explicitly readable by the given user. If identifiers are needed by a
|
||||
* system administrator (who, by definition, does not need explicit read
|
||||
* rights), use selectChildIdentifiers() instead.
|
||||
|
||||
*
|
||||
* @param user
|
||||
* The user whose permissions should determine whether an identifier
|
||||
* is returned.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of any known effective groups that should be taken
|
||||
* into account, such as those defined externally to the database.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The object that contains current configuration for case sensitivity
|
||||
* for usernames and group names.
|
||||
*
|
||||
* @param parent
|
||||
* The model of the object on the parent side of the one-to-many
|
||||
* relationship represented by the RelatedObjectSet.
|
||||
*
|
||||
* @return
|
||||
* A Set containing the identifiers of all readable objects on the
|
||||
* child side of the one-to-many relationship.
|
||||
*/
|
||||
Set<String> selectReadableChildIdentifiers(@Param("user") UserModel user,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity,
|
||||
@Param("parent") ParentModelType parent);
|
||||
|
||||
}
|
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* 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.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
|
||||
/**
|
||||
* A database implementation of RelatedObjectSet which provides access to a
|
||||
* parent object and corresponding set of objects related to the parent, subject
|
||||
* to object-level permissions. Though the parent and child objects have
|
||||
* specific types, only the parent object's type is enforced through type
|
||||
* parameters, as child objects are represented by identifiers only.
|
||||
*
|
||||
* @param <ParentObjectType>
|
||||
* The type of object that represents the parent side of the relation.
|
||||
*
|
||||
* @param <ParentModelType>
|
||||
* The underlying database model of the parent object.
|
||||
*/
|
||||
public abstract class RelatedObjectSet<ParentObjectType extends ModeledDirectoryObject<ParentModelType>, ParentModelType extends ObjectModel>
|
||||
extends RestrictedObject implements org.apache.guacamole.net.auth.RelatedObjectSet {
|
||||
|
||||
/**
|
||||
* The parent object which shares some arbitrary relation with the objects
|
||||
* within this set.
|
||||
*/
|
||||
private ParentObjectType parent;
|
||||
|
||||
/**
|
||||
* Creates a new RelatedObjectSet. The resulting object set must still be
|
||||
* initialized by a call to init().
|
||||
*/
|
||||
public RelatedObjectSet() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this RelatedObjectSet with the current user and the single
|
||||
* object on the parent side of the one-to-many relation represented by the
|
||||
* set.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user who queried this RelatedObjectSet, and whose permissions
|
||||
* dictate the access level of all operations performed on this set.
|
||||
*
|
||||
* @param parent
|
||||
* The parent object which shares some arbitrary relation with the
|
||||
* objects within this set.
|
||||
*/
|
||||
public void init(ModeledAuthenticatedUser currentUser, ParentObjectType parent) {
|
||||
super.init(currentUser);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current case sensitivity setting, which can be used to
|
||||
* determine whether or not certain identifiers should be treated as
|
||||
* case-sensitive.
|
||||
*
|
||||
* @return
|
||||
* The current case sensitivity setting.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs retrieving configuration information on
|
||||
* case sensitivity.
|
||||
*/
|
||||
protected CaseSensitivity getCaseSensitivity() throws GuacamoleException {
|
||||
|
||||
// Identifiers are not case-sensitive by default.
|
||||
return CaseSensitivity.DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mapper which provides low-level access to the database
|
||||
* models which drive the relation represented by this RelatedObjectSet.
|
||||
*
|
||||
* @return
|
||||
* The mapper which provides low-level access to the database
|
||||
* models which drive the relation represented by this
|
||||
* RelatedObjectSet.
|
||||
*/
|
||||
protected abstract ObjectRelationMapper<ParentModelType> getObjectRelationMapper();
|
||||
|
||||
/**
|
||||
* Returns the permission set which exposes the effective permissions
|
||||
* available to the current user regarding the objects on the parent side
|
||||
* of the one-to-many relationship represented by this RelatedObjectSet.
|
||||
* Permission inheritance through user groups is taken into account.
|
||||
*
|
||||
* @return
|
||||
* The permission set which exposes the effective permissions
|
||||
* available to the current user regarding the objects on the parent
|
||||
* side of the one-to-many relationship represented by this
|
||||
* RelatedObjectSet.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to query permission status is denied.
|
||||
*/
|
||||
protected abstract ObjectPermissionSet getParentObjectEffectivePermissionSet()
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the permission set which exposes the effective permissions
|
||||
* available to the current user regarding the objects on the child side
|
||||
* of the one-to-many relationship represented by this RelatedObjectSet.
|
||||
* Permission inheritance through user groups is taken into account.
|
||||
*
|
||||
* @return
|
||||
* The permission set which exposes the effective permissions
|
||||
* available to the current user regarding the objects on the child
|
||||
* side of the one-to-many relationship represented by this
|
||||
* RelatedObjectSet.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to query permission status is denied.
|
||||
*/
|
||||
protected abstract ObjectPermissionSet getChildObjectEffectivePermissionSet()
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns whether the current user has permission to alter the status of
|
||||
* the relation between the parent object and the given child objects.
|
||||
*
|
||||
* @param identifiers
|
||||
* The identifiers of all objects on the child side of the one-to-many
|
||||
* relation being changed.
|
||||
*
|
||||
* @return
|
||||
* true if the user has permission to make the described changes,
|
||||
* false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to query permission status is denied.
|
||||
*/
|
||||
private boolean canAlterRelation(Collection<String> identifiers)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Privileged users (such as system administrators) may alter any
|
||||
// relations
|
||||
if (getCurrentUser().isPrivileged())
|
||||
return true;
|
||||
|
||||
// Non-admin users require UPDATE permission on the parent object ...
|
||||
if (!getParentObjectEffectivePermissionSet().hasPermission(
|
||||
ObjectPermission.Type.UPDATE, parent.getIdentifier()))
|
||||
return false;
|
||||
|
||||
// ... as well as UPDATE permission on all child objects being changed
|
||||
Collection<String> accessibleIdentifiers =
|
||||
getChildObjectEffectivePermissionSet().getAccessibleObjects(
|
||||
Collections.singleton(ObjectPermission.Type.UPDATE),
|
||||
identifiers);
|
||||
|
||||
return accessibleIdentifiers.size() == identifiers.size();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getObjects() throws GuacamoleException {
|
||||
|
||||
// Bypass permission checks if the user is a privileged
|
||||
ModeledAuthenticatedUser user = getCurrentUser();
|
||||
if (user.isPrivileged())
|
||||
return getObjectRelationMapper().selectChildIdentifiers(parent.getModel());
|
||||
|
||||
// Otherwise only return explicitly readable identifiers
|
||||
return getObjectRelationMapper().selectReadableChildIdentifiers(
|
||||
user.getUser().getModel(), user.getEffectiveUserGroups(),
|
||||
getCaseSensitivity(),
|
||||
parent.getModel());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addObjects(Set<String> identifiers) throws GuacamoleException {
|
||||
|
||||
// Nothing to do if nothing provided
|
||||
if (identifiers.isEmpty())
|
||||
return;
|
||||
|
||||
// Create relations only if permission is granted
|
||||
if (canAlterRelation(identifiers))
|
||||
getObjectRelationMapper().insert(parent.getModel(), identifiers,
|
||||
getCaseSensitivity());
|
||||
|
||||
// User lacks permission to add user groups
|
||||
else
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeObjects(Set<String> identifiers) throws GuacamoleException {
|
||||
|
||||
// Nothing to do if nothing provided
|
||||
if (identifiers.isEmpty())
|
||||
return;
|
||||
|
||||
// Delete relations only if permission is granted
|
||||
if (canAlterRelation(identifiers))
|
||||
getObjectRelationMapper().delete(parent.getModel(), identifiers,
|
||||
getCaseSensitivity());
|
||||
|
||||
// User lacks permission to remove user groups
|
||||
else
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
|
||||
/**
|
||||
* Common base class for objects that are associated with the users that
|
||||
* obtain them.
|
||||
*/
|
||||
public abstract class RestrictedObject {
|
||||
|
||||
/**
|
||||
* The user this object belongs to. Access is based on his/her permission
|
||||
* settings.
|
||||
*/
|
||||
private ModeledAuthenticatedUser currentUser;
|
||||
|
||||
/**
|
||||
* Initializes this object, associating it with the current authenticated
|
||||
* user and populating it with data from the given model object
|
||||
*
|
||||
* @param currentUser
|
||||
* The user that created or retrieved this object.
|
||||
*/
|
||||
public void init(ModeledAuthenticatedUser currentUser) {
|
||||
setCurrentUser(currentUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user that created or queried this object. This user's
|
||||
* permissions dictate what operations can be performed on or through this
|
||||
* object.
|
||||
*
|
||||
* @return
|
||||
* The user that created or queried this object.
|
||||
*/
|
||||
public ModeledAuthenticatedUser getCurrentUser() {
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user that created or queried this object. This user's
|
||||
* permissions dictate what operations can be performed on or through this
|
||||
* object.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user that created or queried this object.
|
||||
*/
|
||||
public void setCurrentUser(ModeledAuthenticatedUser currentUser) {
|
||||
this.currentUser = currentUser;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base classes supporting JDBC-driven authentication providers and defining
|
||||
* the relationships between the model and the implementations of guacamole-ext
|
||||
* classes.
|
||||
*/
|
||||
package org.apache.guacamole.auth.jdbc.base;
|
@@ -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.connection;
|
||||
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.JDBCDirectory;
|
||||
import org.apache.guacamole.net.auth.Connection;
|
||||
import org.mybatis.guice.transactional.Transactional;
|
||||
|
||||
/**
|
||||
* Implementation of the Connection Directory which is driven by an underlying,
|
||||
* arbitrary database.
|
||||
*/
|
||||
public class ConnectionDirectory extends JDBCDirectory<Connection> {
|
||||
|
||||
/**
|
||||
* Service for managing connection objects.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionService connectionService;
|
||||
|
||||
@Override
|
||||
public Connection get(String identifier) throws GuacamoleException {
|
||||
return connectionService.retrieveObject(getCurrentUser(), identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Collection<Connection> getAll(Collection<String> identifiers) throws GuacamoleException {
|
||||
Collection<ModeledConnection> objects = connectionService.retrieveObjects(getCurrentUser(), identifiers);
|
||||
return Collections.<Connection>unmodifiableCollection(objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Set<String> getIdentifiers() throws GuacamoleException {
|
||||
return connectionService.getIdentifiers(getCurrentUser());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void add(Connection object) throws GuacamoleException {
|
||||
connectionService.createObject(getCurrentUser(), object);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void update(Connection object) throws GuacamoleException {
|
||||
ModeledConnection connection = (ModeledConnection) object;
|
||||
connectionService.updateObject(getCurrentUser(), connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void remove(String identifier) throws GuacamoleException {
|
||||
connectionService.deleteObject(getCurrentUser(), identifier);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserModel;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Mapper for connection objects.
|
||||
*/
|
||||
public interface ConnectionMapper extends ModeledDirectoryObjectMapper<ConnectionModel> {
|
||||
|
||||
/**
|
||||
* Selects the identifiers of all connections within the given parent
|
||||
* connection group, regardless of whether they are readable by any
|
||||
* particular user. This should only be called on behalf of a system
|
||||
* administrator. If identifiers are needed by a non-administrative user
|
||||
* who must have explicit read rights, use
|
||||
* selectReadableIdentifiersWithin() instead.
|
||||
*
|
||||
* @param parentIdentifier
|
||||
* The identifier of the parent connection group, or null if the root
|
||||
* connection group is to be queried.
|
||||
*
|
||||
* @return
|
||||
* A Set containing all identifiers of all objects.
|
||||
*/
|
||||
Set<String> selectIdentifiersWithin(@Param("parentIdentifier") String parentIdentifier);
|
||||
|
||||
/**
|
||||
* Selects the identifiers of all connections within the given parent
|
||||
* connection group that are explicitly readable by the given user. If
|
||||
* identifiers are needed by a system administrator (who, by definition,
|
||||
* does not need explicit read rights), use selectIdentifiersWithin()
|
||||
* instead.
|
||||
*
|
||||
* @param user
|
||||
* The user whose permissions should determine whether an identifier
|
||||
* is returned.
|
||||
*
|
||||
* @param parentIdentifier
|
||||
* The identifier of the parent connection group, or null if the root
|
||||
* connection group is to be queried.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the user. If
|
||||
* no groups are given, only permissions directly granted to the user
|
||||
* will be used.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The object that contains current configuration for case sensitivity
|
||||
* for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* A Set containing all identifiers of all readable objects.
|
||||
*/
|
||||
Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user,
|
||||
@Param("parentIdentifier") String parentIdentifier,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Selects the connection within the given parent group and having the
|
||||
* given name. If no such connection exists, null is returned.
|
||||
*
|
||||
* @param parentIdentifier
|
||||
* The identifier of the parent group to search within.
|
||||
*
|
||||
* @param name
|
||||
* The name of the connection to find.
|
||||
*
|
||||
* @return
|
||||
* The connection having the given name within the given parent group,
|
||||
* or null if no such connection exists.
|
||||
*/
|
||||
ConnectionModel selectOneByName(@Param("parentIdentifier") String parentIdentifier,
|
||||
@Param("name") String name);
|
||||
|
||||
}
|
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.base.ChildObjectModel;
|
||||
import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration.EncryptionMethod;
|
||||
|
||||
/**
|
||||
* Object representation of a Guacamole connection, as represented in the
|
||||
* database.
|
||||
*/
|
||||
public class ConnectionModel extends ChildObjectModel {
|
||||
|
||||
/**
|
||||
* The human-readable name associated with this connection.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The name of the protocol to use when connecting to this connection.
|
||||
*/
|
||||
private String protocol;
|
||||
|
||||
/**
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection concurrently, zero if no restriction applies, or null if the
|
||||
* default restrictions should be applied.
|
||||
*/
|
||||
private Integer maxConnections;
|
||||
|
||||
/**
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection concurrently by any one user, zero if no restriction applies,
|
||||
* or null if the default restrictions should be applied.
|
||||
*/
|
||||
private Integer maxConnectionsPerUser;
|
||||
|
||||
/**
|
||||
* The weight of the connection for the purposes of calculating
|
||||
* WLC algorithm. null indicates nothing has been set, and anything less
|
||||
* than 1 eliminates the system from being used for connections.
|
||||
*/
|
||||
private Integer connectionWeight;
|
||||
|
||||
/**
|
||||
* Whether this connection should be reserved for failover. Failover-only
|
||||
* connections within a balancing group are only used when all non-failover
|
||||
* connections are unavailable.
|
||||
*/
|
||||
private boolean failoverOnly;
|
||||
|
||||
/**
|
||||
* The identifiers of all readable sharing profiles associated with this
|
||||
* connection.
|
||||
*/
|
||||
private Set<String> sharingProfileIdentifiers = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* The hostname of the guacd instance to use, or null if the hostname of the
|
||||
* default guacd instance should be used.
|
||||
*/
|
||||
private String proxyHostname;
|
||||
|
||||
/**
|
||||
* The port of the guacd instance to use, or null if the port of the default
|
||||
* guacd instance should be used.
|
||||
*/
|
||||
private Integer proxyPort;
|
||||
|
||||
/**
|
||||
* The encryption method required by the desired guacd instance, or null if
|
||||
* the encryption method of the default guacd instance should be used.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public ConnectionModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name associated with this connection.
|
||||
*
|
||||
* @return
|
||||
* The name associated with this connection.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name associated with this connection.
|
||||
*
|
||||
* @param name
|
||||
* The name to associate with this connection.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the protocol to use when connecting to this
|
||||
* connection.
|
||||
*
|
||||
* @return
|
||||
* The name of the protocol to use when connecting to this connection.
|
||||
*/
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the protocol to use when connecting to this connection.
|
||||
*
|
||||
* @param protocol
|
||||
* The name of the protocol to use when connecting to this connection.
|
||||
*/
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of connections that can be established to
|
||||
* this connection concurrently.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection concurrently, zero if no restriction applies, or null if
|
||||
* the default restrictions should be applied.
|
||||
*/
|
||||
public Integer getMaxConnections() {
|
||||
return maxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of connections that can be established to this
|
||||
* connection concurrently.
|
||||
*
|
||||
* @param maxConnections
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection concurrently, zero if no restriction applies, or null if
|
||||
* the default restrictions should be applied.
|
||||
*/
|
||||
public void setMaxConnections(Integer maxConnections) {
|
||||
this.maxConnections = maxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of connections that can be established to
|
||||
* this connection concurrently by any one user.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection concurrently by any one user, zero if no restriction
|
||||
* applies, or null if the default restrictions should be applied.
|
||||
*/
|
||||
public Integer getMaxConnectionsPerUser() {
|
||||
return maxConnectionsPerUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the connection weight for load balancing.
|
||||
*
|
||||
* @param connectionWeight
|
||||
* The weight of the connection used in load balancing.
|
||||
* The value is not required for the connection (null), and
|
||||
* values less than 1 will prevent the connection from being
|
||||
* used.
|
||||
*/
|
||||
public void setConnectionWeight(Integer connectionWeight) {
|
||||
this.connectionWeight = connectionWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection weight used in applying weighted
|
||||
* load balancing algorithms.
|
||||
*
|
||||
* @return
|
||||
* The connection weight used in applying weighted
|
||||
* load balancing aglorithms.
|
||||
*/
|
||||
public Integer getConnectionWeight() {
|
||||
return connectionWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this connection should be reserved for failover.
|
||||
* Failover-only connections within a balancing group are only used when
|
||||
* all non-failover connections are unavailable.
|
||||
*
|
||||
* @return
|
||||
* true if this connection should be reserved for failover, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isFailoverOnly() {
|
||||
return failoverOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this connection should be reserved for failover.
|
||||
* Failover-only connections within a balancing group are only used when
|
||||
* all non-failover connections are unavailable.
|
||||
*
|
||||
* @param failoverOnly
|
||||
* true if this connection should be reserved for failover, false
|
||||
* otherwise.
|
||||
*/
|
||||
public void setFailoverOnly(boolean failoverOnly) {
|
||||
this.failoverOnly = failoverOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of connections that can be established to this
|
||||
* connection concurrently by any one user.
|
||||
*
|
||||
* @param maxConnectionsPerUser
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection concurrently by any one user, zero if no restriction
|
||||
* applies, or null if the default restrictions should be applied.
|
||||
*/
|
||||
public void setMaxConnectionsPerUser(Integer maxConnectionsPerUser) {
|
||||
this.maxConnectionsPerUser = maxConnectionsPerUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname of the guacd instance to use. If the hostname of the
|
||||
* default guacd instance should be used instead, null is returned.
|
||||
*
|
||||
* @return
|
||||
* The hostname of the guacd instance to use, or null if the hostname
|
||||
* of the default guacd instance should be used.
|
||||
*/
|
||||
public String getProxyHostname() {
|
||||
return proxyHostname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hostname of the guacd instance to use.
|
||||
*
|
||||
* @param proxyHostname
|
||||
* The hostname of the guacd instance to use, or null if the hostname
|
||||
* of the default guacd instance should be used.
|
||||
*/
|
||||
public void setProxyHostname(String proxyHostname) {
|
||||
this.proxyHostname = proxyHostname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port of the guacd instance to use. If the port of the default
|
||||
* guacd instance should be used instead, null is returned.
|
||||
*
|
||||
* @return
|
||||
* The port of the guacd instance to use, or null if the port of the
|
||||
* default guacd instance should be used.
|
||||
*/
|
||||
public Integer getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the port of the guacd instance to use.
|
||||
*
|
||||
* @param proxyPort
|
||||
* The port of the guacd instance to use, or null if the port of the
|
||||
* default guacd instance should be used.
|
||||
*/
|
||||
public void setProxyPort(Integer proxyPort) {
|
||||
this.proxyPort = proxyPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of encryption required by the desired guacd instance.
|
||||
* If the encryption method of the default guacd instance should be used
|
||||
* instead, null is returned.
|
||||
*
|
||||
* @return
|
||||
* The type of encryption required by the desired guacd instance, or
|
||||
* null if the encryption method of the default guacd instance should
|
||||
* be used.
|
||||
*/
|
||||
public EncryptionMethod getProxyEncryptionMethod() {
|
||||
return proxyEncryptionMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of encryption which should be used when connecting to
|
||||
* guacd, if any.
|
||||
*
|
||||
* @param proxyEncryptionMethod
|
||||
* The type of encryption required by the desired guacd instance, or
|
||||
* null if the encryption method of the default guacd instance should
|
||||
* be used.
|
||||
*/
|
||||
public void setProxyEncryptionMethod(EncryptionMethod proxyEncryptionMethod) {
|
||||
this.proxyEncryptionMethod = proxyEncryptionMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifiers of all readable sharing profiles associated with
|
||||
* this connection. This is set only when the connection is queried, and has
|
||||
* no effect when a connection is inserted, updated, or deleted.
|
||||
*
|
||||
* @return
|
||||
* The identifiers of all readable sharing profiles associated with
|
||||
* this connection.
|
||||
*/
|
||||
public Set<String> getSharingProfileIdentifiers() {
|
||||
return sharingProfileIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifiers of all readable sharing profiles associated with
|
||||
* this connection. This should be set only when the connection is queried,
|
||||
* as it has no effect when a connection is inserted, updated, or deleted.
|
||||
*
|
||||
* @param sharingProfileIdentifiers
|
||||
* The identifiers of all readable sharing profiles associated with
|
||||
* this connection.
|
||||
*/
|
||||
public void setSharingProfileIdentifiers(Set<String> 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
|
||||
public String getIdentifier() {
|
||||
|
||||
// If no associated ID, then no associated identifier
|
||||
Integer id = getObjectID();
|
||||
if (id == null)
|
||||
return null;
|
||||
|
||||
// Otherwise, the identifier is the ID as a string
|
||||
return id.toString();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(String identifier) {
|
||||
throw new UnsupportedOperationException("Connection identifiers are derived from IDs. They cannot be set.");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
import java.util.Collection;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Mapper for connection parameter objects.
|
||||
*/
|
||||
public interface ConnectionParameterMapper {
|
||||
|
||||
/**
|
||||
* Returns a collection of all parameters associated with the connection
|
||||
* having the given identifier.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the connection whose parameters are to be
|
||||
* retrieved.
|
||||
*
|
||||
* @return
|
||||
* A collection of all parameters associated with the connection
|
||||
* having the given identifier. This collection will be empty if no
|
||||
* such connection exists.
|
||||
*/
|
||||
Collection<ConnectionParameterModel> select(@Param("identifier") String identifier);
|
||||
|
||||
/**
|
||||
* Inserts each of the parameter model objects in the given collection as
|
||||
* new connection parameters.
|
||||
*
|
||||
* @param parameters
|
||||
* The connection parameters to insert.
|
||||
*
|
||||
* @return
|
||||
* The number of rows inserted.
|
||||
*/
|
||||
int insert(@Param("parameters") Collection<ConnectionParameterModel> parameters);
|
||||
|
||||
/**
|
||||
* Deletes all parameters associated with the connection having the given
|
||||
* identifier.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the connection whose parameters should be
|
||||
* deleted.
|
||||
*
|
||||
* @return
|
||||
* The number of rows deleted.
|
||||
*/
|
||||
int delete(@Param("identifier") String identifier);
|
||||
|
||||
}
|
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
/**
|
||||
* A single parameter name/value pair belonging to a connection.
|
||||
*/
|
||||
public class ConnectionParameterModel {
|
||||
|
||||
/**
|
||||
* The identifier of the connection associated with this parameter.
|
||||
*/
|
||||
private String connectionIdentifier;
|
||||
|
||||
/**
|
||||
* The name of the parameter.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The value the parameter is set to.
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Returns the identifier of the connection associated with this parameter.
|
||||
*
|
||||
* @return
|
||||
* The identifier of the connection associated with this parameter.
|
||||
*/
|
||||
public String getConnectionIdentifier() {
|
||||
return connectionIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifier of the connection associated with this parameter.
|
||||
*
|
||||
* @param connectionIdentifier
|
||||
* The identifier of the connection to associate with this parameter.
|
||||
*/
|
||||
public void setConnectionIdentifier(String connectionIdentifier) {
|
||||
this.connectionIdentifier = connectionIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this parameter.
|
||||
*
|
||||
* @return
|
||||
* The name of this parameter.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this parameter.
|
||||
*
|
||||
* @param name
|
||||
* The name of this parameter.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this parameter.
|
||||
*
|
||||
* @return
|
||||
* The value of this parameter.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this parameter.
|
||||
*
|
||||
* @param value
|
||||
* The value of this parameter.
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
import org.apache.guacamole.auth.jdbc.base.ActivityRecordMapper;
|
||||
|
||||
/**
|
||||
* Mapper for connection record objects.
|
||||
*/
|
||||
public interface ConnectionRecordMapper extends ActivityRecordMapper<ConnectionRecordModel> {}
|
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
|
||||
|
||||
/**
|
||||
* A single connection record representing a past usage of a particular
|
||||
* connection. If the connection was being shared, the sharing profile used to
|
||||
* join the connection is included in the record.
|
||||
*/
|
||||
public class ConnectionRecordModel extends ActivityRecordModel {
|
||||
|
||||
/**
|
||||
* The identifier of the connection associated with this connection record.
|
||||
*/
|
||||
private String connectionIdentifier;
|
||||
|
||||
/**
|
||||
* The name of the connection associated with this connection record.
|
||||
*/
|
||||
private String connectionName;
|
||||
|
||||
/**
|
||||
* The identifier of the sharing profile associated with this connection
|
||||
* record. If no sharing profile was used, or the sharing profile that was
|
||||
* used was deleted, this will be null.
|
||||
*/
|
||||
private String sharingProfileIdentifier;
|
||||
|
||||
/**
|
||||
* The name of the sharing profile associated with this connection record.
|
||||
* If no sharing profile was used, this will be null. If the sharing profile
|
||||
* that was used was deleted, this will still contain the name of the
|
||||
* sharing profile at the time that the connection was used.
|
||||
*/
|
||||
private String sharingProfileName;
|
||||
|
||||
/**
|
||||
* Returns the identifier of the connection associated with this connection
|
||||
* record.
|
||||
*
|
||||
* @return
|
||||
* The identifier of the connection associated with this connection
|
||||
* record.
|
||||
*/
|
||||
public String getConnectionIdentifier() {
|
||||
return connectionIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifier of the connection associated with this connection
|
||||
* record.
|
||||
*
|
||||
* @param connectionIdentifier
|
||||
* The identifier of the connection to associate with this connection
|
||||
* record.
|
||||
*/
|
||||
public void setConnectionIdentifier(String connectionIdentifier) {
|
||||
this.connectionIdentifier = connectionIdentifier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the connection associated with this connection
|
||||
* record.
|
||||
*
|
||||
* @return
|
||||
* The name of the connection associated with this connection
|
||||
* record.
|
||||
*/
|
||||
public String getConnectionName() {
|
||||
return connectionName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the name of the connection associated with this connection
|
||||
* record.
|
||||
*
|
||||
* @param connectionName
|
||||
* The name of the connection to associate with this connection
|
||||
* record.
|
||||
*/
|
||||
public void setConnectionName(String connectionName) {
|
||||
this.connectionName = connectionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of the sharing profile associated with this
|
||||
* connection record. If no sharing profile was used, or the sharing profile
|
||||
* that was used was deleted, this will be null.
|
||||
*
|
||||
* @return
|
||||
* The identifier of the sharing profile associated with this connection
|
||||
* record, or null if no sharing profile was used or if the sharing
|
||||
* profile that was used was deleted.
|
||||
*/
|
||||
public String getSharingProfileIdentifier() {
|
||||
return sharingProfileIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifier of the sharing profile associated with this
|
||||
* connection record. If no sharing profile was used, this should be null.
|
||||
*
|
||||
* @param sharingProfileIdentifier
|
||||
* The identifier of the sharing profile associated with this
|
||||
* connection record, or null if no sharing profile was used.
|
||||
*/
|
||||
public void setSharingProfileIdentifier(String sharingProfileIdentifier) {
|
||||
this.sharingProfileIdentifier = sharingProfileIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human-readable name of the sharing profile associated with this
|
||||
* connection record. If no sharing profile was used, this will be null.
|
||||
*
|
||||
* @return
|
||||
* The human-readable name of the sharing profile associated with this
|
||||
* connection record, or null if no sharing profile was used.
|
||||
*/
|
||||
public String getSharingProfileName() {
|
||||
return sharingProfileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the human-readable name of the sharing profile associated with this
|
||||
* connection record. If no sharing profile was used, this should be null.
|
||||
*
|
||||
* @param sharingProfileName
|
||||
* The human-readable name of the sharing profile associated with this
|
||||
* connection record, or null if no sharing profile was used.
|
||||
*/
|
||||
public void setSharingProfileName(String sharingProfileName) {
|
||||
this.sharingProfileName = sharingProfileName;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
|
||||
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecordSet;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.ConnectionRecord;
|
||||
|
||||
/**
|
||||
* A JDBC implementation of ActivityRecordSet for ConnectionRecords. Calls to
|
||||
* asCollection() will query connection history records from the database. Which
|
||||
* records are returned will be determined by the values passed in earlier.
|
||||
*/
|
||||
public class ConnectionRecordSet extends ModeledActivityRecordSet<ConnectionRecord> {
|
||||
|
||||
/**
|
||||
* The namespace for the type 3 UUIDs generated for connection history
|
||||
* records. This UUID namespace is itself a type 3 UUID within the "ns:OID"
|
||||
* namespace for the OID "1.3.6.1.4.1.18060.18.2.1.2", which has been
|
||||
* specifically allocated for Apache Guacamole database connection
|
||||
* history records.
|
||||
*/
|
||||
public static final UUID UUID_NAMESPACE = UUID.fromString("8b55f070-95f4-3d31-93ee-9c5845e7aa40");
|
||||
|
||||
/**
|
||||
* Service for managing connection objects.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionService connectionService;
|
||||
|
||||
/**
|
||||
* The identifier of the connection to which this record set should be
|
||||
* limited, if any. If null, the set should contain all records readable
|
||||
* by the user making the request.
|
||||
*/
|
||||
private String identifier = null;
|
||||
|
||||
/**
|
||||
* Initializes this object, associating it with the current authenticated
|
||||
* user and connection identifier.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user that created or retrieved this object.
|
||||
*
|
||||
* @param identifier
|
||||
* The connection identifier to which this record set should be limited,
|
||||
* or null if the record set should contain all records readable by the
|
||||
* currentUser.
|
||||
*/
|
||||
protected void init(ModeledAuthenticatedUser currentUser, String identifier) {
|
||||
super.init(currentUser);
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ConnectionRecord> retrieveHistory(
|
||||
AuthenticatedUser user, String recordIdentifier,
|
||||
Set<ActivityRecordSearchTerm> requiredContents,
|
||||
List<ActivityRecordSortPredicate> sortPredicates,
|
||||
int limit) throws GuacamoleException {
|
||||
|
||||
// Retrieve history from database
|
||||
return connectionService.retrieveHistory(identifier, getCurrentUser(),
|
||||
recordIdentifier, requiredContents, sortPredicates, limit);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,550 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleClientException;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
|
||||
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.language.TranslatableGuacamoleClientOverrunException;
|
||||
import org.apache.guacamole.language.TranslatableMessage;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.Connection;
|
||||
import org.apache.guacamole.net.auth.ConnectionRecord;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
|
||||
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* manipulating connections.
|
||||
*/
|
||||
public class ConnectionService extends ModeledChildDirectoryObjectService<ModeledConnection, Connection, ConnectionModel> {
|
||||
|
||||
/**
|
||||
* Mapper for accessing connections.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionMapper connectionMapper;
|
||||
|
||||
/**
|
||||
* Mapper for manipulating connection permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionPermissionMapper connectionPermissionMapper;
|
||||
|
||||
/**
|
||||
* Mapper for accessing connection parameters.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionParameterMapper parameterMapper;
|
||||
|
||||
/**
|
||||
* Mapper for accessing connection history.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionRecordMapper connectionRecordMapper;
|
||||
|
||||
/**
|
||||
* Provider for creating connections.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<ModeledConnection> connectionProvider;
|
||||
|
||||
/**
|
||||
* The server environment for retrieving configuration.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Service for creating and tracking tunnels.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleTunnelService tunnelService;
|
||||
|
||||
/**
|
||||
* Known limit for the size of the connection parameter values.
|
||||
*/
|
||||
private static final int CONNECTION_PARAMETER_VALUE_LIMIT = 4096;
|
||||
|
||||
@Override
|
||||
protected ModeledDirectoryObjectMapper<ConnectionModel> getObjectMapper() {
|
||||
return connectionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionMapper getPermissionMapper() {
|
||||
return connectionPermissionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ModeledConnection getObjectInstance(ModeledAuthenticatedUser currentUser,
|
||||
ConnectionModel model) {
|
||||
ModeledConnection connection = connectionProvider.get();
|
||||
connection.init(currentUser, model);
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectionModel getModelInstance(ModeledAuthenticatedUser currentUser,
|
||||
final Connection object) {
|
||||
|
||||
// Create new ModeledConnection backed by blank model
|
||||
ConnectionModel model = new ConnectionModel();
|
||||
ModeledConnection connection = getObjectInstance(currentUser, model);
|
||||
|
||||
// Set model contents through ModeledConnection, copying the provided connection
|
||||
connection.setParentIdentifier(object.getParentIdentifier());
|
||||
connection.setName(object.getName());
|
||||
connection.setConfiguration(object.getConfiguration());
|
||||
connection.setAttributes(object.getAttributes());
|
||||
|
||||
return model;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasCreatePermission(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Return whether user has explicit connection creation permission
|
||||
SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
|
||||
return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Return permissions related to connections
|
||||
return user.getUser().getEffectivePermissions().getConnectionPermissions();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Connections are contained by connection groups
|
||||
return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that all connection parameter values are within the expected size limit.
|
||||
*
|
||||
* @param parameters
|
||||
* The map of connection parameter name/value pairs to validate.
|
||||
*
|
||||
* @throws GuacamoleClientException
|
||||
* If any of the parameter values exceed the defined limit.
|
||||
*/
|
||||
private void validateParameters(Map<String, String> parameters) throws GuacamoleClientException {
|
||||
// Iterate through each parameter to validate its size
|
||||
for (Map.Entry<String, String> parameter : parameters.entrySet()) {
|
||||
String value = parameter.getValue();
|
||||
|
||||
// Check if parameter value exceeds size limit
|
||||
if (value != null && value.length() > CONNECTION_PARAMETER_VALUE_LIMIT) {
|
||||
|
||||
Map<String, Object> vars = new HashMap<>();
|
||||
vars.put("MAX_SIZE", CONNECTION_PARAMETER_VALUE_LIMIT);
|
||||
vars.put("PARAMETER_NAME", parameter.getKey());
|
||||
|
||||
// Create a translatable message with the error key and substitution variables
|
||||
TranslatableMessage translatableMessage = new TranslatableMessage(
|
||||
"CONNECTION_PARAMETERS.DATABASE_PARAMETER_VALUE_TOO_LONG",
|
||||
vars
|
||||
);
|
||||
|
||||
throw new TranslatableGuacamoleClientOverrunException(
|
||||
"The value provided for connection parameter \"" + parameter.getKey() +
|
||||
"\" exceeds the maximum allowed length.",
|
||||
translatableMessage
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user,
|
||||
Connection object, ConnectionModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Validate parameters before saving
|
||||
validateParameters(object.getConfiguration().getParameters());
|
||||
|
||||
super.beforeCreate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
throw new GuacamoleClientException("Connection names must not be blank.");
|
||||
|
||||
// Do not attempt to create duplicate connections
|
||||
ConnectionModel existing = connectionMapper.selectOneByName(model.getParentIdentifier(), model.getName());
|
||||
if (existing != null)
|
||||
throw new GuacamoleClientException("The connection \"" + model.getName() + "\" already exists.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
ModeledConnection object, ConnectionModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Validate parameters before saving
|
||||
validateParameters(object.getConfiguration().getParameters());
|
||||
|
||||
super.beforeUpdate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
throw new GuacamoleClientException("Connection names must not be blank.");
|
||||
|
||||
// Check whether such a connection is already present
|
||||
ConnectionModel existing = connectionMapper.selectOneByName(model.getParentIdentifier(), model.getName());
|
||||
if (existing != null) {
|
||||
|
||||
// If the specified name matches a DIFFERENT existing connection, the update cannot continue
|
||||
if (!existing.getObjectID().equals(model.getObjectID()))
|
||||
throw new GuacamoleClientException("The connection \"" + model.getName() + "\" already exists.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an arbitrary Guacamole connection, produces a collection of
|
||||
* parameter model objects containing the name/value pairs of that
|
||||
* connection's parameters.
|
||||
*
|
||||
* @param connection
|
||||
* The connection whose configuration should be used to produce the
|
||||
* collection of parameter models.
|
||||
*
|
||||
* @return
|
||||
* A collection of parameter models containing the name/value pairs
|
||||
* of the given connection's parameters.
|
||||
*/
|
||||
private Collection<ConnectionParameterModel> getParameterModels(ModeledConnection connection) {
|
||||
|
||||
Map<String, String> parameters = connection.getConfiguration().getParameters();
|
||||
|
||||
// Convert parameters to model objects
|
||||
Collection<ConnectionParameterModel> parameterModels = new ArrayList<>(parameters.size());
|
||||
for (Map.Entry<String, String> parameterEntry : parameters.entrySet()) {
|
||||
|
||||
// Get parameter name and value
|
||||
String name = parameterEntry.getKey();
|
||||
String value = parameterEntry.getValue();
|
||||
|
||||
// There is no need to insert empty parameters
|
||||
if (value == null || value.isEmpty())
|
||||
continue;
|
||||
|
||||
// Produce model object from parameter
|
||||
ConnectionParameterModel model = new ConnectionParameterModel();
|
||||
model.setConnectionIdentifier(connection.getIdentifier());
|
||||
model.setName(name);
|
||||
model.setValue(value);
|
||||
|
||||
// Add model to list
|
||||
parameterModels.add(model);
|
||||
|
||||
}
|
||||
|
||||
return parameterModels;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModeledConnection createObject(ModeledAuthenticatedUser user, Connection object)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Create connection
|
||||
ModeledConnection connection = super.createObject(user, object);
|
||||
connection.setConfiguration(object.getConfiguration());
|
||||
|
||||
// Insert new parameters, if any
|
||||
Collection<ConnectionParameterModel> parameterModels = getParameterModels(connection);
|
||||
if (!parameterModels.isEmpty())
|
||||
parameterMapper.insert(parameterModels);
|
||||
|
||||
return connection;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateObject(ModeledAuthenticatedUser user, ModeledConnection object)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Update connection
|
||||
super.updateObject(user, object);
|
||||
|
||||
// Replace existing parameters with new parameters, if any
|
||||
Collection<ConnectionParameterModel> parameterModels = getParameterModels(object);
|
||||
parameterMapper.delete(object.getIdentifier());
|
||||
if (!parameterModels.isEmpty())
|
||||
parameterMapper.insert(parameterModels);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of all identifiers for all connections within the
|
||||
* connection group having the given identifier. Only connections that the
|
||||
* user has read access to will be returned.
|
||||
*
|
||||
* Permission to read the connection group having the given identifier is
|
||||
* NOT checked.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the identifiers.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the parent connection group, or null to check the
|
||||
* root connection group.
|
||||
*
|
||||
* @return
|
||||
* The set of all identifiers for all connections in the connection
|
||||
* group having the given identifier that the user has read access to.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while reading identifiers.
|
||||
*/
|
||||
public Set<String> getIdentifiersWithin(ModeledAuthenticatedUser user,
|
||||
String identifier)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Bypass permission checks if the user is privileged
|
||||
if (user.isPrivileged())
|
||||
return connectionMapper.selectIdentifiersWithin(identifier);
|
||||
|
||||
// Otherwise only return explicitly readable identifiers
|
||||
else
|
||||
return connectionMapper.selectReadableIdentifiersWithin(
|
||||
user.getUser().getModel(), identifier,
|
||||
user.getEffectiveUserGroups(),
|
||||
getCaseSensitivity());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all parameters visible to the given user and associated with
|
||||
* the connection having the given identifier. If the given user has no
|
||||
* access to such parameters, or no such connection exists, the returned
|
||||
* map will be empty.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving connection parameters.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the connection whose parameters are being
|
||||
* retrieved.
|
||||
*
|
||||
* @return
|
||||
* A new map of all parameter name/value pairs that the given user has
|
||||
* access to.
|
||||
*/
|
||||
public Map<String, String> retrieveParameters(ModeledAuthenticatedUser user,
|
||||
String identifier) {
|
||||
|
||||
Map<String, String> parameterMap = new HashMap<>();
|
||||
|
||||
// Determine whether we have permission to read parameters
|
||||
boolean canRetrieveParameters;
|
||||
try {
|
||||
canRetrieveParameters = hasObjectPermission(user, identifier,
|
||||
ObjectPermission.Type.UPDATE);
|
||||
}
|
||||
|
||||
// Provide empty (but mutable) map if unable to check permissions
|
||||
catch (GuacamoleException e) {
|
||||
return parameterMap;
|
||||
}
|
||||
|
||||
// Populate parameter map if we have permission to do so
|
||||
if (canRetrieveParameters) {
|
||||
for (ConnectionParameterModel parameter : parameterMapper.select(identifier))
|
||||
parameterMap.put(parameter.getName(), parameter.getValue());
|
||||
}
|
||||
|
||||
return parameterMap;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a connection records 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 ConnectionRecord getObjectInstance(ConnectionRecordModel model) {
|
||||
return new ModeledConnectionRecord(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of connection records objects which are backed by the
|
||||
* models in the given list.
|
||||
*
|
||||
* @param models
|
||||
* The model objects to use to back the connection record objects
|
||||
* within the returned list.
|
||||
*
|
||||
* @return
|
||||
* A list of connection record objects which are backed by the models
|
||||
* in the given list.
|
||||
*/
|
||||
protected List<ConnectionRecord> getObjectInstances(List<ConnectionRecordModel> models) {
|
||||
|
||||
// Create new list of records by manually converting each model
|
||||
List<ConnectionRecord> objects = new ArrayList<>(models.size());
|
||||
for (ConnectionRecordModel model : models)
|
||||
objects.add(getObjectInstance(model));
|
||||
|
||||
return objects;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the connection history records matching the given criteria.
|
||||
* Retrieves up to <code>limit</code> connection history records matching
|
||||
* the given terms and sorted by the given predicates. Only history records
|
||||
* associated with data that the given user can read are returned.
|
||||
*
|
||||
* @param identifier
|
||||
* The optional connection identifier for which history records should
|
||||
* be retrieved, or null if all readable records should be retrieved.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the connection history.
|
||||
*
|
||||
* @param recordIdentifier
|
||||
* The identifier of the specific history record to retrieve, if not
|
||||
* all matching records. Search terms, etc. will still be applied to
|
||||
* the single record.
|
||||
*
|
||||
* @param requiredContents
|
||||
* The search terms that must be contained somewhere within each of the
|
||||
* returned records.
|
||||
*
|
||||
* @param sortPredicates
|
||||
* A list of predicates to sort the returned records by, in order of
|
||||
* priority.
|
||||
*
|
||||
* @param limit
|
||||
* The maximum number of records that should be returned.
|
||||
*
|
||||
* @return
|
||||
* The connection history of the given connection, including any
|
||||
* active connections.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to read the connection history is denied.
|
||||
*/
|
||||
public List<ConnectionRecord> retrieveHistory(String identifier,
|
||||
ModeledAuthenticatedUser user, String recordIdentifier,
|
||||
Collection<ActivityRecordSearchTerm> requiredContents,
|
||||
List<ActivityRecordSortPredicate> sortPredicates, int limit)
|
||||
throws GuacamoleException {
|
||||
|
||||
List<ConnectionRecordModel> searchResults;
|
||||
|
||||
// Bypass permission checks if the user is privileged or has System-level audit permissions
|
||||
if (user.isPrivileged() || user.getUser().getEffectivePermissions().getSystemPermissions().hasPermission(SystemPermission.Type.AUDIT))
|
||||
searchResults = connectionRecordMapper.search(identifier,
|
||||
recordIdentifier, requiredContents, sortPredicates, limit,
|
||||
getCaseSensitivity());
|
||||
|
||||
// Otherwise only return explicitly readable history records
|
||||
else
|
||||
searchResults = connectionRecordMapper.searchReadable(identifier,
|
||||
user.getUser().getModel(), recordIdentifier,
|
||||
requiredContents, sortPredicates, limit,
|
||||
user.getEffectiveUserGroups(),
|
||||
getCaseSensitivity());
|
||||
|
||||
return getObjectInstances(searchResults);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the given connection as the given user, using the given
|
||||
* client information. If the user does not have permission to read the
|
||||
* connection, permission will be denied.
|
||||
*
|
||||
* @param user
|
||||
* The user connecting to the connection.
|
||||
*
|
||||
* @param connection
|
||||
* The connection being connected to.
|
||||
*
|
||||
* @param info
|
||||
* Information associated with the connecting client.
|
||||
*
|
||||
* @param tokens
|
||||
* A Map containing the token names and corresponding values to be
|
||||
* applied as parameter tokens when establishing the connection.
|
||||
*
|
||||
* @return
|
||||
* A connected GuacamoleTunnel associated with a newly-established
|
||||
* connection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to connect to this connection is denied.
|
||||
*/
|
||||
public GuacamoleTunnel connect(ModeledAuthenticatedUser user,
|
||||
ModeledConnection connection, GuacamoleClientInformation info,
|
||||
Map<String, String> tokens) throws GuacamoleException {
|
||||
|
||||
// Connect only if READ permission is granted
|
||||
if (hasObjectPermission(user, connection.getIdentifier(), ObjectPermission.Type.READ))
|
||||
return tunnelService.getGuacamoleTunnel(user, connection, info, tokens);
|
||||
|
||||
// The user does not have permission to connect
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,508 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObject;
|
||||
import org.apache.guacamole.form.BooleanField;
|
||||
import org.apache.guacamole.form.EnumField;
|
||||
import org.apache.guacamole.form.Field;
|
||||
import org.apache.guacamole.form.Form;
|
||||
import org.apache.guacamole.form.NumericField;
|
||||
import org.apache.guacamole.form.TextField;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.ActivityRecordSet;
|
||||
import org.apache.guacamole.net.auth.Connection;
|
||||
import org.apache.guacamole.net.auth.ConnectionRecord;
|
||||
import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration;
|
||||
import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration.EncryptionMethod;
|
||||
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||
import org.apache.guacamole.protocol.GuacamoleConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* An implementation of the Connection object which is backed by a database
|
||||
* model.
|
||||
*/
|
||||
public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionModel>
|
||||
implements Connection {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(ModeledConnection.class);
|
||||
|
||||
/**
|
||||
* The name of the attribute which overrides the hostname used to connect
|
||||
* to guacd for this connection.
|
||||
*/
|
||||
public static final String GUACD_HOSTNAME_NAME = "guacd-hostname";
|
||||
|
||||
/**
|
||||
* The name of the attribute which overrides the port used to connect to
|
||||
* guacd for this connection.
|
||||
*/
|
||||
public static final String GUACD_PORT_NAME = "guacd-port";
|
||||
|
||||
/**
|
||||
* The name of the attribute which overrides the encryption method used to
|
||||
* connect to guacd for this connection.
|
||||
*/
|
||||
public static final String GUACD_ENCRYPTION_NAME = "guacd-encryption";
|
||||
|
||||
/**
|
||||
* The value specified for the "guacd-encryption" attribute if encryption
|
||||
* should not be used to connect to guacd.
|
||||
*/
|
||||
public static final String GUACD_ENCRYPTION_VALUE_NONE = "none";
|
||||
|
||||
/**
|
||||
* The value specified for the "guacd-encryption" attribute if SSL/TLS
|
||||
* encryption should be used to connect to guacd.
|
||||
*/
|
||||
public static final String GUACD_ENCRYPTION_VALUE_SSL = "ssl";
|
||||
|
||||
/**
|
||||
* All attributes which describe the configuration of the guacd instance
|
||||
* which will be used to connect to the remote desktop described by this
|
||||
* connection.
|
||||
*/
|
||||
public static final Form GUACD_PARAMETERS = new Form("guacd", Arrays.<Field>asList(
|
||||
new TextField(GUACD_HOSTNAME_NAME),
|
||||
new NumericField(GUACD_PORT_NAME),
|
||||
new EnumField(GUACD_ENCRYPTION_NAME, Arrays.asList(
|
||||
"",
|
||||
GUACD_ENCRYPTION_VALUE_NONE,
|
||||
GUACD_ENCRYPTION_VALUE_SSL
|
||||
))
|
||||
));
|
||||
|
||||
/**
|
||||
* The name of the attribute which controls the maximum number of
|
||||
* concurrent connections.
|
||||
*/
|
||||
public static final String MAX_CONNECTIONS_NAME = "max-connections";
|
||||
|
||||
/**
|
||||
* The name of the attribute which controls the maximum number of
|
||||
* concurrent connections per user.
|
||||
*/
|
||||
public static final String MAX_CONNECTIONS_PER_USER_NAME = "max-connections-per-user";
|
||||
|
||||
/**
|
||||
* The connection weight attribute used for weighted load balancing algorithms.
|
||||
*/
|
||||
public static final String CONNECTION_WEIGHT = "weight";
|
||||
|
||||
/**
|
||||
* The name of the attribute which controls whether the connection should
|
||||
* be used as a spare only (all other non-spare connections within the same
|
||||
* balancing group should be preferred).
|
||||
*/
|
||||
public static final String FAILOVER_ONLY_NAME = "failover-only";
|
||||
|
||||
/**
|
||||
* All attributes related to restricting user accounts, within a logical
|
||||
* form.
|
||||
*/
|
||||
public static final Form CONCURRENCY_LIMITS = new Form("concurrency", Arrays.<Field>asList(
|
||||
new NumericField(MAX_CONNECTIONS_NAME),
|
||||
new NumericField(MAX_CONNECTIONS_PER_USER_NAME)
|
||||
));
|
||||
|
||||
/**
|
||||
* All attributes related to load balancing in a logical form.
|
||||
*/
|
||||
public static final Form LOAD_BALANCING = new Form("load-balancing", Arrays.<Field>asList(
|
||||
new NumericField(CONNECTION_WEIGHT),
|
||||
new BooleanField(FAILOVER_ONLY_NAME, "true")
|
||||
));
|
||||
|
||||
/**
|
||||
* All possible attributes of connection objects organized as individual,
|
||||
* logical forms.
|
||||
*/
|
||||
public static final Collection<Form> ATTRIBUTES = Collections.unmodifiableCollection(Arrays.asList(
|
||||
CONCURRENCY_LIMITS,
|
||||
LOAD_BALANCING,
|
||||
GUACD_PARAMETERS
|
||||
));
|
||||
|
||||
/**
|
||||
* The names of all attributes which are explicitly supported by this
|
||||
* extension's Connection objects.
|
||||
*/
|
||||
public static final Set<String> ATTRIBUTE_NAMES =
|
||||
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
|
||||
GUACD_HOSTNAME_NAME,
|
||||
GUACD_PORT_NAME,
|
||||
GUACD_ENCRYPTION_NAME,
|
||||
MAX_CONNECTIONS_NAME,
|
||||
MAX_CONNECTIONS_PER_USER_NAME,
|
||||
CONNECTION_WEIGHT,
|
||||
FAILOVER_ONLY_NAME
|
||||
)));
|
||||
|
||||
/**
|
||||
* The environment of the Guacamole server.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Service for managing connections.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionService connectionService;
|
||||
|
||||
/**
|
||||
* Service for creating and tracking tunnels.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleTunnelService tunnelService;
|
||||
|
||||
/**
|
||||
* Provider for lazy-loaded, permission-controlled configurations.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<ModeledGuacamoleConfiguration> configProvider;
|
||||
|
||||
/**
|
||||
* Provider for creating connection record sets.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<ConnectionRecordSet> connectionRecordSetProvider;
|
||||
|
||||
/**
|
||||
* The manually-set GuacamoleConfiguration, if any.
|
||||
*/
|
||||
private GuacamoleConfiguration config = null;
|
||||
|
||||
/**
|
||||
* Creates a new, empty ModeledConnection.
|
||||
*/
|
||||
public ModeledConnection() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getModel().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
getModel().setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleConfiguration getConfiguration() {
|
||||
|
||||
// If configuration has been manually set, return that
|
||||
if (config != null)
|
||||
return config;
|
||||
|
||||
// Otherwise, return permission-controlled configuration
|
||||
ModeledGuacamoleConfiguration restrictedConfig = configProvider.get();
|
||||
restrictedConfig.init(getCurrentUser(), getModel());
|
||||
return restrictedConfig;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfiguration(GuacamoleConfiguration config) {
|
||||
|
||||
// Store manually-set configuration internally
|
||||
this.config = config;
|
||||
|
||||
// Update model
|
||||
getModel().setProtocol(config.getProtocol());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSharingProfileIdentifiers()
|
||||
throws GuacamoleException {
|
||||
return getModel().getSharingProfileIdentifiers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getLastActive() {
|
||||
return getModel().getLastActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityRecordSet<ConnectionRecord> getConnectionHistory()
|
||||
throws GuacamoleException {
|
||||
ConnectionRecordSet connectionRecordSet = connectionRecordSetProvider.get();
|
||||
connectionRecordSet.init(getCurrentUser(), this.getIdentifier());
|
||||
return connectionRecordSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleTunnel connect(GuacamoleClientInformation info,
|
||||
Map<String, String> tokens) throws GuacamoleException {
|
||||
return connectionService.connect(getCurrentUser(), this, info, tokens);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActiveConnections() {
|
||||
return tunnelService.getActiveConnections(this).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedAttributeNames() {
|
||||
return ATTRIBUTE_NAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
|
||||
// Include any defined arbitrary attributes
|
||||
Map<String, String> attributes = super.getAttributes();
|
||||
|
||||
// Set connection limit attribute
|
||||
attributes.put(MAX_CONNECTIONS_NAME, NumericField.format(getModel().getMaxConnections()));
|
||||
|
||||
// Set per-user connection limit attribute
|
||||
attributes.put(MAX_CONNECTIONS_PER_USER_NAME, NumericField.format(getModel().getMaxConnectionsPerUser()));
|
||||
|
||||
// Set guacd (proxy) hostname and port
|
||||
attributes.put(GUACD_HOSTNAME_NAME, getModel().getProxyHostname());
|
||||
attributes.put(GUACD_PORT_NAME, NumericField.format(getModel().getProxyPort()));
|
||||
|
||||
// Set guacd (proxy) encryption method
|
||||
EncryptionMethod encryptionMethod = getModel().getProxyEncryptionMethod();
|
||||
if (encryptionMethod == null)
|
||||
attributes.put(GUACD_ENCRYPTION_NAME, null);
|
||||
|
||||
else {
|
||||
switch (encryptionMethod) {
|
||||
|
||||
// Unencrypted
|
||||
case NONE:
|
||||
attributes.put(GUACD_ENCRYPTION_NAME, GUACD_ENCRYPTION_VALUE_NONE);
|
||||
break;
|
||||
|
||||
// SSL / TLS encryption
|
||||
case SSL:
|
||||
attributes.put(GUACD_ENCRYPTION_NAME, GUACD_ENCRYPTION_VALUE_SSL);
|
||||
break;
|
||||
|
||||
// Unimplemented / unspecified
|
||||
default:
|
||||
attributes.put(GUACD_ENCRYPTION_NAME, null);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Set connection weight
|
||||
attributes.put(CONNECTION_WEIGHT, NumericField.format(getModel().getConnectionWeight()));
|
||||
|
||||
// Set whether connection is failover-only
|
||||
attributes.put(FAILOVER_ONLY_NAME, getModel().isFailoverOnly() ? "true" : null);
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttributes(Map<String, String> attributes) {
|
||||
|
||||
// Set arbitrary attributes
|
||||
super.setAttributes(attributes);
|
||||
|
||||
// Translate connection limit attribute
|
||||
try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); }
|
||||
catch (NumberFormatException e) {
|
||||
logger.warn("Not setting maximum connections: {}", e.getMessage());
|
||||
logger.debug("Unable to parse numeric attribute.", e);
|
||||
}
|
||||
|
||||
// Translate per-user connection limit attribute
|
||||
try { getModel().setMaxConnectionsPerUser(NumericField.parse(attributes.get(MAX_CONNECTIONS_PER_USER_NAME))); }
|
||||
catch (NumberFormatException e) {
|
||||
logger.warn("Not setting maximum connections per user: {}", e.getMessage());
|
||||
logger.debug("Unable to parse numeric attribute.", e);
|
||||
}
|
||||
|
||||
// Translate guacd hostname
|
||||
getModel().setProxyHostname(TextField.parse(attributes.get(GUACD_HOSTNAME_NAME)));
|
||||
|
||||
// Translate guacd port
|
||||
try { getModel().setProxyPort(NumericField.parse(attributes.get(GUACD_PORT_NAME))); }
|
||||
catch (NumberFormatException e) {
|
||||
logger.warn("Not setting guacd port: {}", e.getMessage());
|
||||
logger.debug("Unable to parse numeric attribute.", e);
|
||||
}
|
||||
|
||||
// Translate guacd encryption method
|
||||
String encryptionMethod = attributes.get(GUACD_ENCRYPTION_NAME);
|
||||
|
||||
// Unencrypted
|
||||
if (GUACD_ENCRYPTION_VALUE_NONE.equals(encryptionMethod))
|
||||
getModel().setProxyEncryptionMethod(EncryptionMethod.NONE);
|
||||
|
||||
// SSL / TLS
|
||||
else if (GUACD_ENCRYPTION_VALUE_SSL.equals(encryptionMethod))
|
||||
getModel().setProxyEncryptionMethod(EncryptionMethod.SSL);
|
||||
|
||||
// Unimplemented / unspecified
|
||||
else
|
||||
getModel().setProxyEncryptionMethod(null);
|
||||
|
||||
// Translate connection weight attribute
|
||||
try { getModel().setConnectionWeight(NumericField.parse(attributes.get(CONNECTION_WEIGHT))); }
|
||||
catch (NumberFormatException e) {
|
||||
logger.warn("Not setting the connection weight: {}", e.getMessage());
|
||||
logger.debug("Unable to parse numeric attribute.", e);
|
||||
}
|
||||
|
||||
// Translate failover-only attribute
|
||||
getModel().setFailoverOnly("true".equals(attributes.get(FAILOVER_ONLY_NAME)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of connections that should be allowed to this
|
||||
* connection overall. If no limit applies, zero is returned.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of connections that should be allowed to this
|
||||
* connection overall, or zero if no limit applies.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while parsing the concurrency limit properties
|
||||
* specified within guacamole.properties.
|
||||
*/
|
||||
public int getMaxConnections() throws GuacamoleException {
|
||||
|
||||
// Pull default from environment if connection limit is unset
|
||||
Integer value = getModel().getMaxConnections();
|
||||
if (value == null)
|
||||
return environment.getDefaultMaxConnections();
|
||||
|
||||
// Otherwise use defined value
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of connections that should be allowed to this
|
||||
* connection for any individual user. If no limit applies, zero is
|
||||
* returned.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of connections that should be allowed to this
|
||||
* connection for any individual user, or zero if no limit applies.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while parsing the concurrency limit properties
|
||||
* specified within guacamole.properties.
|
||||
*/
|
||||
public int getMaxConnectionsPerUser() throws GuacamoleException {
|
||||
|
||||
// Pull default from environment if per-user connection limit is unset
|
||||
Integer value = getModel().getMaxConnectionsPerUser();
|
||||
if (value == null)
|
||||
return environment.getDefaultMaxConnectionsPerUser();
|
||||
|
||||
// Otherwise use defined value
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connection information which should be used to connect to
|
||||
* guacd when establishing a connection to the remote desktop described by
|
||||
* this connection. If no such information is defined for this specific
|
||||
* remote desktop connection, the default guacd connection information will
|
||||
* be used instead, as defined by JDBCEnvironment.
|
||||
*
|
||||
* @return
|
||||
* The connection information which should be used to connect to guacd
|
||||
* when establishing a connection to the remote desktop described by
|
||||
* this connection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the connection information for guacd cannot be parsed.
|
||||
*/
|
||||
public GuacamoleProxyConfiguration getGuacamoleProxyConfiguration()
|
||||
throws GuacamoleException {
|
||||
|
||||
// Retrieve default proxy configuration from environment
|
||||
GuacamoleProxyConfiguration defaultConfig = environment.getDefaultGuacamoleProxyConfiguration();
|
||||
|
||||
// Retrieve proxy configuration overrides from model
|
||||
String hostname = getModel().getProxyHostname();
|
||||
Integer port = getModel().getProxyPort();
|
||||
EncryptionMethod encryptionMethod = getModel().getProxyEncryptionMethod();
|
||||
|
||||
// Produce new proxy configuration from model, using defaults where unspecified
|
||||
return new GuacamoleProxyConfiguration(
|
||||
hostname != null ? hostname : defaultConfig.getHostname(),
|
||||
port != null ? port : defaultConfig.getPort(),
|
||||
encryptionMethod != null ? encryptionMethod : defaultConfig.getEncryptionMethod()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the weight of the connection used in applying weighted
|
||||
* load balancing algorithms, or a default of 1 if the
|
||||
* attribute is undefined.
|
||||
*
|
||||
* @return
|
||||
* The weight of the connection used in applying weighted
|
||||
* load balancing algorithms.
|
||||
*/
|
||||
public int getConnectionWeight() {
|
||||
|
||||
Integer connectionWeight = getModel().getConnectionWeight();
|
||||
if (connectionWeight == null)
|
||||
return 1;
|
||||
return connectionWeight;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this connection should be reserved for failover.
|
||||
* Failover-only connections within a balancing group are only used when
|
||||
* all non-failover connections are unavailable.
|
||||
*
|
||||
* @return
|
||||
* true if this connection should be reserved for failover, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isFailoverOnly() {
|
||||
return getModel().isFailoverOnly();
|
||||
}
|
||||
|
||||
}
|
@@ -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.connection;
|
||||
|
||||
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord;
|
||||
import org.apache.guacamole.net.auth.ConnectionRecord;
|
||||
|
||||
/**
|
||||
* A ConnectionRecord which is backed by a database model.
|
||||
*/
|
||||
public class ModeledConnectionRecord extends ModeledActivityRecord
|
||||
implements ConnectionRecord {
|
||||
|
||||
/**
|
||||
* The model object backing this connection record.
|
||||
*/
|
||||
private final ConnectionRecordModel model;
|
||||
|
||||
/**
|
||||
* Creates a new ModeledConnectionRecord 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 connection record.
|
||||
*/
|
||||
public ModeledConnectionRecord(ConnectionRecordModel model) {
|
||||
super(ConnectionRecordSet.UUID_NAMESPACE, model);
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectionIdentifier() {
|
||||
return model.getConnectionIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectionName() {
|
||||
return model.getConnectionName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSharingProfileIdentifier() {
|
||||
return model.getSharingProfileIdentifier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSharingProfileName() {
|
||||
return model.getSharingProfileName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionRecordModel getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.connection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Map;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.protocol.GuacamoleConfiguration;
|
||||
|
||||
/**
|
||||
* Implementation of GuacamoleConfiguration which loads parameter values only
|
||||
* if necessary, and only if allowed.
|
||||
*/
|
||||
public class ModeledGuacamoleConfiguration extends GuacamoleConfiguration {
|
||||
|
||||
/**
|
||||
* The user this configuration belongs to. Access is based on his/her
|
||||
* permission settings.
|
||||
*/
|
||||
private ModeledAuthenticatedUser currentUser;
|
||||
|
||||
/**
|
||||
* The internal model object containing the values which represent the
|
||||
* connection associated with this configuration.
|
||||
*/
|
||||
private ConnectionModel connectionModel;
|
||||
|
||||
/**
|
||||
* Service for managing connection parameters.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionService connectionService;
|
||||
|
||||
/**
|
||||
* The manually-set parameter map, if any.
|
||||
*/
|
||||
private Map<String, String> parameters = null;
|
||||
|
||||
/**
|
||||
* Creates a new, empty ModelGuacamoleConfiguration.
|
||||
*/
|
||||
public ModeledGuacamoleConfiguration() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this configuration, associating it with the current
|
||||
* authenticated user and populating it with data from the given model
|
||||
* object.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user that created or retrieved this configuration.
|
||||
*
|
||||
* @param connectionModel
|
||||
* The model object backing this configuration.
|
||||
*/
|
||||
public void init(ModeledAuthenticatedUser currentUser, ConnectionModel connectionModel) {
|
||||
this.currentUser = currentUser;
|
||||
this.connectionModel = connectionModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return connectionModel.getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocol(String protocol) {
|
||||
super.setProtocol(protocol);
|
||||
connectionModel.setProtocol(protocol);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setParameters(Map<String, String> parameters) {
|
||||
this.parameters = parameters;
|
||||
super.setParameters(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getParameters() {
|
||||
|
||||
// Retrieve visible parameters, if not overridden by setParameters()
|
||||
if (parameters == null) {
|
||||
|
||||
// Retrieve all visible parameters
|
||||
Map<String, String> visibleParameters =
|
||||
connectionService.retrieveParameters(currentUser, connectionModel.getIdentifier());
|
||||
|
||||
// Use retrieved parameters to back future operations
|
||||
super.setParameters(visibleParameters);
|
||||
|
||||
}
|
||||
|
||||
return super.getParameters();
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes related to connections and their parameters and history.
|
||||
*/
|
||||
package org.apache.guacamole.auth.jdbc.connection;
|
@@ -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.connectiongroup;
|
||||
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.JDBCDirectory;
|
||||
import org.apache.guacamole.net.auth.ConnectionGroup;
|
||||
import org.mybatis.guice.transactional.Transactional;
|
||||
|
||||
/**
|
||||
* Implementation of the ConnectionGroup Directory which is driven by an
|
||||
* underlying, arbitrary database.
|
||||
*/
|
||||
public class ConnectionGroupDirectory extends JDBCDirectory<ConnectionGroup> {
|
||||
|
||||
/**
|
||||
* Service for managing connection group objects.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionGroupService connectionGroupService;
|
||||
|
||||
@Override
|
||||
public ConnectionGroup get(String identifier) throws GuacamoleException {
|
||||
return connectionGroupService.retrieveObject(getCurrentUser(), identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Collection<ConnectionGroup> getAll(Collection<String> identifiers) throws GuacamoleException {
|
||||
Collection<ModeledConnectionGroup> objects = connectionGroupService.retrieveObjects(getCurrentUser(), identifiers);
|
||||
return Collections.<ConnectionGroup>unmodifiableCollection(objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Set<String> getIdentifiers() throws GuacamoleException {
|
||||
return connectionGroupService.getIdentifiers(getCurrentUser());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void add(ConnectionGroup object) throws GuacamoleException {
|
||||
connectionGroupService.createObject(getCurrentUser(), object);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void update(ConnectionGroup object) throws GuacamoleException {
|
||||
ModeledConnectionGroup connectionGroup = (ModeledConnectionGroup) object;
|
||||
connectionGroupService.updateObject(getCurrentUser(), connectionGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void remove(String identifier) throws GuacamoleException {
|
||||
connectionGroupService.deleteObject(getCurrentUser(), identifier);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.connectiongroup;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
|
||||
import org.apache.guacamole.auth.jdbc.user.UserModel;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Mapper for connection group objects.
|
||||
*/
|
||||
public interface ConnectionGroupMapper extends ModeledDirectoryObjectMapper<ConnectionGroupModel> {
|
||||
|
||||
/**
|
||||
* Selects the identifiers of all connection groups within the given parent
|
||||
* connection group, regardless of whether they are readable by any
|
||||
* particular user. This should only be called on behalf of a system
|
||||
* administrator. If identifiers are needed by a non-administrative user
|
||||
* who must have explicit read rights, use
|
||||
* selectReadableIdentifiersWithin() instead.
|
||||
*
|
||||
* @param parentIdentifier
|
||||
* The identifier of the parent connection group, or null if the root
|
||||
* connection group is to be queried.
|
||||
*
|
||||
* @return
|
||||
* A Set containing all identifiers of all objects.
|
||||
*/
|
||||
Set<String> selectIdentifiersWithin(@Param("parentIdentifier") String parentIdentifier);
|
||||
|
||||
/**
|
||||
* Selects the identifiers of all connection groups within the given parent
|
||||
* connection group that are explicitly readable by the given user. If
|
||||
* identifiers are needed by a system administrator (who, by definition,
|
||||
* does not need explicit read rights), use selectIdentifiersWithin()
|
||||
* instead.
|
||||
*
|
||||
* @param user
|
||||
* The user whose permissions should determine whether an identifier
|
||||
* is returned.
|
||||
*
|
||||
* @param parentIdentifier
|
||||
* The identifier of the parent connection group, or null if the root
|
||||
* connection group is to be queried.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the user. If
|
||||
* no groups are given, only permissions directly granted to the user
|
||||
* will be used.
|
||||
*
|
||||
* @return
|
||||
* A Set containing all identifiers of all readable objects.
|
||||
*/
|
||||
Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user,
|
||||
@Param("parentIdentifier") String parentIdentifier,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Selects the connection group within the given parent group and having
|
||||
* the given name. If no such connection group exists, null is returned.
|
||||
*
|
||||
* @param parentIdentifier
|
||||
* The identifier of the parent group to search within.
|
||||
*
|
||||
* @param name
|
||||
* The name of the connection group to find.
|
||||
*
|
||||
* @return
|
||||
* The connection group having the given name within the given parent
|
||||
* group, or null if no such connection group exists.
|
||||
*/
|
||||
ConnectionGroupModel selectOneByName(@Param("parentIdentifier") String parentIdentifier,
|
||||
@Param("name") String name);
|
||||
|
||||
}
|
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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.connectiongroup;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.base.ChildObjectModel;
|
||||
import org.apache.guacamole.net.auth.ConnectionGroup;
|
||||
|
||||
/**
|
||||
* Object representation of a Guacamole connection group, as represented in the
|
||||
* database.
|
||||
*/
|
||||
public class ConnectionGroupModel extends ChildObjectModel {
|
||||
|
||||
/**
|
||||
* The human-readable name associated with this connection group.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The type of this connection group, such as organizational or balancing.
|
||||
*/
|
||||
private ConnectionGroup.Type type;
|
||||
|
||||
/**
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection group concurrently, zero if no restriction applies, or
|
||||
* null if the default restrictions should be applied.
|
||||
*/
|
||||
private Integer maxConnections;
|
||||
|
||||
/**
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection group concurrently by any one user, zero if no restriction
|
||||
* applies, or null if the default restrictions should be applied.
|
||||
*/
|
||||
private Integer maxConnectionsPerUser;
|
||||
|
||||
/**
|
||||
* Whether individual users should be consistently assigned the same
|
||||
* connection within a balancing group until they log out.
|
||||
*/
|
||||
private boolean sessionAffinityEnabled;
|
||||
|
||||
/**
|
||||
* The identifiers of all readable child connections within this connection
|
||||
* group.
|
||||
*/
|
||||
private Set<String> connectionIdentifiers = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* The identifiers of all readable child connection groups within this
|
||||
* connection group.
|
||||
*/
|
||||
private Set<String> connectionGroupIdentifiers = new HashSet<String>();
|
||||
|
||||
/**
|
||||
* Creates a new, empty connection group.
|
||||
*/
|
||||
public ConnectionGroupModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name associated with this connection group.
|
||||
*
|
||||
* @return
|
||||
* The name associated with this connection group.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name associated with this connection group.
|
||||
*
|
||||
* @param name
|
||||
* The name to associate with this connection group.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this connection group, such as organizational or
|
||||
* balancing.
|
||||
*
|
||||
* @return
|
||||
* The type of this connection group.
|
||||
*/
|
||||
public ConnectionGroup.Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of this connection group, such as organizational or
|
||||
* balancing.
|
||||
*
|
||||
* @param type
|
||||
* The type of this connection group.
|
||||
*/
|
||||
public void setType(ConnectionGroup.Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of connections that can be established to
|
||||
* this connection group concurrently.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection group concurrently, zero if no restriction applies, or
|
||||
* null if the default restrictions should be applied.
|
||||
*/
|
||||
public Integer getMaxConnections() {
|
||||
return maxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of connections that can be established to this
|
||||
* connection group concurrently.
|
||||
*
|
||||
* @param maxConnections
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection group concurrently, zero if no restriction applies, or
|
||||
* null if the default restrictions should be applied.
|
||||
*/
|
||||
public void setMaxConnections(Integer maxConnections) {
|
||||
this.maxConnections = maxConnections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of connections that can be established to
|
||||
* this connection group concurrently by any one user.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection group concurrently by any one user, zero if no
|
||||
* restriction applies, or null if the default restrictions should be
|
||||
* applied.
|
||||
*/
|
||||
public Integer getMaxConnectionsPerUser() {
|
||||
return maxConnectionsPerUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of connections that can be established to this
|
||||
* connection group concurrently by any one user.
|
||||
*
|
||||
* @param maxConnectionsPerUser
|
||||
* The maximum number of connections that can be established to this
|
||||
* connection group concurrently by any one user, zero if no
|
||||
* restriction applies, or null if the default restrictions should be
|
||||
* applied.
|
||||
*/
|
||||
public void setMaxConnectionsPerUser(Integer maxConnectionsPerUser) {
|
||||
this.maxConnectionsPerUser = maxConnectionsPerUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether individual users should be consistently assigned the same
|
||||
* connection within a balancing group until they log out.
|
||||
*
|
||||
* @return
|
||||
* Whether individual users should be consistently assigned the same
|
||||
* connection within a balancing group until they log out.
|
||||
*/
|
||||
public boolean isSessionAffinityEnabled() {
|
||||
return sessionAffinityEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether individual users should be consistently assigned the same
|
||||
* connection within a balancing group until they log out.
|
||||
*
|
||||
* @param sessionAffinityEnabled
|
||||
* Whether individual users should be consistently assigned the same
|
||||
* connection within a balancing group until they log out.
|
||||
*/
|
||||
public void setSessionAffinityEnabled(boolean sessionAffinityEnabled) {
|
||||
this.sessionAffinityEnabled = sessionAffinityEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifiers of all readable child connections within this
|
||||
* connection group. This is set only when the parent connection group is
|
||||
* queried, and has no effect when a connection group is inserted, updated,
|
||||
* or deleted.
|
||||
*
|
||||
* @return
|
||||
* The identifiers of all readable child connections within this
|
||||
* connection group.
|
||||
*/
|
||||
public Set<String> getConnectionIdentifiers() {
|
||||
return connectionIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifiers of all readable child connections within this
|
||||
* connection group. This should be set only when the parent connection
|
||||
* group is queried, as it has no effect when a connection group is
|
||||
* inserted, updated, or deleted.
|
||||
*
|
||||
* @param connectionIdentifiers
|
||||
* The identifiers of all readable child connections within this
|
||||
* connection group.
|
||||
*/
|
||||
public void setConnectionIdentifiers(Set<String> connectionIdentifiers) {
|
||||
this.connectionIdentifiers = connectionIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifiers of all readable child connection groups within
|
||||
* this connection group. This is set only when the parent connection group
|
||||
* is queried, and has no effect when a connection group is inserted,
|
||||
* updated, or deleted.
|
||||
*
|
||||
* @return
|
||||
* The identifiers of all readable child connection groups within this
|
||||
* connection group.
|
||||
*/
|
||||
public Set<String> getConnectionGroupIdentifiers() {
|
||||
return connectionGroupIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifiers of all readable child connection groups within this
|
||||
* connection group. This should be set only when the parent connection
|
||||
* group is queried, as it has no effect when a connection group is
|
||||
* inserted, updated, or deleted.
|
||||
*
|
||||
* @param connectionGroupIdentifiers
|
||||
* The identifiers of all readable child connection groups within this
|
||||
* connection group.
|
||||
*/
|
||||
public void setConnectionGroupIdentifiers(Set<String> connectionGroupIdentifiers) {
|
||||
this.connectionGroupIdentifiers = connectionGroupIdentifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
|
||||
// If no associated ID, then no associated identifier
|
||||
Integer id = getObjectID();
|
||||
if (id == null)
|
||||
return null;
|
||||
|
||||
// Otherwise, the identifier is the ID as a string
|
||||
return id.toString();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(String identifier) {
|
||||
throw new UnsupportedOperationException("Connection group identifiers are derived from IDs. They cannot be set.");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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.connectiongroup;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.GuacamoleClientException;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.GuacamoleUnsupportedException;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.ConnectionGroup;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
|
||||
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* manipulating connection groups.
|
||||
*/
|
||||
public class ConnectionGroupService extends ModeledChildDirectoryObjectService<ModeledConnectionGroup,
|
||||
ConnectionGroup, ConnectionGroupModel> {
|
||||
|
||||
/**
|
||||
* Mapper for accessing connection groups.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionGroupMapper connectionGroupMapper;
|
||||
|
||||
/**
|
||||
* Mapper for manipulating connection group permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionGroupPermissionMapper connectionGroupPermissionMapper;
|
||||
|
||||
/**
|
||||
* Provider for creating connection groups.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<ModeledConnectionGroup> connectionGroupProvider;
|
||||
|
||||
/**
|
||||
* Service for creating and tracking tunnels.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleTunnelService tunnelService;
|
||||
|
||||
@Override
|
||||
protected ModeledDirectoryObjectMapper<ConnectionGroupModel> getObjectMapper() {
|
||||
return connectionGroupMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionMapper getPermissionMapper() {
|
||||
return connectionGroupPermissionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ModeledConnectionGroup getObjectInstance(ModeledAuthenticatedUser currentUser,
|
||||
ConnectionGroupModel model) {
|
||||
ModeledConnectionGroup connectionGroup = connectionGroupProvider.get();
|
||||
connectionGroup.init(currentUser, model);
|
||||
return connectionGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectionGroupModel getModelInstance(ModeledAuthenticatedUser currentUser,
|
||||
final ConnectionGroup object) {
|
||||
|
||||
// Create new ModeledConnectionGroup backed by blank model
|
||||
ConnectionGroupModel model = new ConnectionGroupModel();
|
||||
ModeledConnectionGroup connectionGroup = getObjectInstance(currentUser, model);
|
||||
|
||||
// Set model contents through ModeledConnectionGroup, copying the provided connection group
|
||||
connectionGroup.setParentIdentifier(object.getParentIdentifier());
|
||||
connectionGroup.setName(object.getName());
|
||||
connectionGroup.setType(object.getType());
|
||||
connectionGroup.setAttributes(object.getAttributes());
|
||||
|
||||
return model;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasCreatePermission(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Return whether user has explicit connection group creation permission
|
||||
SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
|
||||
return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION_GROUP);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Return permissions related to connection groups
|
||||
return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Connection groups are contained by other connection groups
|
||||
return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user,
|
||||
ConnectionGroup object, ConnectionGroupModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
super.beforeCreate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
throw new GuacamoleClientException("Connection group names must not be blank.");
|
||||
|
||||
// Do not attempt to create duplicate connection groups
|
||||
ConnectionGroupModel existing = connectionGroupMapper.selectOneByName(model.getParentIdentifier(), model.getName());
|
||||
if (existing != null)
|
||||
throw new GuacamoleClientException("The connection group \"" + model.getName() + "\" already exists.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
ModeledConnectionGroup object, ConnectionGroupModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
super.beforeUpdate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
throw new GuacamoleClientException("Connection group names must not be blank.");
|
||||
|
||||
// Check whether such a connection group is already present
|
||||
ConnectionGroupModel existing = connectionGroupMapper.selectOneByName(model.getParentIdentifier(), model.getName());
|
||||
if (existing != null) {
|
||||
|
||||
// If the specified name matches a DIFFERENT existing connection group, the update cannot continue
|
||||
if (!existing.getObjectID().equals(model.getObjectID()))
|
||||
throw new GuacamoleClientException("The connection group \"" + model.getName() + "\" already exists.");
|
||||
|
||||
}
|
||||
|
||||
// Verify that this connection group's location does not create a cycle
|
||||
String relativeParentIdentifier = model.getParentIdentifier();
|
||||
while (relativeParentIdentifier != null) {
|
||||
|
||||
// Abort if cycle is detected
|
||||
if (relativeParentIdentifier.equals(model.getIdentifier()))
|
||||
throw new GuacamoleUnsupportedException("A connection group may not contain itself.");
|
||||
|
||||
// Advance to next parent
|
||||
ModeledConnectionGroup relativeParentGroup = retrieveObject(user, relativeParentIdentifier);
|
||||
relativeParentIdentifier = relativeParentGroup.getModel().getParentIdentifier();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of all identifiers for all connection groups within the
|
||||
* connection group having the given identifier. Only connection groups
|
||||
* that the user has read access to will be returned.
|
||||
*
|
||||
* Permission to read the connection group having the given identifier is
|
||||
* NOT checked.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the identifiers.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the parent connection group, or null to check the
|
||||
* root connection group.
|
||||
*
|
||||
* @return
|
||||
* The set of all identifiers for all connection groups in the
|
||||
* connection group having the given identifier that the user has read
|
||||
* access to.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while reading identifiers.
|
||||
*/
|
||||
public Set<String> getIdentifiersWithin(ModeledAuthenticatedUser user,
|
||||
String identifier)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Bypass permission checks if the user is privileged
|
||||
if (user.isPrivileged())
|
||||
return connectionGroupMapper.selectIdentifiersWithin(identifier);
|
||||
|
||||
// Otherwise only return explicitly readable identifiers
|
||||
else
|
||||
return connectionGroupMapper.selectReadableIdentifiersWithin(
|
||||
user.getUser().getModel(), identifier,
|
||||
user.getEffectiveUserGroups(),
|
||||
getCaseSensitivity());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the given connection group as the given user, using the
|
||||
* given client information. If the user does not have permission to read
|
||||
* the connection group, permission will be denied.
|
||||
*
|
||||
* @param user
|
||||
* The user connecting to the connection group.
|
||||
*
|
||||
* @param connectionGroup
|
||||
* The connectionGroup being connected to.
|
||||
*
|
||||
* @param info
|
||||
* Information associated with the connecting client.
|
||||
*
|
||||
* @param tokens
|
||||
* A Map containing the token names and corresponding values to be
|
||||
* applied as parameter tokens when establishing the connection.
|
||||
*
|
||||
* @return
|
||||
* A connected GuacamoleTunnel associated with a newly-established
|
||||
* connection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to connect to this connection is denied.
|
||||
*/
|
||||
public GuacamoleTunnel connect(ModeledAuthenticatedUser user,
|
||||
ModeledConnectionGroup connectionGroup, GuacamoleClientInformation info,
|
||||
Map<String, String> tokens) throws GuacamoleException {
|
||||
|
||||
// Connect only if READ permission is granted
|
||||
if (hasObjectPermission(user, connectionGroup.getIdentifier(), ObjectPermission.Type.READ))
|
||||
return tunnelService.getGuacamoleTunnel(user, connectionGroup, info, tokens);
|
||||
|
||||
// The user does not have permission to connect
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* 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.connectiongroup;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObject;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.form.BooleanField;
|
||||
import org.apache.guacamole.form.Field;
|
||||
import org.apache.guacamole.form.Form;
|
||||
import org.apache.guacamole.form.NumericField;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.ConnectionGroup;
|
||||
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* An implementation of the ConnectionGroup object which is backed by a
|
||||
* database model.
|
||||
*/
|
||||
public class ModeledConnectionGroup extends ModeledChildDirectoryObject<ConnectionGroupModel>
|
||||
implements ConnectionGroup {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(ModeledConnectionGroup.class);
|
||||
|
||||
/**
|
||||
* The name of the attribute which controls the maximum number of
|
||||
* concurrent connections.
|
||||
*/
|
||||
public static final String MAX_CONNECTIONS_NAME = "max-connections";
|
||||
|
||||
/**
|
||||
* The name of the attribute which controls the maximum number of
|
||||
* concurrent connections per user.
|
||||
*/
|
||||
public static final String MAX_CONNECTIONS_PER_USER_NAME = "max-connections-per-user";
|
||||
|
||||
/**
|
||||
* The name of the attribute which controls whether individual users will be
|
||||
* consistently assigned the same connection within a balancing group until
|
||||
* they log out.
|
||||
*/
|
||||
public static final String ENABLE_SESSION_AFFINITY = "enable-session-affinity";
|
||||
|
||||
/**
|
||||
* All attributes related to restricting user accounts, within a logical
|
||||
* form.
|
||||
*/
|
||||
public static final Form CONCURRENCY_LIMITS = new Form("concurrency", Arrays.<Field>asList(
|
||||
new NumericField(MAX_CONNECTIONS_NAME),
|
||||
new NumericField(MAX_CONNECTIONS_PER_USER_NAME),
|
||||
new BooleanField(ENABLE_SESSION_AFFINITY, "true")
|
||||
));
|
||||
|
||||
/**
|
||||
* All possible attributes of connection group objects organized as
|
||||
* individual, logical forms.
|
||||
*/
|
||||
public static final Collection<Form> ATTRIBUTES = Collections.unmodifiableCollection(Arrays.asList(
|
||||
CONCURRENCY_LIMITS
|
||||
));
|
||||
|
||||
/**
|
||||
* The names of all attributes which are explicitly supported by this
|
||||
* extension's ConnectionGroup objects.
|
||||
*/
|
||||
public static final Set<String> ATTRIBUTE_NAMES =
|
||||
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
|
||||
MAX_CONNECTIONS_NAME,
|
||||
MAX_CONNECTIONS_PER_USER_NAME,
|
||||
ENABLE_SESSION_AFFINITY
|
||||
)));
|
||||
|
||||
/**
|
||||
* The environment of the Guacamole server.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Service for managing connection groups.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionGroupService connectionGroupService;
|
||||
|
||||
/**
|
||||
* Service for creating and tracking tunnels.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleTunnelService tunnelService;
|
||||
|
||||
/**
|
||||
* Creates a new, empty ModeledConnectionGroup.
|
||||
*/
|
||||
public ModeledConnectionGroup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getModel().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
getModel().setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleTunnel connect(GuacamoleClientInformation info,
|
||||
Map<String, String> tokens) throws GuacamoleException {
|
||||
return connectionGroupService.connect(getCurrentUser(), this, info, tokens);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActiveConnections() {
|
||||
return tunnelService.getActiveConnections(this).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(Type type) {
|
||||
getModel().setType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return getModel().getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getConnectionIdentifiers()
|
||||
throws GuacamoleException {
|
||||
return getModel().getConnectionIdentifiers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getConnectionGroupIdentifiers()
|
||||
throws GuacamoleException {
|
||||
return getModel().getConnectionGroupIdentifiers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedAttributeNames() {
|
||||
return ATTRIBUTE_NAMES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
|
||||
// Include any defined arbitrary attributes
|
||||
Map<String, String> attributes = super.getAttributes();
|
||||
|
||||
// Set connection limit attribute
|
||||
attributes.put(MAX_CONNECTIONS_NAME, NumericField.format(getModel().getMaxConnections()));
|
||||
|
||||
// Set per-user connection limit attribute
|
||||
attributes.put(MAX_CONNECTIONS_PER_USER_NAME, NumericField.format(getModel().getMaxConnectionsPerUser()));
|
||||
|
||||
// Set session affinity attribute
|
||||
attributes.put(ENABLE_SESSION_AFFINITY,
|
||||
getModel().isSessionAffinityEnabled() ? "true" : "");
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttributes(Map<String, String> attributes) {
|
||||
|
||||
// Set arbitrary attributes
|
||||
super.setAttributes(attributes);
|
||||
|
||||
// Translate connection limit attribute
|
||||
try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); }
|
||||
catch (NumberFormatException e) {
|
||||
logger.warn("Not setting maximum connections: {}", e.getMessage());
|
||||
logger.debug("Unable to parse numeric attribute.", e);
|
||||
}
|
||||
|
||||
// Translate per-user connection limit attribute
|
||||
try { getModel().setMaxConnectionsPerUser(NumericField.parse(attributes.get(MAX_CONNECTIONS_PER_USER_NAME))); }
|
||||
catch (NumberFormatException e) {
|
||||
logger.warn("Not setting maximum connections per user: {}", e.getMessage());
|
||||
logger.debug("Unable to parse numeric attribute.", e);
|
||||
}
|
||||
|
||||
// Translate session affinity attribute
|
||||
getModel().setSessionAffinityEnabled(
|
||||
"true".equals(attributes.get(ENABLE_SESSION_AFFINITY)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of connections that should be allowed to this
|
||||
* connection group overall. If no limit applies, zero is returned.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of connections that should be allowed to this
|
||||
* connection group overall, or zero if no limit applies.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while parsing the concurrency limit properties
|
||||
* specified within guacamole.properties.
|
||||
*/
|
||||
public int getMaxConnections() throws GuacamoleException {
|
||||
|
||||
// Pull default from environment if connection limit is unset
|
||||
Integer value = getModel().getMaxConnections();
|
||||
if (value == null)
|
||||
return environment.getDefaultMaxGroupConnections();
|
||||
|
||||
// Otherwise use defined value
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of connections that should be allowed to this
|
||||
* connection group for any individual user. If no limit applies, zero is
|
||||
* returned.
|
||||
*
|
||||
* @return
|
||||
* The maximum number of connections that should be allowed to this
|
||||
* connection group for any individual user, or zero if no limit
|
||||
* applies.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while parsing the concurrency limit properties
|
||||
* specified within guacamole.properties.
|
||||
*/
|
||||
public int getMaxConnectionsPerUser() throws GuacamoleException {
|
||||
|
||||
// Pull default from environment if per-user connection limit is unset
|
||||
Integer value = getModel().getMaxConnectionsPerUser();
|
||||
if (value == null)
|
||||
return environment.getDefaultMaxGroupConnectionsPerUser();
|
||||
|
||||
// Otherwise use defined value
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether individual users should be consistently assigned the same
|
||||
* connection within a balancing group until they log out.
|
||||
*
|
||||
* @return
|
||||
* Whether individual users should be consistently assigned the same
|
||||
* connection within a balancing group until they log out.
|
||||
*/
|
||||
public boolean isSessionAffinityEnabled() {
|
||||
return getModel().isSessionAffinityEnabled();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.connectiongroup;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ConnectionService;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.ConnectionGroup;
|
||||
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
/**
|
||||
* The root connection group, here represented as its own dedicated object as
|
||||
* the database does not contain an actual root group.
|
||||
*/
|
||||
public class RootConnectionGroup extends RestrictedObject
|
||||
implements ConnectionGroup {
|
||||
|
||||
/**
|
||||
* The identifier used to represent the root connection group. There is no
|
||||
* corresponding entry in the database, thus a reserved identifier that
|
||||
* cannot collide with database-generated identifiers is needed.
|
||||
*/
|
||||
public static final String IDENTIFIER = "ROOT";
|
||||
|
||||
/**
|
||||
* The human-readable name of this connection group. The name of the root
|
||||
* group is not normally visible, and may even be replaced by the web
|
||||
* interface for the sake of translation.
|
||||
*/
|
||||
public static final String NAME = "ROOT";
|
||||
|
||||
/**
|
||||
* Service for managing connection objects.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionService connectionService;
|
||||
|
||||
/**
|
||||
* Service for managing connection group objects.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionGroupService connectionGroupService;
|
||||
|
||||
/**
|
||||
* Creates a new, empty RootConnectionGroup.
|
||||
*/
|
||||
public RootConnectionGroup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
throw new UnsupportedOperationException("The root connection group cannot be modified.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentIdentifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParentIdentifier(String parentIdentifier) {
|
||||
throw new UnsupportedOperationException("The root connection group cannot be modified.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return ConnectionGroup.Type.ORGANIZATIONAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(Type type) {
|
||||
throw new UnsupportedOperationException("The root connection group cannot be modified.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getConnectionIdentifiers() throws GuacamoleException {
|
||||
return connectionService.getIdentifiersWithin(getCurrentUser(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getConnectionGroupIdentifiers()
|
||||
throws GuacamoleException {
|
||||
return connectionGroupService.getIdentifiersWithin(getCurrentUser(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(String identifier) {
|
||||
throw new UnsupportedOperationException("The root connection group cannot be modified.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleTunnel connect(GuacamoleClientInformation info,
|
||||
Map<String, String> tokens) throws GuacamoleException {
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActiveConnections() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
return Collections.<String, String>emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttributes(Map<String, String> attributes) {
|
||||
throw new UnsupportedOperationException("The root connection group cannot be modified.");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes related to connection groups.
|
||||
*/
|
||||
package org.apache.guacamole.auth.jdbc.connectiongroup;
|
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The base JDBC authentication provider. This authentication provider serves
|
||||
* as a basis for other JDBC authentication provider implementations which are
|
||||
* driven by relatively-common schemas. The only difference between such
|
||||
* implementations are maintained within database-specific MyBatis mappings.
|
||||
*/
|
||||
package org.apache.guacamole.auth.jdbc;
|
@@ -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.permission;
|
||||
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledUser;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.apache.guacamole.net.auth.permission.Permission;
|
||||
import org.apache.guacamole.net.auth.permission.PermissionSet;
|
||||
|
||||
/**
|
||||
* Abstract PermissionService implementation which provides additional
|
||||
* convenience methods for enforcing the permission model.
|
||||
*
|
||||
* @param <PermissionSetType>
|
||||
* The type of permission sets this service provides access to.
|
||||
*
|
||||
* @param <PermissionType>
|
||||
* The type of permission this service provides access to.
|
||||
*/
|
||||
public abstract class AbstractPermissionService<PermissionSetType extends PermissionSet<PermissionType>,
|
||||
PermissionType extends Permission>
|
||||
implements PermissionService<PermissionSetType, PermissionType> {
|
||||
|
||||
/**
|
||||
* Returns the ObjectPermissionSet related to the type of the given entity.
|
||||
* If the given entity represents a user, then the ObjectPermissionSet
|
||||
* containing user permissions is returned. If the given entity represents
|
||||
* a user group, then the ObjectPermissionSet containing user group
|
||||
* permissions is returned.
|
||||
*
|
||||
* @param user
|
||||
* The user to retrieve the ObjectPermissionSet from.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity whose type dictates the ObjectPermissionSet returned.
|
||||
*
|
||||
* @return
|
||||
* The ObjectPermissionSet related to the type of the given entity.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the relevant ObjectPermissionSet cannot be retrieved.
|
||||
*/
|
||||
protected ObjectPermissionSet getRelevantPermissionSet(ModeledUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity)
|
||||
throws GuacamoleException {
|
||||
|
||||
if (targetEntity.isUser())
|
||||
return user.getUserPermissions();
|
||||
|
||||
if (targetEntity.isUserGroup())
|
||||
return user.getUserGroupPermissions();
|
||||
|
||||
// Entities should be only users or groups
|
||||
throw new UnsupportedOperationException("Unexpected entity type.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given user can read the permissions currently
|
||||
* granted to the given target entity. If the reading user and the target
|
||||
* entity are not the same, then explicit READ or SYSTEM_ADMINISTER access
|
||||
* is required. Permission inheritance via user groups is taken into account.
|
||||
*
|
||||
* @param user
|
||||
* The user attempting to read permissions.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity whose permissions are being read.
|
||||
*
|
||||
* @return
|
||||
* true if permission is granted, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while checking permission status, or if
|
||||
* permission is denied to read the current user's permissions.
|
||||
*/
|
||||
protected boolean canReadPermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity)
|
||||
throws GuacamoleException {
|
||||
|
||||
// A user can always read their own permissions
|
||||
if (targetEntity.isUser(user.getUser().getIdentifier()))
|
||||
return true;
|
||||
|
||||
// Privileged users (such as system administrators) may do anything
|
||||
if (user.isPrivileged())
|
||||
return true;
|
||||
|
||||
// Can read permissions on target entity if explicit READ is granted
|
||||
ObjectPermissionSet permissionSet = getRelevantPermissionSet(user.getUser(), targetEntity);
|
||||
return permissionSet.hasPermission(ObjectPermission.Type.READ, targetEntity.getIdentifier());
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
/**
|
||||
* Mapper for connection group permissions.
|
||||
*/
|
||||
public interface ConnectionGroupPermissionMapper extends ObjectPermissionMapper {}
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting connection group permissions. This service will automatically
|
||||
* enforce the permissions of the current user.
|
||||
*/
|
||||
public class ConnectionGroupPermissionService extends ModeledObjectPermissionService {
|
||||
|
||||
/**
|
||||
* Mapper for connection group permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionGroupPermissionMapper connectionGroupPermissionMapper;
|
||||
|
||||
/**
|
||||
* Provider for connection group permission sets.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<ConnectionGroupPermissionSet> connectionGroupPermissionSetProvider;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionMapper getPermissionMapper() {
|
||||
return connectionGroupPermissionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Create permission set for requested entity
|
||||
ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get();
|
||||
permissionSet.init(user, targetEntity, effectiveGroups);
|
||||
|
||||
return permissionSet;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* A database implementation of ObjectPermissionSet which uses an injected
|
||||
* service to query and manipulate the connection group permissions associated
|
||||
* with a particular user.
|
||||
*/
|
||||
public class ConnectionGroupPermissionSet extends ObjectPermissionSet {
|
||||
|
||||
/**
|
||||
* Service for querying and manipulating connection group permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionGroupPermissionService connectionGroupPermissionService;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionService getObjectPermissionService() {
|
||||
return connectionGroupPermissionService;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
/**
|
||||
* Mapper for connection permissions.
|
||||
*/
|
||||
public interface ConnectionPermissionMapper extends ObjectPermissionMapper {}
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting connection permissions. This service will automatically enforce the
|
||||
* permissions of the current user.
|
||||
*/
|
||||
public class ConnectionPermissionService extends ModeledObjectPermissionService {
|
||||
|
||||
/**
|
||||
* Mapper for connection permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionPermissionMapper connectionPermissionMapper;
|
||||
|
||||
/**
|
||||
* Provider for connection permission sets.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<ConnectionPermissionSet> connectionPermissionSetProvider;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionMapper getPermissionMapper() {
|
||||
return connectionPermissionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Create permission set for requested entity
|
||||
ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get();
|
||||
permissionSet.init(user, targetEntity, effectiveGroups);
|
||||
|
||||
return permissionSet;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* A database implementation of ObjectPermissionSet which uses an injected
|
||||
* service to query and manipulate the connection permissions associated with
|
||||
* a particular user.
|
||||
*/
|
||||
public class ConnectionPermissionSet extends ObjectPermissionSet {
|
||||
|
||||
/**
|
||||
* Service for querying and manipulating connection permissions.
|
||||
*/
|
||||
@Inject
|
||||
private ConnectionPermissionService connectionPermissionService;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionService getObjectPermissionService() {
|
||||
return connectionPermissionService;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting object permissions within a backend database model. This service
|
||||
* will automatically enforce the permissions of the current user.
|
||||
*/
|
||||
public abstract class ModeledObjectPermissionService
|
||||
extends ModeledPermissionService<ObjectPermissionSet, ObjectPermission, ObjectPermissionModel>
|
||||
implements ObjectPermissionService {
|
||||
|
||||
@Override
|
||||
protected abstract ObjectPermissionMapper getPermissionMapper();
|
||||
|
||||
@Override
|
||||
protected ObjectPermission getPermissionInstance(ObjectPermissionModel model) {
|
||||
return new ObjectPermission(model.getType(), model.getObjectIdentifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionModel getModelInstance(
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
ObjectPermission permission) {
|
||||
|
||||
ObjectPermissionModel model = new ObjectPermissionModel();
|
||||
|
||||
// Populate model object with data from entity and permission
|
||||
model.setEntityID(targetEntity.getModel().getEntityID());
|
||||
model.setType(permission.getType());
|
||||
model.setObjectIdentifier(permission.getObjectIdentifier());
|
||||
|
||||
return model;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the current user has permission to update the given
|
||||
* target entity, adding or removing the given permissions. Such permission
|
||||
* depends on whether the current user is a system administrator, whether
|
||||
* they have explicit UPDATE permission on the target entity, and whether
|
||||
* they have explicit ADMINISTER permission on all affected objects.
|
||||
* Permission inheritance via user groups is taken into account.
|
||||
*
|
||||
* @param user
|
||||
* The user who is changing permissions.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity whose permissions are being changed.
|
||||
*
|
||||
* @param permissions
|
||||
* The permissions that are being added or removed from the target
|
||||
* entity.
|
||||
*
|
||||
* @return
|
||||
* true if the user has permission to change the target entity's
|
||||
* permissions as specified, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while checking permission status, or if
|
||||
* permission is denied to read the current user's permissions.
|
||||
*/
|
||||
protected boolean canAlterPermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<ObjectPermission> permissions)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Privileged users (such as system administrators) may do anything
|
||||
if (user.isPrivileged())
|
||||
return true;
|
||||
|
||||
// Verify user has update permission on the target entity
|
||||
ObjectPermissionSet permissionSet = getRelevantPermissionSet(user.getUser(), targetEntity);
|
||||
if (!permissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetEntity.getIdentifier()))
|
||||
return false;
|
||||
|
||||
// Produce collection of affected identifiers
|
||||
Collection<String> affectedIdentifiers = new HashSet<String>(permissions.size());
|
||||
for (ObjectPermission permission : permissions)
|
||||
affectedIdentifiers.add(permission.getObjectIdentifier());
|
||||
|
||||
// Determine subset of affected identifiers that we have admin access to
|
||||
ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser(), user.getEffectiveUserGroups());
|
||||
Collection<String> allowedSubset = affectedPermissionSet.getAccessibleObjects(
|
||||
Collections.singleton(ObjectPermission.Type.ADMINISTER),
|
||||
affectedIdentifiers
|
||||
);
|
||||
|
||||
// The permissions can be altered if and only if the set of objects we
|
||||
// are allowed to administer is equal to the set of objects we will be
|
||||
// affecting.
|
||||
|
||||
return affectedIdentifiers.size() == allowedSubset.size();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createPermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<ObjectPermission> permissions)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Create permissions only if user has permission to do so
|
||||
if (canAlterPermissions(user, targetEntity, permissions)) {
|
||||
|
||||
CaseSensitivity caseSensitivity = getCaseSensitivity();
|
||||
|
||||
batchPermissionUpdates(permissions, permissionSubset -> {
|
||||
Collection<ObjectPermissionModel> models = getModelInstances(
|
||||
targetEntity, permissionSubset);
|
||||
getPermissionMapper().insert(models, caseSensitivity);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// User lacks permission to create object permissions
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<ObjectPermission> permissions)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Delete permissions only if user has permission to do so
|
||||
if (canAlterPermissions(user, targetEntity, permissions)) {
|
||||
|
||||
CaseSensitivity caseSensitivity = getCaseSensitivity();
|
||||
|
||||
batchPermissionUpdates(permissions, permissionSubset -> {
|
||||
Collection<ObjectPermissionModel> models = getModelInstances(
|
||||
targetEntity, permissionSubset);
|
||||
getPermissionMapper().delete(models, caseSensitivity);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// User lacks permission to delete object permissions
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
ObjectPermission.Type type, String identifier,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Retrieve permissions only if allowed
|
||||
if (canReadPermissions(user, targetEntity))
|
||||
return getPermissionMapper().selectOne(targetEntity.getModel(),
|
||||
type, identifier, effectiveGroups, getCaseSensitivity()) != null;
|
||||
|
||||
// User cannot read this entity's permissions
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<ObjectPermission.Type> permissions,
|
||||
Collection<String> identifiers, Set<String> effectiveGroups)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Nothing is always accessible
|
||||
if (identifiers.isEmpty())
|
||||
return identifiers;
|
||||
|
||||
// Privileged users (such as system administrators) may access everything
|
||||
if (user.isPrivileged())
|
||||
return identifiers;
|
||||
|
||||
// Otherwise, return explicitly-retrievable identifiers only if allowed
|
||||
if (canReadPermissions(user, targetEntity))
|
||||
return getPermissionMapper().selectAccessibleIdentifiers(
|
||||
targetEntity.getModel(), permissions, identifiers,
|
||||
effectiveGroups, getCaseSensitivity());
|
||||
|
||||
// User cannot read this entity's permissions
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.net.auth.permission.Permission;
|
||||
import org.apache.guacamole.net.auth.permission.PermissionSet;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting permissions within a backend database model, and for obtaining the
|
||||
* permission sets that contain these permissions. This service will
|
||||
* automatically enforce the permissions of the current user.
|
||||
*
|
||||
* @param <PermissionSetType>
|
||||
* The type of permission sets this service provides access to.
|
||||
*
|
||||
* @param <PermissionType>
|
||||
* The type of permission this service provides access to.
|
||||
*
|
||||
* @param <ModelType>
|
||||
* The underlying model object used to represent PermissionType in the
|
||||
* database.
|
||||
*/
|
||||
public abstract class ModeledPermissionService<PermissionSetType extends PermissionSet<PermissionType>,
|
||||
PermissionType extends Permission, ModelType>
|
||||
extends AbstractPermissionService<PermissionSetType, PermissionType> {
|
||||
|
||||
/**
|
||||
* The environment of the Guacamole server.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Returns an instance of a mapper for the type of permission used by this
|
||||
* service.
|
||||
*
|
||||
* @return
|
||||
* A mapper which provides access to the model objects associated with
|
||||
* the permissions used by this service.
|
||||
*/
|
||||
protected abstract PermissionMapper<ModelType> getPermissionMapper();
|
||||
|
||||
/**
|
||||
* Returns an instance of a permission which is based on the given model
|
||||
* object.
|
||||
*
|
||||
* @param model
|
||||
* The model object to use to produce the returned permission.
|
||||
*
|
||||
* @return
|
||||
* A permission which is based on the given model object.
|
||||
*/
|
||||
protected abstract PermissionType getPermissionInstance(ModelType model);
|
||||
|
||||
/**
|
||||
* Returns a collection of permissions which are based on the models in
|
||||
* the given collection.
|
||||
*
|
||||
* @param models
|
||||
* The model objects to use to produce the permissions within the
|
||||
* returned set.
|
||||
*
|
||||
* @return
|
||||
* A set of permissions which are based on the models in the given
|
||||
* collection.
|
||||
*/
|
||||
protected Set<PermissionType> getPermissionInstances(Collection<ModelType> models) {
|
||||
|
||||
// Create new collection of permissions by manually converting each model
|
||||
Set<PermissionType> permissions = new HashSet<PermissionType>(models.size());
|
||||
for (ModelType model : models)
|
||||
permissions.add(getPermissionInstance(model));
|
||||
|
||||
return permissions;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of a model object which is based on the given
|
||||
* permission and target entity.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity to whom this permission is granted.
|
||||
*
|
||||
* @param permission
|
||||
* The permission to use to produce the returned model object.
|
||||
*
|
||||
* @return
|
||||
* A model object which is based on the given permission and target
|
||||
* entity.
|
||||
*/
|
||||
protected abstract ModelType getModelInstance(
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
PermissionType permission);
|
||||
|
||||
/**
|
||||
* Returns a collection of model objects which are based on the given
|
||||
* permissions and target entity.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity to whom this permission is granted.
|
||||
*
|
||||
* @param permissions
|
||||
* The permissions to use to produce the returned model objects.
|
||||
*
|
||||
* @return
|
||||
* A collection of model objects which are based on the given
|
||||
* permissions and target entity.
|
||||
*/
|
||||
protected Collection<ModelType> getModelInstances(
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<PermissionType> permissions) {
|
||||
|
||||
// Create new collection of models by manually converting each permission
|
||||
Collection<ModelType> models = new ArrayList<ModelType>(permissions.size());
|
||||
for (PermissionType permission : permissions)
|
||||
models.add(getModelInstance(targetEntity, permission));
|
||||
|
||||
return models;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the provided consumer function on subsets of the original collection
|
||||
* of objects, with each subset being no larger than the maximum batch size
|
||||
* configured for the JDBC environment. Any permission update that involves
|
||||
* passing potentially-large lists of models to a mapper should use this
|
||||
* method to perform the update to ensure that the maximum number of
|
||||
* parameters for an individual query is not exceeded.
|
||||
*
|
||||
* @param <T>
|
||||
* The type of object stored in the provided objects list, and consumed
|
||||
* by the provided consumer.
|
||||
*
|
||||
* @param objects
|
||||
* A collection of objects to be partitioned.
|
||||
*
|
||||
* @param consumer
|
||||
* A function that will consume subsets of the objects from the provided
|
||||
* collection of objects, performing any update as needed.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the batch size cannot be determined for the JDBC environment.
|
||||
*/
|
||||
protected <T> void batchPermissionUpdates(
|
||||
Collection<T> objects, Consumer<Collection<T>> consumer)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Split the original collection into views, each no larger than the
|
||||
// configured batch size, and call the collector function with each
|
||||
Iterables.partition(objects, environment.getBatchSize())
|
||||
.forEach(batch -> consumer.accept(batch));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Retrieve permissions only if allowed
|
||||
if (canReadPermissions(user, targetEntity))
|
||||
return getPermissionInstances(getPermissionMapper().select(
|
||||
targetEntity.getModel(),
|
||||
effectiveGroups,
|
||||
getCaseSensitivity()));
|
||||
|
||||
// User cannot read this entity's permissions
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import java.util.Collection;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Mapper for object-related permissions.
|
||||
*/
|
||||
public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissionModel> {
|
||||
|
||||
/**
|
||||
* Retrieve the permission of the given type associated with the given
|
||||
* entity and object, if it exists. If no such permission exists, null is
|
||||
* returned.
|
||||
*
|
||||
* @param entity
|
||||
* The entity to retrieve permissions for.
|
||||
*
|
||||
* @param type
|
||||
* The type of permission to return.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the object affected by the permission to return.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the user. If
|
||||
* no groups are given, only permissions directly granted to the user
|
||||
* will be used.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The configuration of case sensitivity, used to determine whether
|
||||
* usernames and/or group names will be treated as case-sensitive.
|
||||
*
|
||||
* @return
|
||||
* The requested permission, or null if no such permission is granted
|
||||
* to the given entity for the given object.
|
||||
*/
|
||||
ObjectPermissionModel selectOne(@Param("entity") EntityModel entity,
|
||||
@Param("type") ObjectPermission.Type type,
|
||||
@Param("identifier") String identifier,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Retrieves the subset of the given identifiers for which the given entity
|
||||
* has at least one of the given permissions.
|
||||
*
|
||||
* @param entity
|
||||
* The entity to check permissions of.
|
||||
*
|
||||
* @param permissions
|
||||
* The permissions to check. An identifier will be included in the
|
||||
* resulting collection if at least one of these permissions is granted
|
||||
* for the associated object
|
||||
*
|
||||
* @param identifiers
|
||||
* The identifiers of the objects affected by the permissions being
|
||||
* checked.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the user. If
|
||||
* no groups are given, only permissions directly granted to the user
|
||||
* will be used.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The configuration of case sensitivity, used to determine whether
|
||||
* usernames and/or group names will be treated as case-sensitive.
|
||||
*
|
||||
* @return
|
||||
* A collection containing the subset of identifiers for which at least
|
||||
* one of the specified permissions is granted.
|
||||
*/
|
||||
Collection<String> selectAccessibleIdentifiers(@Param("entity") EntityModel entity,
|
||||
@Param("permissions") Collection<ObjectPermission.Type> permissions,
|
||||
@Param("identifiers") Collection<String> identifiers,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
|
||||
/**
|
||||
* Object representation of an object-related Guacamole permission, as
|
||||
* represented in the database.
|
||||
*/
|
||||
public class ObjectPermissionModel extends PermissionModel<ObjectPermission.Type> {
|
||||
|
||||
/**
|
||||
* The unique identifier of the object affected by this permission.
|
||||
*/
|
||||
private String objectIdentifier;
|
||||
|
||||
/**
|
||||
* Creates a new, empty object permission.
|
||||
*/
|
||||
public ObjectPermissionModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier of the object affected by this permission.
|
||||
*
|
||||
* @return
|
||||
* The unique identifier of the object affected by this permission.
|
||||
*/
|
||||
public String getObjectIdentifier() {
|
||||
return objectIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unique identifier of the object affected by this permission.
|
||||
*
|
||||
* @param objectIdentifier
|
||||
* The unique identifier of the object affected by this permission.
|
||||
*/
|
||||
public void setObjectIdentifier(String objectIdentifier) {
|
||||
this.objectIdentifier = objectIdentifier;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting object permissions. This service will automatically enforce the
|
||||
* permissions of the current user.
|
||||
*/
|
||||
public interface ObjectPermissionService
|
||||
extends PermissionService<ObjectPermissionSet, ObjectPermission> {
|
||||
|
||||
/**
|
||||
* Returns whether the permission of the given type and associated with the
|
||||
* given object has been granted to the given entity.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the permission.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity associated with the permission to be retrieved.
|
||||
*
|
||||
* @param type
|
||||
* The type of permission to retrieve.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the object affected by the permission to return.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the entity.
|
||||
* If no groups are given, only permissions directly granted to the
|
||||
* entity will be used.
|
||||
*
|
||||
* @return
|
||||
* true if permission of the given type and associated with the given
|
||||
* object has been granted to the given entity, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the requested permission.
|
||||
*/
|
||||
boolean hasPermission(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
ObjectPermission.Type type, String identifier,
|
||||
Set<String> effectiveGroups) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Retrieves the subset of the given identifiers for which the given entity
|
||||
* has at least one of the given permissions.
|
||||
*
|
||||
* @param user
|
||||
* The user checking the permissions.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity to check permissions of.
|
||||
*
|
||||
* @param permissions
|
||||
* The permissions to check. An identifier will be included in the
|
||||
* resulting collection if at least one of these permissions is granted
|
||||
* for the associated object
|
||||
*
|
||||
* @param identifiers
|
||||
* The identifiers of the objects affected by the permissions being
|
||||
* checked.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the entity.
|
||||
* If no groups are given, only permissions directly granted to the
|
||||
* entity will be used.
|
||||
*
|
||||
* @return
|
||||
* A collection containing the subset of identifiers for which at least
|
||||
* one of the specified permissions is granted.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving permissions.
|
||||
*/
|
||||
Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<ObjectPermission.Type> permissions,
|
||||
Collection<String> identifiers, Set<String> effectiveGroups)
|
||||
throws GuacamoleException;
|
||||
|
||||
}
|
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
|
||||
/**
|
||||
* A database implementation of ObjectPermissionSet which uses an injected
|
||||
* service to query and manipulate the object-level permissions associated with
|
||||
* a particular entity.
|
||||
*/
|
||||
public abstract class ObjectPermissionSet extends RestrictedObject
|
||||
implements org.apache.guacamole.net.auth.permission.ObjectPermissionSet {
|
||||
|
||||
/**
|
||||
* The entity associated with this permission set. Each of the permissions
|
||||
* in this permission set is granted to this entity.
|
||||
*/
|
||||
private ModeledPermissions<? extends EntityModel> entity;
|
||||
|
||||
/**
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the entity.
|
||||
*/
|
||||
private Set<String> effectiveGroups;
|
||||
|
||||
/**
|
||||
* Creates a new ObjectPermissionSet. The resulting permission set
|
||||
* must still be initialized by a call to init(), or the information
|
||||
* necessary to read and modify this set will be missing.
|
||||
*/
|
||||
public ObjectPermissionSet() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this permission set with the current user and the entity
|
||||
* to whom the permissions in this set are granted.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user who queried this permission set, and whose permissions
|
||||
* dictate the access level of all operations performed on this set.
|
||||
*
|
||||
* @param entity
|
||||
* The entity to whom the permissions in this set are granted.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the entity.
|
||||
* If no groups are given, only permissions directly granted to the
|
||||
* entity will be used.
|
||||
*/
|
||||
public void init(ModeledAuthenticatedUser currentUser,
|
||||
ModeledPermissions<? extends EntityModel> entity,
|
||||
Set<String> effectiveGroups) {
|
||||
super.init(currentUser);
|
||||
this.entity = entity;
|
||||
this.effectiveGroups = effectiveGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ObjectPermissionService implementation for manipulating the
|
||||
* type of permissions contained within this permission set.
|
||||
*
|
||||
* @return
|
||||
* An object permission service for manipulating the type of
|
||||
* permissions contained within this permission set.
|
||||
*/
|
||||
protected abstract ObjectPermissionService getObjectPermissionService();
|
||||
|
||||
@Override
|
||||
public Set<ObjectPermission> getPermissions() throws GuacamoleException {
|
||||
return getObjectPermissionService().retrievePermissions(getCurrentUser(), entity, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(ObjectPermission.Type permission,
|
||||
String identifier) throws GuacamoleException {
|
||||
return getObjectPermissionService().hasPermission(getCurrentUser(), entity, permission, identifier, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPermission(ObjectPermission.Type permission,
|
||||
String identifier) throws GuacamoleException {
|
||||
addPermissions(Collections.singleton(new ObjectPermission(permission, identifier)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePermission(ObjectPermission.Type permission,
|
||||
String identifier) throws GuacamoleException {
|
||||
removePermissions(Collections.singleton(new ObjectPermission(permission, identifier)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getAccessibleObjects(Collection<ObjectPermission.Type> permissions,
|
||||
Collection<String> identifiers) throws GuacamoleException {
|
||||
return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), entity, permissions, identifiers, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPermissions(Set<ObjectPermission> permissions)
|
||||
throws GuacamoleException {
|
||||
getObjectPermissionService().createPermissions(getCurrentUser(), entity, permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePermissions(Set<ObjectPermission> permissions)
|
||||
throws GuacamoleException {
|
||||
getObjectPermissionService().deletePermissions(getCurrentUser(), entity, permissions);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import java.util.Collection;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Generic base for mappers which handle permissions.
|
||||
*
|
||||
* @param <PermissionType>
|
||||
* The type of permission model object handled by this mapper.
|
||||
*/
|
||||
public interface PermissionMapper<PermissionType> {
|
||||
|
||||
/**
|
||||
* Retrieves all permissions associated with the given entity (user or user
|
||||
* group).
|
||||
*
|
||||
* @param entity
|
||||
* The entity to retrieve permissions for.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the user. If
|
||||
* no groups are given, only permissions directly granted to the user
|
||||
* will be used.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The case sensitivity configuration for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* All permissions associated with the given entity.
|
||||
*/
|
||||
Collection<PermissionType> select(@Param("entity") EntityModel entity,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Inserts the given permissions into the database. If any permissions
|
||||
* already exist, they will be ignored.
|
||||
*
|
||||
* @param permissions
|
||||
* The permissions to insert.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The case sensitivity configuration for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* The number of rows inserted.
|
||||
*/
|
||||
int insert(@Param("permissions") Collection<PermissionType> permissions,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
/**
|
||||
* Deletes the given permissions from the database. If any permissions do
|
||||
* not exist, they will be ignored.
|
||||
*
|
||||
* @param permissions
|
||||
* The permissions to delete.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The case sensitivity configuration for usernames and group names.
|
||||
*
|
||||
* @return
|
||||
* The number of rows deleted.
|
||||
*/
|
||||
int delete(@Param("permissions") Collection<PermissionType> permissions,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
/**
|
||||
* Generic base permission model which grants a permission of a particular type
|
||||
* to a specific entity (user or user group).
|
||||
*
|
||||
* @param <PermissionType>
|
||||
* The type of permissions allowed within this model.
|
||||
*/
|
||||
public abstract class PermissionModel<PermissionType> {
|
||||
|
||||
/**
|
||||
* The database ID of the entity to whom this permission is granted.
|
||||
*/
|
||||
private Integer entityID;
|
||||
|
||||
/**
|
||||
* The type of action granted by this permission.
|
||||
*/
|
||||
private PermissionType type;
|
||||
|
||||
/**
|
||||
* Returns the database ID of the entity to whom this permission is
|
||||
* granted.
|
||||
*
|
||||
* @return
|
||||
* The database ID of the entity to whom this permission is granted.
|
||||
*/
|
||||
public Integer getEntityID() {
|
||||
return entityID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database ID of the entity to whom this permission is granted.
|
||||
*
|
||||
* @param entityID
|
||||
* The database ID of the entity to whom this permission is granted.
|
||||
*/
|
||||
public void setEntityID(Integer entityID) {
|
||||
this.entityID = entityID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of action granted by this permission.
|
||||
*
|
||||
* @return
|
||||
* The type of action granted by this permission.
|
||||
*/
|
||||
public PermissionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of action granted by this permission.
|
||||
*
|
||||
* @param type
|
||||
* The type of action granted by this permission.
|
||||
*/
|
||||
public void setType(PermissionType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.net.auth.permission.Permission;
|
||||
import org.apache.guacamole.net.auth.permission.PermissionSet;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting permissions, and for obtaining the permission sets that contain
|
||||
* these permissions. This service will automatically enforce the permissions
|
||||
* of the current user.
|
||||
*
|
||||
* @param <PermissionSetType>
|
||||
* The type of permission sets this service provides access to.
|
||||
*
|
||||
* @param <PermissionType>
|
||||
* The type of permission this service provides access to.
|
||||
*/
|
||||
public interface PermissionService<PermissionSetType extends PermissionSet<PermissionType>,
|
||||
PermissionType extends Permission> {
|
||||
|
||||
/**
|
||||
* Return the current case sensitivity setting, allowing the system to
|
||||
* determine if usernames and/or group names should be treated as case-
|
||||
* sensitive.
|
||||
*
|
||||
* @return
|
||||
* The current case sensitivity configuration.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs retrieving configuration information related to
|
||||
* case sensitivity.
|
||||
*/
|
||||
default CaseSensitivity getCaseSensitivity() throws GuacamoleException {
|
||||
|
||||
// By default identifiers are case-sensitive.
|
||||
return CaseSensitivity.ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a permission set that can be used to retrieve and manipulate the
|
||||
* permissions of the given entity.
|
||||
*
|
||||
* @param user
|
||||
* The user who will be retrieving or manipulating permissions through
|
||||
* the returned permission set.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity to whom the permissions in the returned permission set are
|
||||
* granted.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the entity.
|
||||
* If no groups are given, only permissions directly granted to the
|
||||
* entity will be used.
|
||||
*
|
||||
* @return
|
||||
* A permission set that contains all permissions associated with the
|
||||
* given entity, and can be used to manipulate that entity's
|
||||
* permissions.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the permissions of the given
|
||||
* entity, or if permission to retrieve the permissions of the given
|
||||
* entity is denied.
|
||||
*/
|
||||
PermissionSetType getPermissionSet(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Retrieves all permissions associated with the given entity.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the permissions.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity associated with the permissions to be retrieved.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the entity.
|
||||
* If no groups are given, only permissions directly granted to the
|
||||
* entity will be used.
|
||||
*
|
||||
* @return
|
||||
* The permissions associated with the given entity.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the requested permissions.
|
||||
*/
|
||||
Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Creates the given permissions within the database. If any permissions
|
||||
* already exist, they will be ignored.
|
||||
*
|
||||
* @param user
|
||||
* The user creating the permissions.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity associated with the permissions to be created.
|
||||
*
|
||||
* @param permissions
|
||||
* The permissions to create.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the user lacks permission to create the permissions, or an error
|
||||
* occurs while creating the permissions.
|
||||
*/
|
||||
void createPermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<PermissionType> permissions)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Deletes the given permissions. If any permissions do not exist, they
|
||||
* will be ignored.
|
||||
*
|
||||
* @param user
|
||||
* The user deleting the permissions.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity associated with the permissions to be deleted.
|
||||
*
|
||||
* @param permissions
|
||||
* The permissions to delete.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the user lacks permission to delete the permissions, or an error
|
||||
* occurs while deleting the permissions.
|
||||
*/
|
||||
void deletePermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<PermissionType> permissions)
|
||||
throws GuacamoleException;
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
/**
|
||||
* Mapper for sharing profile permissions.
|
||||
*/
|
||||
public interface SharingProfilePermissionMapper
|
||||
extends ObjectPermissionMapper {}
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting sharing profile permissions. This service will automatically enforce
|
||||
* the permissions of the current user.
|
||||
*/
|
||||
public class SharingProfilePermissionService extends ModeledObjectPermissionService {
|
||||
|
||||
/**
|
||||
* Mapper for sharing profile permissions.
|
||||
*/
|
||||
@Inject
|
||||
private SharingProfilePermissionMapper sharingProfilePermissionMapper;
|
||||
|
||||
/**
|
||||
* Provider for sharing profile permission sets.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<SharingProfilePermissionSet> sharingProfilePermissionSetProvider;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionMapper getPermissionMapper() {
|
||||
return sharingProfilePermissionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Create permission set for requested entity
|
||||
ObjectPermissionSet permissionSet = sharingProfilePermissionSetProvider.get();
|
||||
permissionSet.init(user, targetEntity, effectiveGroups);
|
||||
|
||||
return permissionSet;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* A database implementation of ObjectPermissionSet which uses an injected
|
||||
* service to query and manipulate the sharing profile permissions associated
|
||||
* with a particular user.
|
||||
*/
|
||||
public class SharingProfilePermissionSet extends ObjectPermissionSet {
|
||||
|
||||
/**
|
||||
* Service for querying and manipulating sharing profile permissions.
|
||||
*/
|
||||
@Inject
|
||||
private SharingProfilePermissionService sharingProfilePermissionService;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionService getObjectPermissionService() {
|
||||
return sharingProfilePermissionService;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import java.util.Collection;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* Mapper for system-level permissions.
|
||||
*/
|
||||
public interface SystemPermissionMapper extends PermissionMapper<SystemPermissionModel> {
|
||||
|
||||
/**
|
||||
* Retrieve the permission of the given type associated with the given
|
||||
* entity, if it exists. If no such permission exists, null is returned.
|
||||
*
|
||||
* @param entity
|
||||
* The entity to retrieve permissions for.
|
||||
*
|
||||
* @param type
|
||||
* The type of permission to return.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the user. If
|
||||
* no groups are given, only permissions directly granted to the user
|
||||
* will be used.
|
||||
*
|
||||
* @param caseSensitivity
|
||||
* The case sensitivity configuration, used to determine whether usernames
|
||||
* and/or group names will be treated as case-sensitive.
|
||||
*
|
||||
* @return
|
||||
* The requested permission, or null if no such permission is granted
|
||||
* to the given entity.
|
||||
*/
|
||||
SystemPermissionModel selectOne(@Param("entity") EntityModel entity,
|
||||
@Param("type") SystemPermission.Type type,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitivity") CaseSensitivity caseSensitivity);
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermission;
|
||||
|
||||
/**
|
||||
* Object representation of an system-level Guacamole permission, as
|
||||
* represented in the database.
|
||||
*/
|
||||
public class SystemPermissionModel extends PermissionModel<SystemPermission.Type> {
|
||||
|
||||
/**
|
||||
* Creates a new, empty System permission.
|
||||
*/
|
||||
public SystemPermissionModel() {
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.GuacamoleUnsupportedException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting system permissions. This service will automatically enforce
|
||||
* the permissions of the current user.
|
||||
*/
|
||||
public class SystemPermissionService
|
||||
extends ModeledPermissionService<SystemPermissionSet, SystemPermission, SystemPermissionModel> {
|
||||
|
||||
/**
|
||||
* Mapper for system-level permissions.
|
||||
*/
|
||||
@Inject
|
||||
private SystemPermissionMapper systemPermissionMapper;
|
||||
|
||||
/**
|
||||
* Provider for creating system permission sets.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<SystemPermissionSet> systemPermissionSetProvider;
|
||||
|
||||
@Override
|
||||
protected SystemPermissionMapper getPermissionMapper() {
|
||||
return systemPermissionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SystemPermission getPermissionInstance(SystemPermissionModel model) {
|
||||
return new SystemPermission(model.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SystemPermissionModel getModelInstance(
|
||||
final ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
final SystemPermission permission) {
|
||||
|
||||
SystemPermissionModel model = new SystemPermissionModel();
|
||||
|
||||
// Populate model object with data from entity and permission
|
||||
model.setEntityID(targetEntity.getModel().getEntityID());
|
||||
model.setType(permission.getType());
|
||||
|
||||
return model;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Create permission set for requested entity
|
||||
SystemPermissionSet permissionSet = systemPermissionSetProvider.get();
|
||||
permissionSet.init(user, targetEntity, effectiveGroups);
|
||||
|
||||
return permissionSet;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createPermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<SystemPermission> permissions) throws GuacamoleException {
|
||||
|
||||
// Only privileged users (such as system administrators) can create
|
||||
// system permissions
|
||||
if (user.isPrivileged()) {
|
||||
|
||||
// Pull identifier case sensitivity
|
||||
CaseSensitivity caseSensitivity = getCaseSensitivity();
|
||||
|
||||
batchPermissionUpdates(permissions, permissionSubset -> {
|
||||
Collection<SystemPermissionModel> models = getModelInstances(
|
||||
targetEntity, permissionSubset);
|
||||
systemPermissionMapper.insert(models, caseSensitivity);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// User lacks permission to create system permissions
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePermissions(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Collection<SystemPermission> permissions) throws GuacamoleException {
|
||||
|
||||
// Only privileged users (such as system administrators) can delete
|
||||
// system permissions
|
||||
if (user.isPrivileged()) {
|
||||
|
||||
// Do not allow users to remove their own admin powers
|
||||
if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier()))
|
||||
throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed.");
|
||||
|
||||
// Pull case sensitivity
|
||||
CaseSensitivity caseSensitivity = getCaseSensitivity();
|
||||
|
||||
batchPermissionUpdates(permissions, permissionSubset -> {
|
||||
Collection<SystemPermissionModel> models = getModelInstances(
|
||||
targetEntity, permissionSubset);
|
||||
systemPermissionMapper.delete(models, caseSensitivity);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// User lacks permission to delete system permissions
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves whether the permission of the given type has been granted to
|
||||
* the given entity. Permission inheritance through group membership is
|
||||
* taken into account.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the permission.
|
||||
*
|
||||
* @param targetEntity
|
||||
* The entity associated with the permission to be retrieved.
|
||||
*
|
||||
* @param type
|
||||
* The type of permission to retrieve.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the entity.
|
||||
* If no groups are given, only permissions directly granted to the
|
||||
* entity will be used.
|
||||
*
|
||||
* @return
|
||||
* true if permission of the given type has been granted to the given
|
||||
* entity, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving the requested permission.
|
||||
*/
|
||||
public boolean hasPermission(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
SystemPermission.Type type, Set<String> effectiveGroups)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Retrieve permissions only if allowed
|
||||
if (canReadPermissions(user, targetEntity))
|
||||
return getPermissionMapper().selectOne(targetEntity.getModel(), type, effectiveGroups, getCaseSensitivity()) != null;
|
||||
|
||||
// User cannot read this entity's permissions
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
|
||||
import org.apache.guacamole.net.auth.permission.SystemPermission;
|
||||
|
||||
/**
|
||||
* A database implementation of SystemPermissionSet which uses an injected
|
||||
* service to query and manipulate the system permissions associated with a
|
||||
* particular entity.
|
||||
*/
|
||||
public class SystemPermissionSet extends RestrictedObject
|
||||
implements org.apache.guacamole.net.auth.permission.SystemPermissionSet {
|
||||
|
||||
/**
|
||||
* The entity associated with this permission set. Each of the permissions
|
||||
* in this permission set is granted to this entity.
|
||||
*/
|
||||
private ModeledPermissions<? extends EntityModel> entity;
|
||||
|
||||
/**
|
||||
* The identifiers of all groups that should be taken into account when
|
||||
* determining the permissions effectively granted to the entity.
|
||||
*/
|
||||
private Set<String> effectiveGroups;
|
||||
|
||||
/**
|
||||
* Service for reading and manipulating system permissions.
|
||||
*/
|
||||
@Inject
|
||||
private SystemPermissionService systemPermissionService;
|
||||
|
||||
/**
|
||||
* Creates a new SystemPermissionSet. The resulting permission set
|
||||
* must still be initialized by a call to init(), or the information
|
||||
* necessary to read and modify this set will be missing.
|
||||
*/
|
||||
public SystemPermissionSet() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this permission set with the current user and the entity
|
||||
* to whom the permissions in this set are granted.
|
||||
*
|
||||
* @param currentUser
|
||||
* The user who queried this permission set, and whose permissions
|
||||
* dictate the access level of all operations performed on this set.
|
||||
*
|
||||
* @param entity
|
||||
* The entity to whom the permissions in this set are granted.
|
||||
*
|
||||
* @param effectiveGroups
|
||||
* The identifiers of all groups that should be taken into account
|
||||
* when determining the permissions effectively granted to the entity.
|
||||
* If no groups are given, only permissions directly granted to the
|
||||
* entity will be used.
|
||||
*/
|
||||
public void init(ModeledAuthenticatedUser currentUser,
|
||||
ModeledPermissions<? extends EntityModel> entity,
|
||||
Set<String> effectiveGroups) {
|
||||
super.init(currentUser);
|
||||
this.entity = entity;
|
||||
this.effectiveGroups = effectiveGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SystemPermission> getPermissions() throws GuacamoleException {
|
||||
return systemPermissionService.retrievePermissions(getCurrentUser(), entity, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(SystemPermission.Type permission)
|
||||
throws GuacamoleException {
|
||||
return systemPermissionService.hasPermission(getCurrentUser(), entity, permission, effectiveGroups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPermission(SystemPermission.Type permission)
|
||||
throws GuacamoleException {
|
||||
addPermissions(Collections.singleton(new SystemPermission(permission)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePermission(SystemPermission.Type permission)
|
||||
throws GuacamoleException {
|
||||
removePermissions(Collections.singleton(new SystemPermission(permission)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPermissions(Set<SystemPermission> permissions)
|
||||
throws GuacamoleException {
|
||||
systemPermissionService.createPermissions(getCurrentUser(), entity, permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePermissions(Set<SystemPermission> permissions)
|
||||
throws GuacamoleException {
|
||||
systemPermissionService.deletePermissions(getCurrentUser(), entity, permissions);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
/**
|
||||
* Mapper for user group permissions.
|
||||
*/
|
||||
public interface UserGroupPermissionMapper extends ObjectPermissionMapper {}
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting user group permissions. This service will automatically enforce the
|
||||
* permissions of the current user.
|
||||
*/
|
||||
public class UserGroupPermissionService extends ModeledObjectPermissionService {
|
||||
|
||||
/**
|
||||
* Mapper for user group permissions.
|
||||
*/
|
||||
@Inject
|
||||
private UserGroupPermissionMapper userGroupPermissionMapper;
|
||||
|
||||
/**
|
||||
* Provider for user group permission sets.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<UserGroupPermissionSet> userGroupPermissionSetProvider;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionMapper getPermissionMapper() {
|
||||
return userGroupPermissionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Create permission set for requested entity
|
||||
ObjectPermissionSet permissionSet = userGroupPermissionSetProvider.get();
|
||||
permissionSet.init(user, targetEntity, effectiveGroups);
|
||||
|
||||
return permissionSet;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* A database implementation of ObjectPermissionSet which uses an injected
|
||||
* service to query and manipulate the user group permissions associated with a
|
||||
* particular user.
|
||||
*/
|
||||
public class UserGroupPermissionSet extends ObjectPermissionSet {
|
||||
|
||||
/**
|
||||
* Service for querying and manipulating user group permissions.
|
||||
*/
|
||||
@Inject
|
||||
private UserGroupPermissionService userGroupPermissionService;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionService getObjectPermissionService() {
|
||||
return userGroupPermissionService;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
/**
|
||||
* Mapper for user permissions.
|
||||
*/
|
||||
public interface UserPermissionMapper extends ObjectPermissionMapper {}
|
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Set;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.base.EntityModel;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.properties.CaseSensitivity;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
* deleting user permissions. This service will automatically enforce the
|
||||
* permissions of the current user.
|
||||
*/
|
||||
public class UserPermissionService extends ModeledObjectPermissionService {
|
||||
|
||||
/**
|
||||
* Mapper for user permissions.
|
||||
*/
|
||||
@Inject
|
||||
private UserPermissionMapper userPermissionMapper;
|
||||
|
||||
/**
|
||||
* Provider for user permission sets.
|
||||
*/
|
||||
@Inject
|
||||
private Provider<UserPermissionSet> userPermissionSetProvider;
|
||||
|
||||
/**
|
||||
* The server environment for retrieving configuration data.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
@Override
|
||||
public CaseSensitivity getCaseSensitivity() throws GuacamoleException {
|
||||
return environment.getCaseSensitivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionMapper getPermissionMapper() {
|
||||
return userPermissionMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
|
||||
ModeledPermissions<? extends EntityModel> targetEntity,
|
||||
Set<String> effectiveGroups) throws GuacamoleException {
|
||||
|
||||
// Create permission set for requested entity
|
||||
ObjectPermissionSet permissionSet = userPermissionSetProvider.get();
|
||||
permissionSet.init(user, targetEntity, effectiveGroups);
|
||||
|
||||
return permissionSet;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
* A database implementation of ObjectPermissionSet which uses an injected
|
||||
* service to query and manipulate the user permissions associated with a
|
||||
* particular user.
|
||||
*/
|
||||
public class UserPermissionSet extends ObjectPermissionSet {
|
||||
|
||||
/**
|
||||
* Service for querying and manipulating user permissions.
|
||||
*/
|
||||
@Inject
|
||||
private UserPermissionService userPermissionService;
|
||||
|
||||
@Override
|
||||
protected ObjectPermissionService getObjectPermissionService() {
|
||||
return userPermissionService;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Classes related to object- and system-level permissions.
|
||||
*/
|
||||
package org.apache.guacamole.auth.jdbc.permission;
|
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.security;
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to set a user's password to a string which
|
||||
* contains their own username, in violation of the defined password policy.
|
||||
*/
|
||||
public class PasswordContainsUsernameException extends PasswordPolicyException {
|
||||
|
||||
/**
|
||||
* Creates a new PasswordContainsUsernameException with the given
|
||||
* human-readable message. The translatable message is already defined.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the password policy violation
|
||||
* that occurred.
|
||||
*/
|
||||
public PasswordContainsUsernameException(String message) {
|
||||
super(message, "PASSWORD_POLICY.ERROR_CONTAINS_USERNAME");
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user