-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit eb62a72
Showing
6 changed files
with
780 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
target/ | ||
.*.swp |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
guacamole-auth-redis | ||
==================== | ||
|
||
[Guacamole](http://guac-dev.org/) Redis authentication plugin. | ||
|
||
|
||
Build | ||
----- | ||
|
||
- Clone the [git repository](https://github.com/erigones/guacamole-auth-redis.git): | ||
|
||
git clone https://github.com/erigones/guacamole-auth-redis.git | ||
|
||
- Compile. This will create a new jar file `guacamole-auth-redis-VERSION.jar` in the `target/` folder: | ||
|
||
cd guacamole-auth-redis | ||
mvn package | ||
|
||
Install | ||
------- | ||
|
||
- Copy `guacamole-auth-redis-VERSION.jar` into `webapps/guacamole/WEB-INF/lib/`. It does not work if you copy the jar into common/lib/ or shared/lib/. | ||
|
||
- Download [redis.jar](https://github.com/xetorthio/jedis/downloads) into `webapps/guacamole/WEB-INF/lib/`. | ||
|
||
|
||
Configure | ||
--------- | ||
|
||
- Edit the Guacamole configuration file (`/etc/guacamole/guacamole.properties`): | ||
|
||
# Auth provider class | ||
auth-provider: com.erigones.guacamole.net.auth.redis.RedisAuthenticationProvider | ||
|
||
# Redis properties | ||
redis-host: localhost | ||
redis-port: 6379 | ||
#redis-parent: myparent: | ||
#redis-password: secret | ||
#redis-timeout: 2 | ||
|
||
- Restart guacamole. | ||
|
||
|
||
Use | ||
--- | ||
|
||
- To create a user mapping for user "testuser" with one VNC connection named "connection1": | ||
|
||
redis> HSET testuser password "SecretPassw0rd" | ||
|
||
redis> HSET testuser connection1 "protocol=vnc\nhostname=localhost\nport=5900\npassword=VNCPASS" | ||
|
||
- You can use redis *pipelines* for grouping operations into transactions and reducing overhead. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<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>com.erigones.guacamole</groupId> | ||
<artifactId>guacamole-auth-redis</artifactId> | ||
<packaging>jar</packaging> | ||
<version>0.1.0</version> | ||
<name>guacamole-auth-redis</name> | ||
<url>https://github.com/erigones/guacamole-auth-redis</url> | ||
|
||
<properties> | ||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
</properties> | ||
|
||
<build> | ||
<plugins> | ||
<!-- Written for 1.6 --> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-compiler-plugin</artifactId> | ||
<configuration> | ||
<source>1.6</source> | ||
<target>1.6</target> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
<dependencies> | ||
<!-- SLF4J - logging --> | ||
<dependency> | ||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-api</artifactId> | ||
<version>1.6.1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.slf4j</groupId> | ||
<artifactId>slf4j-jcl</artifactId> | ||
<version>1.6.1</version> | ||
<scope>runtime</scope> | ||
</dependency> | ||
|
||
<!-- Guacamole Java API --> | ||
<dependency> | ||
<groupId>org.glyptodon.guacamole</groupId> | ||
<artifactId>guacamole-common</artifactId> | ||
<version>0.8.0</version> | ||
</dependency> | ||
|
||
<!-- Guacamole Extension API --> | ||
<dependency> | ||
<groupId>org.glyptodon.guacamole</groupId> | ||
<artifactId>guacamole-ext</artifactId> | ||
<version>0.8.1</version> | ||
</dependency> | ||
|
||
<!-- Jedis --> | ||
<dependency> | ||
<groupId>redis.clients</groupId> | ||
<artifactId>jedis</artifactId> | ||
<version>2.2.1</version> | ||
<type>jar</type> | ||
<scope>compile</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
152 changes: 152 additions & 0 deletions
152
src/main/java/com/erigones/guacamole/net/auth/redis/RedisAuthenticationProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package com.erigones.guacamole.net.auth.redis; | ||
|
||
|
||
import java.util.Map; | ||
import java.util.HashMap; | ||
import java.util.Properties; | ||
import java.io.StringReader; | ||
import java.io.IOException; | ||
import redis.clients.jedis.Jedis; | ||
import redis.clients.jedis.JedisPool; | ||
import redis.clients.jedis.JedisPoolConfig; | ||
import com.erigones.guacamole.net.auth.redis.properties.RedisGuacamoleProperties; | ||
import org.glyptodon.guacamole.GuacamoleException; | ||
import org.glyptodon.guacamole.net.auth.Credentials; | ||
import org.glyptodon.guacamole.net.auth.simple.SimpleAuthenticationProvider; | ||
import org.glyptodon.guacamole.properties.GuacamoleProperty; | ||
import org.glyptodon.guacamole.properties.GuacamoleProperties; | ||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
|
||
public class RedisAuthenticationProvider extends SimpleAuthenticationProvider { | ||
|
||
private static Logger logger = LoggerFactory.getLogger(RedisAuthenticationProvider.class); | ||
|
||
private static String redisParent; | ||
private static JedisPool pool; | ||
|
||
private static final <T> T getRedisProperty(GuacamoleProperty<T> propName, T def) { | ||
T redisProp = null; | ||
|
||
try { | ||
redisProp = GuacamoleProperties.getProperty(propName); | ||
|
||
if (redisProp == null) { | ||
throw new GuacamoleException("Configuration parameter \""+ propName.getName() +"\" is null."); | ||
} | ||
} catch (GuacamoleException e) { | ||
logger.error("{}", e.getMessage()); | ||
logger.error("Using default value of \"{}\" for configuration parameter \"{}\".", def, propName.getName()); | ||
redisProp = def; | ||
} | ||
|
||
return redisProp; | ||
} | ||
|
||
static { | ||
// Create jedis pool | ||
pool = new JedisPool(new JedisPoolConfig(), | ||
getRedisProperty(RedisGuacamoleProperties.REDIS_HOST, "localhost"), | ||
getRedisProperty(RedisGuacamoleProperties.REDIS_PORT, 6379), | ||
getRedisProperty(RedisGuacamoleProperties.REDIS_TIMEOUT, 2), | ||
getRedisProperty(RedisGuacamoleProperties.REDIS_PASSWORD, null) | ||
); | ||
|
||
// Set key prefix | ||
redisParent = getRedisProperty(RedisGuacamoleProperties.REDIS_PARENT, ""); | ||
} | ||
|
||
private Map<String, String> getMap(String key) { | ||
Jedis jedis = pool.getResource(); | ||
|
||
try { | ||
logger.info("Fetching key \"{}\" from redis.", key); | ||
return jedis.hgetAll(key); | ||
} finally { | ||
pool.returnResource(jedis); | ||
} | ||
} | ||
|
||
private Map<String, GuacamoleConfiguration> getUserConfigurations(Map<String, String> cfgMap) throws GuacamoleException { | ||
// Authorized configuration hash map | ||
Map<String, GuacamoleConfiguration> configs = new HashMap<String, GuacamoleConfiguration>(); | ||
|
||
for (Map.Entry<String, String> item : cfgMap.entrySet()) { | ||
// New empty configuration | ||
GuacamoleConfiguration config = new GuacamoleConfiguration(); | ||
|
||
// Parse connection parameters from item value | ||
Properties properties = new Properties(); | ||
try { | ||
properties.load(new StringReader(item.getValue())); | ||
} catch (IOException e) { | ||
throw new GuacamoleException("Error reading basic user mapping string.", e); | ||
} | ||
|
||
boolean protocol_found = false; | ||
// Iterate through properties | ||
for (String cfg_key : properties.stringPropertyNames()) { | ||
String cfg_val = properties.getProperty(cfg_key); | ||
|
||
if (cfg_key.equals("protocol")) { | ||
config.setProtocol(cfg_val); | ||
protocol_found = true; | ||
} else { | ||
config.setParameter(cfg_key, cfg_val); | ||
} | ||
} | ||
|
||
if (protocol_found) { | ||
// Add user config to user config map | ||
configs.put(item.getKey(), config); | ||
protocol_found = false; | ||
} else { | ||
throw new GuacamoleException("Missing protocol in connection \""+ item.getKey() +"\"."); | ||
} | ||
} | ||
|
||
return configs; | ||
} | ||
|
||
@Override | ||
public Map<String, GuacamoleConfiguration> getAuthorizedConfigurations(Credentials credentials) throws GuacamoleException { | ||
// We are using the username as redis key | ||
if (credentials.getUsername() == null) { | ||
return null; // Unauthorized | ||
} | ||
|
||
// Create the key | ||
String key = redisParent.concat(credentials.getUsername()); | ||
|
||
// Fetch the configuration from redis | ||
Map<String, String> map = getMap(key); | ||
|
||
// Check the value | ||
if (map == null || map.isEmpty()) { | ||
logger.warn("User mapping for key \"{}\" not found in redis.", key); | ||
return null; // Unauthorized | ||
} | ||
|
||
// Check password | ||
if (! credentials.getPassword().equals(map.get("password"))) { | ||
logger.warn("Password mismatch in user mapping for key \"{}\".", key); | ||
return null; | ||
} | ||
|
||
// Remove password (everything else is a connection) | ||
map.remove("password"); | ||
|
||
try { | ||
// Parse connections from remaining key/values in map | ||
return getUserConfigurations(map); | ||
|
||
} catch (GuacamoleException e) { | ||
logger.error("User mapping for key \"{}\" could not be parsed. Error was: \"{}\".", key, e.getMessage()); | ||
|
||
// Return empty configuration map since we are already authenticated | ||
return new HashMap<String, GuacamoleConfiguration>(); | ||
} | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
src/main/java/com/erigones/guacamole/net/auth/redis/properties/RedisGuacamoleProperties.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.erigones.guacamole.net.auth.redis.properties; | ||
|
||
import org.glyptodon.guacamole.properties.IntegerGuacamoleProperty; | ||
import org.glyptodon.guacamole.properties.StringGuacamoleProperty; | ||
|
||
public class RedisGuacamoleProperties { | ||
|
||
private RedisGuacamoleProperties() {} | ||
|
||
public static final StringGuacamoleProperty REDIS_HOST = new StringGuacamoleProperty() { | ||
@Override | ||
public String getName() { return "redis-host"; } | ||
}; | ||
|
||
public static final IntegerGuacamoleProperty REDIS_PORT = new IntegerGuacamoleProperty() { | ||
@Override | ||
public String getName() { return "redis-port"; } | ||
}; | ||
|
||
public static final IntegerGuacamoleProperty REDIS_TIMEOUT = new IntegerGuacamoleProperty() { | ||
@Override | ||
public String getName() { return "redis-timeout"; } | ||
}; | ||
|
||
public static final StringGuacamoleProperty REDIS_PASSWORD = new StringGuacamoleProperty() { | ||
@Override | ||
public String getName() { return "redis-password"; } | ||
}; | ||
|
||
public static final StringGuacamoleProperty REDIS_PARENT = new StringGuacamoleProperty() { | ||
@Override | ||
public String getName() { return "redis-parent"; } | ||
}; | ||
} |