Initial commit.

The application can connect to the MariaDB database and Wallix Bastion.
This commit is contained in:
2025-10-24 11:36:35 +01:00
commit 6e69e54096
10 changed files with 492 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/target/
/.classpath
/.mvn/
/.settings/
/.project

47
pom.xml Normal file
View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cm.soungui.guacamole</groupId>
<artifactId>guacamole-ext-wallix-sync</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>guacamole-ext-wallix-sync</name>
<description>Guacamole extension for synchronizing parameters from Wallix Bastion.</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- Guacamole Extension API -->
<dependency>
<groupId>org.apache.guacamole</groupId>
<artifactId>guacamole-ext</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency>
<!-- Slf4j API -->
<!-- This is needed only if your listener wants to
write to the Guacamole web application log -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,88 @@
package cm.soungui.guacamole.ext.wallix.sync;
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
import org.apache.guacamole.properties.LongGuacamoleProperty;
import org.apache.guacamole.properties.StringGuacamoleProperty;
public class Configuration {
public static LongGuacamoleProperty UPDATE_INTERVAL = new LongGuacamoleProperty() {
@Override
public String getName() {
return "wallix-sync-interval";
}
};
public static StringGuacamoleProperty MYSQL_HOSTNAME = new StringGuacamoleProperty() {
@Override
public String getName() {
return "mysql-hostname";
}
};
public static IntegerGuacamoleProperty MYSQL_PORT = new IntegerGuacamoleProperty() {
@Override
public String getName() {
return "mysql-port";
}
};
public static StringGuacamoleProperty MYSQL_DB = new StringGuacamoleProperty() {
@Override
public String getName() {
return "mysql-database";
}
};
public static StringGuacamoleProperty MYSQL_USERNAME = new StringGuacamoleProperty() {
@Override
public String getName() {
return "mysql-username";
}
};
public static StringGuacamoleProperty MYSQL_PASSWORD = new StringGuacamoleProperty() {
@Override
public String getName() {
return "mysql-password";
}
};
public static StringGuacamoleProperty MYSQL_SSL_MODE = new StringGuacamoleProperty() {
@Override
public String getName() {
return "mysql-ssl-mode";
}
};
public static StringGuacamoleProperty WALLIX_URL = new StringGuacamoleProperty() {
@Override
public String getName() {
return "wallix-url";
}
};
public static StringGuacamoleProperty WALLIX_USER = new StringGuacamoleProperty() {
@Override
public String getName() {
return "wallix-user";
}
};
public static StringGuacamoleProperty WALLIX_AUTH_KEY = new StringGuacamoleProperty() {
@Override
public String getName() {
return "wallix-auth-key";
}
};
}

View File

@@ -0,0 +1,113 @@
package cm.soungui.guacamole.ext.wallix.sync;
import java.net.Socket;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.environment.LocalEnvironment;
public class Wallix {
private static Wallix INSTANCE;
private static String HEADER_AUTH_USER = "X-Auth-User";
private static String HEADER_AUTH_KEY = "X-Auth-Key";
private String url;
private String user;
private String authKey;
private Wallix() throws GuacamoleException {
Environment environment = LocalEnvironment.getInstance();
url = environment.getRequiredProperty(Configuration.WALLIX_URL);
user = environment.getRequiredProperty(Configuration.WALLIX_USER);
authKey = environment.getRequiredProperty(Configuration.WALLIX_AUTH_KEY);
}
TrustManager[] trustAllCerts = new X509ExtendedTrustManager[]{
new X509ExtendedTrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0]; // Not used
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Trust all client certificates
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Trust all server certificates
}
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1, Socket arg2)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1, SSLEngine arg2)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1, Socket arg2)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1, SSLEngine arg2)
throws CertificateException {
// TODO Auto-generated method stub
}
}
};
public static Wallix getInstance() throws GuacamoleException {
if (INSTANCE == null) {
INSTANCE = new Wallix();
}
return INSTANCE;
}
public String get(String query) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url + query))
.setHeader(HEADER_AUTH_USER, user)
.setHeader(HEADER_AUTH_KEY, authKey)
.build();
// TODO Disable this section before release and make this configurable
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new SecureRandom());
HttpClient client = HttpClient.newBuilder().sslContext(sslContext).build();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response.body();
} catch (Exception e) {
throw e;
}
}
}

View File

@@ -0,0 +1,60 @@
package cm.soungui.guacamole.ext.wallix.sync;
import java.util.List;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.LocalEnvironment;
import cm.soungui.guacamole.ext.wallix.sync.db.DB;
import cm.soungui.guacamole.ext.wallix.sync.db.UserGroup;
public class WallixConfigSynchronizer implements Runnable {
private long sleepDuration;
private LocalEnvironment environment;
public WallixConfigSynchronizer() throws GuacamoleException {
System.out.println("Wazuh synchronizer Thread started");
environment = LocalEnvironment.getInstance();
sleepDuration = 1000 * environment.getProperty(Configuration.UPDATE_INTERVAL, Long.valueOf(900));
}
@Override
public void run() {
while (true) {
try {
System.out.println("Fetching config");
synchronizeGroups();
Thread.sleep(sleepDuration);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
private void synchronizeGroups() throws Exception {
System.out.println("Synchronizing groups");
System.out.println("Getting Wallix groups");
printWallixVersion();
getWallixGroups();
DB db = DB.getInstance();
List<UserGroup> groups = db.getUserGroups();
for (UserGroup group : groups) {
System.out.println("ID : " + group.getId() + " - Name : " + group.getName());
}
}
private void printWallixVersion() throws Exception {
Wallix wallix = Wallix.getInstance();
String output = wallix.get("/version");
System.out.println(output);
}
private void getWallixGroups() throws Exception {
Wallix wallix = Wallix.getInstance();
String output = wallix.get("/usergroups");
System.out.println(output);
}
}

View File

@@ -0,0 +1,79 @@
package cm.soungui.guacamole.ext.wallix.sync.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.environment.LocalEnvironment;
import cm.soungui.guacamole.ext.wallix.sync.Configuration;
public class DB {
private static DB instance = new DB();
private Connection mysqlConnection;
public Connection getMySQLConnection() throws GuacamoleException {
try {
if (mysqlConnection == null) {
Environment environment = LocalEnvironment.getInstance();
String hostname = environment.getProperty(Configuration.MYSQL_HOSTNAME, "localhost");
int port = environment.getProperty(Configuration.MYSQL_PORT, 3306);
String database = environment.getProperty(Configuration.MYSQL_DB, "guacamole_db");
String username = environment.getProperty(Configuration.MYSQL_USERNAME);
String password = environment.getProperty(Configuration.MYSQL_PASSWORD);
String sslMode = environment.getProperty(Configuration.MYSQL_SSL_MODE, "disable");
String url = new StringBuffer("jdbc:mariadb://")
.append(hostname)
.append(":").append(port).append("/")
.append(database).append("?")
.append(username == null ? "" : "user=" + username + "&")
.append(password == null ? "" : "password=" + password + "&")
.append(sslMode == null ? "" : "sslMode=" + sslMode + "&")
.toString();
System.out.println("JDBC URL : " + url);
Class.forName("org.mariadb.jdbc.Driver");
mysqlConnection = DriverManager.getConnection(url);
System.out.println("Connected to Database");
}
return mysqlConnection;
} catch (Exception e) {
throw new GuacamoleException(e);
}
}
public static DB getInstance() {
return instance;
}
public List<UserGroup> getUserGroups() throws GuacamoleException, SQLException {
DB db = DB.getInstance();
Connection connection = db.getMySQLConnection();
ResultSet rs = connection
.prepareStatement("select entity_id,name from guacamole_entity where type='USER_GROUP'")
.executeQuery();
ArrayList<UserGroup> groups = new ArrayList<>();
while (rs.next()) {
UserGroup group = new UserGroup();
group.setId(rs.getInt("entity_id"));
group.setName(rs.getString("name"));
groups.add(group);
}
return groups;
}
}

View File

@@ -0,0 +1,37 @@
package cm.soungui.guacamole.ext.wallix.sync.db;
public class Entity {
public static enum EntityType { USER, GROUP };
private int id;
private String name;
public EntityType type;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public EntityType getType() {
return type;
}
public void setType(EntityType type) {
this.type = type;
}
}

View File

@@ -0,0 +1,29 @@
package cm.soungui.guacamole.ext.wallix.sync.db;
import java.util.ArrayList;
import java.util.List;
public class UserGroup extends Entity {
private int groupId;
private List<Entity> members = new ArrayList<>();
@Override
public EntityType getType() {
return EntityType.GROUP;
}
public int getGroupId() {
return groupId;
}
public void setGroupId(int groupId) {
this.groupId = groupId;
}
public List<Entity> getMembers() {
return members;
}
}

View File

@@ -0,0 +1,22 @@
package cm.soungui.guacamole.ext.wallix.sync.listener;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.event.ApplicationStartedEvent;
import org.apache.guacamole.net.event.listener.Listener;
import cm.soungui.guacamole.ext.wallix.sync.WallixConfigSynchronizer;
public class ApplicationStartedListener implements Listener {
private WallixConfigSynchronizer synchronizer;
@Override
public void handleEvent(Object event) throws GuacamoleException {
if (event instanceof ApplicationStartedEvent) {
synchronizer = new WallixConfigSynchronizer();
Thread thread = new Thread(synchronizer);
thread.start();
}
}
}

View File

@@ -0,0 +1,12 @@
{
"guacamoleVersion" : "1.6.0",
"name" : "Soungui Wallix Synchronizer extension",
"namespace" : "soungui-wallix-synchronizer-extension",
"listeners" : [
"cm.soungui.guacamole.ext.wallix.sync.listener.ApplicationStartedListener"
]
}