From 416c388904d3989fe18b84523f3da3c9531c3b86 Mon Sep 17 00:00:00 2001
From: Felix Sidokhine <felix.sidokhine@randstad.ca>
Date: Tue, 12 May 2020 17:14:59 +0300
Subject: [PATCH] functional and tested flow for installation

---
 .../jami/jams/ad/connector/ADConnector.java   |  4 +-
 .../authmodule/UserAuthenticationModule.java  | 18 +++++
 .../net/jami/datastore/dao/SystemDao.java     | 19 ++++-
 .../net/jami/datastore/main/DataStore.java    |  2 +-
 integration-test/install-server.py            | 72 +++++++++++++++++
 .../csr/builders/SystemAccountBuilder.java    |  4 +-
 .../builders/SystemAccountBuilderTest.java    |  6 +-
 jams-common/src/main/java/module-info.java    |  1 +
 .../authentication/AuthenticationSource.java  |  2 +-
 .../local/LocalAuthSettings.java              | 11 +++
 .../authmodule/AuthenticationModule.java      |  1 +
 .../requests/CreateAuthSourceRequest.java     | 19 +++++
 .../objects/requests/CreateCARequest.java     | 16 ++++
 .../objects/requests/CredentialsRequest.java  | 13 ++++
 .../jams/common/objects/roots/X509Entity.java |  1 -
 .../jams/common/objects/roots/X509Fields.java |  1 +
 .../common/objects/system/SystemAccount.java  | 25 +++++-
 .../jams/common/server/ServerSettings.java    |  1 +
 .../net/jami/jams/common/utils/Validator.java | 28 +++++++
 .../java/net/jami/jams/server/Server.java     | 17 ++--
 .../core/workflows/InstallationFinalizer.java | 78 +++++++++++++++++++
 .../servlets/api/install/CachedObjects.java   | 17 ++++
 .../api/install/CreateAuthSourceServlet.java  | 36 ++++++++-
 .../servlets/api/install/CreateCAServlet.java | 12 ++-
 .../install/CreateGeneralSettingsServlet.java | 23 ------
 .../install/CreateServerSettingsServlet.java  | 35 +++++++++
 .../api/install/StartInstallServlet.java      | 14 +++-
 .../jams/ldap/connector/LDAPConnector.java    |  5 +-
 .../connector/service/UserProfileService.java |  4 +-
 29 files changed, 432 insertions(+), 53 deletions(-)
 create mode 100644 integration-test/install-server.py
 create mode 100644 jams-common/src/main/java/net/jami/jams/common/authentication/local/LocalAuthSettings.java
 create mode 100644 jams-common/src/main/java/net/jami/jams/common/objects/requests/CreateAuthSourceRequest.java
 create mode 100644 jams-common/src/main/java/net/jami/jams/common/objects/requests/CreateCARequest.java
 create mode 100644 jams-common/src/main/java/net/jami/jams/common/objects/requests/CredentialsRequest.java
 create mode 100644 jams-common/src/main/java/net/jami/jams/common/utils/Validator.java
 create mode 100644 jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java
 create mode 100644 jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CachedObjects.java
 delete mode 100644 jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateGeneralSettingsServlet.java
 create mode 100644 jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateServerSettingsServlet.java

diff --git a/ad-connector/src/main/java/net/jami/jams/ad/connector/ADConnector.java b/ad-connector/src/main/java/net/jami/jams/ad/connector/ADConnector.java
index 2be71eb9..de213aa6 100644
--- a/ad-connector/src/main/java/net/jami/jams/ad/connector/ADConnector.java
+++ b/ad-connector/src/main/java/net/jami/jams/ad/connector/ADConnector.java
@@ -87,8 +87,8 @@ public class ADConnector implements AuthenticationSource {
     }
 
     @Override
-    public boolean testConfiguration(String configuration) {
-        return false;
+    public boolean test() {
+        return authenticate(settings.getUsername(), settings.getPassword());
     }
 
     @Override
diff --git a/authentication-module/src/main/java/net/jami/jams/authmodule/UserAuthenticationModule.java b/authentication-module/src/main/java/net/jami/jams/authmodule/UserAuthenticationModule.java
index 2a99fb96..ce3fc7ea 100644
--- a/authentication-module/src/main/java/net/jami/jams/authmodule/UserAuthenticationModule.java
+++ b/authentication-module/src/main/java/net/jami/jams/authmodule/UserAuthenticationModule.java
@@ -33,6 +33,8 @@ public class UserAuthenticationModule implements AuthenticationModule {
     public UserAuthenticationModule(DataStore dataStore, CertificateAuthority certificateAuthority) {
         UserAuthenticationModule.datastore = dataStore;
         UserAuthenticationModule.certificateAuthority = certificateAuthority;
+        authenticationSources.put(new AuthModuleKey("LOCAL",AuthenticationSourceType.LOCAL),datastore);
+        log.info("Started authentication module - default local source is already enabled!");
     }
 
     @Override
@@ -103,4 +105,20 @@ public class UserAuthenticationModule implements AuthenticationModule {
     public HashMap<AuthModuleKey, AuthenticationSource> getAuthSources(){
         return authenticationSources;
     }
+
+    @Override
+    public boolean testModuleConfiguration(AuthenticationSourceType type, String settings) {
+        try {
+            String className = "";
+            if (type.equals(AuthenticationSourceType.AD)) className = AD_CONNECTOR_CLASS;
+            if (type.equals(AuthenticationSourceType.LDAP)) className = LDAP_CONNECTOR_CLASS;
+            Class<?> cls = LibraryLoader.classLoader.loadClass(className);
+            AuthenticationSource source = (AuthenticationSource) cls.getConstructor(String.class).newInstance(settings);
+            return source.test();
+        }
+        catch (Exception e){
+            log.error("The testing of the source was unsuccessful!");
+            return false;
+        }
+    }
 }
diff --git a/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java b/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java
index 1d269872..63545e50 100644
--- a/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java
+++ b/datastore/src/main/java/net/jami/datastore/dao/SystemDao.java
@@ -17,7 +17,7 @@ public class SystemDao extends AbstractDao<SystemAccount> {
         try {
             this.setTableName("system");
             this.setTClass(SystemAccount.class);
-            String createTable = "CREATE TABLE system (" +
+            String createTable = "CREATE TABLE "+ this.getTableName() + " (" +
                     "entity varchar(255), " +
                     "certificate varchar(5000), "+
                     "privatekey varchar(5000)," +
@@ -35,7 +35,22 @@ public class SystemDao extends AbstractDao<SystemAccount> {
 
     @Override
     public boolean storeObject(SystemAccount object) {
-        return false;
+        SQLConnection connection = DataStore.connectionPool.getConnection();
+        try{
+            PreparedStatement ps = connection.getConnection().prepareStatement("INSERT INTO system " +
+                    "(entity,certificate,privatekey)" +
+                    "VALUES " +
+                    "(?, ?, ?)");
+            ps = object.getInsert(ps);
+            return ps.execute();
+        }
+        catch (Exception e){
+            log.error("An error has occurred while trying to store a system entity: " + e.toString());
+            return false;
+        }
+        finally {
+            DataStore.connectionPool.returnConnection(connection);
+        }
     }
 
     @Override
diff --git a/datastore/src/main/java/net/jami/datastore/main/DataStore.java b/datastore/src/main/java/net/jami/datastore/main/DataStore.java
index 76ecca92..457f9074 100644
--- a/datastore/src/main/java/net/jami/datastore/main/DataStore.java
+++ b/datastore/src/main/java/net/jami/datastore/main/DataStore.java
@@ -67,7 +67,7 @@ public class DataStore implements AuthenticationSource {
     }
 
     @Override
-    public boolean testConfiguration(String configuration) {
+    public boolean test() {
         return true;
     }
 
diff --git a/integration-test/install-server.py b/integration-test/install-server.py
new file mode 100644
index 00000000..ca837e9b
--- /dev/null
+++ b/integration-test/install-server.py
@@ -0,0 +1,72 @@
+import requests
+import json
+
+data = {}
+data['username'] = "admin"
+data['password'] = "abc123"
+
+header = {}
+header['Content-type'] = "application/json"
+
+response = requests.put('http://localhost:8080/api/install/start',data=json.dumps(data),headers=header)
+if response.status_code == 200:
+    print("Succesfully created the administrative user!")
+    token = json.loads(response.text)['token']
+else:
+    print("Could not create admin user, the test has failed!")
+
+
+header['x-token'] = token
+
+data = {}
+data['fields'] = {}
+data['fields']['commonName'] = "TEST CA"
+data['fields']['country'] = "FR"
+data['fields']['lifetime'] = 10000000
+
+response = requests.post('http://localhost:8080/api/install/ca',data=json.dumps(data),headers=header)
+if response.status_code == 200:
+    print("Added CA parameters!")
+else:
+    print("Could not add CA parameters, the test has failed")
+
+
+data = {}
+data['type'] = "LDAP"
+data['ldapSettings'] = {}
+data['ldapSettings']['useStartTLS'] = True
+data['ldapSettings']['realm'] = "savoirfairelinux"
+data['ldapSettings']['baseDN'] = "ou=users,dc=savoirfairelinux,dc=net"
+data['ldapSettings']['host'] = "ldap://annuaire.savoirfairelinux.com"
+data['ldapSettings']['username'] = "cn=sipallow,ou=dsa,dc=savoirfairelinux,dc=net"
+data['ldapSettings']['password'] = "Dewaaghei3Yo"
+data['ldapSettings']['usernameField'] = "uid"
+data['ldapSettings']['fieldMappings'] = {}
+data['ldapSettings']['fieldMappings']['givenName'] = "FirstName"
+data['ldapSettings']['fieldMappings']['sn'] = "LastName"
+data['ldapSettings']['fieldMappings']['jpegPhoto'] = "ProfilePicture"
+data['ldapSettings']['fieldMappings']['mail'] = "Email"
+data['ldapSettings']['fieldMappings']['telephoneNumber'] = "PhoneNumber"
+data['ldapSettings']['fieldMappings']['mobile'] = "MobileNumber"
+data['ldapSettings']['fieldMappings']['facsimileTelephoneNumber'] = "FaxNumber"
+data['ldapSettings']['fieldMappings']['extensionName'] = "PhoneNumberExtension"
+data['ldapSettings']['fieldMappings']['o'] = "Organization"
+
+response = requests.post('http://localhost:8080/api/install/auth',data=json.dumps(data),headers=header)
+if response.status_code == 200:
+    print("Added LDAP parameters!")
+else:
+    print("Could not add LDAP parameters, the test has failed")
+
+
+data['serverDomain'] = "http://localhost"
+data['signingAlgorithm'] = "SHA512WITHRSA"
+data['crlLifetime'] = 100000
+data['userLifetime'] = 100000
+data['deviceLifetime'] = 100000
+
+response = requests.post('http://localhost:8080/api/install/settings',data=json.dumps(data),headers=header)
+if response.status_code == 200:
+    print("Finished Installation Successfully!")
+else:
+    print("Could not finish installation")
\ No newline at end of file
diff --git a/jams-ca/src/main/java/net/jami/jams/ca/workers/csr/builders/SystemAccountBuilder.java b/jams-ca/src/main/java/net/jami/jams/ca/workers/csr/builders/SystemAccountBuilder.java
index f6ab1e77..d656c8ce 100644
--- a/jams-ca/src/main/java/net/jami/jams/ca/workers/csr/builders/SystemAccountBuilder.java
+++ b/jams-ca/src/main/java/net/jami/jams/ca/workers/csr/builders/SystemAccountBuilder.java
@@ -29,7 +29,7 @@ public class SystemAccountBuilder {
                     new X500Name(systemAccount.getX509Fields().getDN()),
                     new BigInteger(256, new SecureRandom()),
                     new Date(System.currentTimeMillis()),
-                    new Date(System.currentTimeMillis() + systemAccount.getLifetime()),
+                    new Date(System.currentTimeMillis() + systemAccount.getX509Fields().getLifetime()),
                     new X500Name(systemAccount.getX509Fields().getDN()),
                     SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded())
             );
@@ -54,7 +54,7 @@ public class SystemAccountBuilder {
                     new JcaX509CertificateHolder(JamsCA.CA.getCertificate()).getSubject(),
                     new BigInteger(256, new SecureRandom()),
                     new Date(System.currentTimeMillis()),
-                    new Date(System.currentTimeMillis() + systemAccount.getLifetime()),
+                    new Date(System.currentTimeMillis() + systemAccount.getX509Fields().getLifetime()),
                     new X500Name("CN=" + systemAccount.getX509Fields().getDN()),
                     SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded())
             );
diff --git a/jams-ca/src/test/java/net/jami/jams/ca/workers/csr/builders/SystemAccountBuilderTest.java b/jams-ca/src/test/java/net/jami/jams/ca/workers/csr/builders/SystemAccountBuilderTest.java
index 71dba13f..c9fdd70d 100644
--- a/jams-ca/src/test/java/net/jami/jams/ca/workers/csr/builders/SystemAccountBuilderTest.java
+++ b/jams-ca/src/test/java/net/jami/jams/ca/workers/csr/builders/SystemAccountBuilderTest.java
@@ -38,7 +38,7 @@ class SystemAccountBuilderTest {
         caAccount.setX509Fields(new X509Fields());
         caAccount.getX509Fields().setCommonName("Test CA");
         caAccount.getX509Fields().setCountry("FR");
-        caAccount.setLifetime(10000000L);
+        caAccount.getX509Fields().setLifetime(10000000L);
         caAccount = SystemAccountBuilder.generateCA(caAccount);
         Assertions.assertNotNull(caAccount.getCertificate(),"CA Certificate was not generated!");
 
@@ -49,7 +49,7 @@ class SystemAccountBuilderTest {
         ocspAccount.setSystemAccountType(SystemAccountType.OCSP);
         ocspAccount.setX509Fields(new X509Fields());
         ocspAccount.getX509Fields().setCommonName("OCSP Server");
-        ocspAccount.setLifetime(10000000L);
+        ocspAccount.getX509Fields().setLifetime(10000000L);
         ocspAccount = SystemAccountBuilder.generateOCSP(ocspAccount);
         Assertions.assertNotNull(ocspAccount.getCertificate(),"OCSP Certificate was not generated!");
 
@@ -76,7 +76,7 @@ class SystemAccountBuilderTest {
         caAccount.setX509Fields(new X509Fields());
         caAccount.getX509Fields().setCommonName("Test CA");
         caAccount.getX509Fields().setCountry("FR");
-        caAccount.setLifetime(10000000L);
+        caAccount.getX509Fields().setLifetime(10000000L);
         caAccount = SystemAccountBuilder.generateCA(caAccount);
         Assertions.assertNotNull(caAccount.getCertificate(),"CA Certificate was not generated!");
         CertificateAuthorityConfig config = new CertificateAuthorityConfig();
diff --git a/jams-common/src/main/java/module-info.java b/jams-common/src/main/java/module-info.java
index fcc8f2d3..2d38ebbb 100644
--- a/jams-common/src/main/java/module-info.java
+++ b/jams-common/src/main/java/module-info.java
@@ -48,6 +48,7 @@ module jams.common {
     exports net.jami.jams.common.jami;
     exports net.jami.jams.common.authmodule;
     exports net.jami.jams.common.server;
+    exports net.jami.jams.common.authentication.local;
     requires jdk.crypto.cryptoki;
     requires java.base;
     requires java.sql;
diff --git a/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSource.java b/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSource.java
index ab1e1b5c..1b27f44b 100644
--- a/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSource.java
+++ b/jams-common/src/main/java/net/jami/jams/common/authentication/AuthenticationSource.java
@@ -9,7 +9,7 @@ public interface AuthenticationSource {
     UserProfile[] getUserProfile(String queryString, String field);
     boolean authenticate(String username, String password);
     AuthenticationSourceInfo getInfo();
-    boolean testConfiguration(String configuration);
+    boolean test();
     boolean updatePassword(User user, String password);
 
 }
diff --git a/jams-common/src/main/java/net/jami/jams/common/authentication/local/LocalAuthSettings.java b/jams-common/src/main/java/net/jami/jams/common/authentication/local/LocalAuthSettings.java
new file mode 100644
index 00000000..d9024e34
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/authentication/local/LocalAuthSettings.java
@@ -0,0 +1,11 @@
+package net.jami.jams.common.authentication.local;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class LocalAuthSettings {
+    private Boolean publicNames;
+    private String  publicNameServer;
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/authmodule/AuthenticationModule.java b/jams-common/src/main/java/net/jami/jams/common/authmodule/AuthenticationModule.java
index 78f0860e..a9e7b6ad 100644
--- a/jams-common/src/main/java/net/jami/jams/common/authmodule/AuthenticationModule.java
+++ b/jams-common/src/main/java/net/jami/jams/common/authmodule/AuthenticationModule.java
@@ -13,4 +13,5 @@ public interface AuthenticationModule {
     AuthenticationResult authenticateUser(X509Certificate[] certificates);
     String validateAndGetUsername(String token);
     HashMap<AuthModuleKey, AuthenticationSource> getAuthSources();
+    boolean testModuleConfiguration(AuthenticationSourceType type, String configuration);
 }
diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/requests/CreateAuthSourceRequest.java b/jams-common/src/main/java/net/jami/jams/common/objects/requests/CreateAuthSourceRequest.java
new file mode 100644
index 00000000..a167c150
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/objects/requests/CreateAuthSourceRequest.java
@@ -0,0 +1,19 @@
+package net.jami.jams.common.objects.requests;
+
+import lombok.Getter;
+import lombok.Setter;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+import net.jami.jams.common.authentication.activedirectory.ActiveDirectorySettings;
+import net.jami.jams.common.authentication.ldap.LDAPSettings;
+import net.jami.jams.common.authentication.local.LocalAuthSettings;
+
+@Getter
+@Setter
+public class CreateAuthSourceRequest {
+
+    private AuthenticationSourceType type;
+    private LDAPSettings ldapSettings;
+    private ActiveDirectorySettings activeDirectorySettings;
+    private LocalAuthSettings localAuthSettings;
+
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/requests/CreateCARequest.java b/jams-common/src/main/java/net/jami/jams/common/objects/requests/CreateCARequest.java
new file mode 100644
index 00000000..82b6b57f
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/objects/requests/CreateCARequest.java
@@ -0,0 +1,16 @@
+package net.jami.jams.common.objects.requests;
+
+import lombok.Getter;
+import lombok.Setter;
+import net.jami.jams.common.objects.roots.X509Fields;
+
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+@Getter
+@Setter
+public class CreateCARequest {
+    private X509Fields fields;
+    private X509Certificate certificate;
+    private PrivateKey privateKey;
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/requests/CredentialsRequest.java b/jams-common/src/main/java/net/jami/jams/common/objects/requests/CredentialsRequest.java
new file mode 100644
index 00000000..c899e2ed
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/objects/requests/CredentialsRequest.java
@@ -0,0 +1,13 @@
+package net.jami.jams.common.objects.requests;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class CredentialsRequest {
+
+    private String username;
+    private String password;
+
+}
diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/roots/X509Entity.java b/jams-common/src/main/java/net/jami/jams/common/objects/roots/X509Entity.java
index d56b96c1..c4de1279 100644
--- a/jams-common/src/main/java/net/jami/jams/common/objects/roots/X509Entity.java
+++ b/jams-common/src/main/java/net/jami/jams/common/objects/roots/X509Entity.java
@@ -15,5 +15,4 @@ public class X509Entity {
     //These can be null because they are only used if this is a request.
     private X509Fields x509Fields;
     private PKCS10CertificationRequest certificationRequest;
-    private Long lifetime;
 }
diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/roots/X509Fields.java b/jams-common/src/main/java/net/jami/jams/common/objects/roots/X509Fields.java
index fc635c69..68cd4596 100644
--- a/jams-common/src/main/java/net/jami/jams/common/objects/roots/X509Fields.java
+++ b/jams-common/src/main/java/net/jami/jams/common/objects/roots/X509Fields.java
@@ -12,6 +12,7 @@ public class X509Fields {
     private String state;
     private String organization;
     private String organizationUnit;
+    private Long   lifetime;
 
     public String getDN(){
         StringBuilder stringBuilder = new StringBuilder();
diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/system/SystemAccount.java b/jams-common/src/main/java/net/jami/jams/common/objects/system/SystemAccount.java
index 4764ec09..eb335177 100644
--- a/jams-common/src/main/java/net/jami/jams/common/objects/system/SystemAccount.java
+++ b/jams-common/src/main/java/net/jami/jams/common/objects/system/SystemAccount.java
@@ -3,10 +3,33 @@ package net.jami.jams.common.objects.system;
 import lombok.Getter;
 import lombok.Setter;
 import net.jami.jams.common.objects.roots.X509Entity;
+import net.jami.jams.common.serialization.database.DatabaseObject;
+import net.jami.jams.common.utils.X509Utils;
+
+import java.sql.PreparedStatement;
 
 @Getter
 @Setter
-public class SystemAccount extends X509Entity {
+public class SystemAccount extends X509Entity implements DatabaseObject {
 
     private SystemAccountType systemAccountType;
+
+
+    @Override
+    public PreparedStatement getInsert(PreparedStatement ps) throws Exception {
+        ps.setString(1, systemAccountType.toString());
+        ps.setString(2, X509Utils.getPEMStringFromCertificate(this.getCertificate()));
+        ps.setString(3,X509Utils.getPEMStringFromPrivateKey(this.getPrivateKey()));
+        return ps;
+    }
+
+    @Override
+    public PreparedStatement getDelete(PreparedStatement ps) throws Exception {
+        return null;
+    }
+
+    @Override
+    public PreparedStatement getUpdate(PreparedStatement ps) throws Exception {
+        return null;
+    }
 }
diff --git a/jams-common/src/main/java/net/jami/jams/common/server/ServerSettings.java b/jams-common/src/main/java/net/jami/jams/common/server/ServerSettings.java
index fbfeb1bf..de761bc4 100644
--- a/jams-common/src/main/java/net/jami/jams/common/server/ServerSettings.java
+++ b/jams-common/src/main/java/net/jami/jams/common/server/ServerSettings.java
@@ -10,5 +10,6 @@ public class ServerSettings {
     private String ldapConfiguration;
     private String caConfiguration;
     private String activeDirectoryConfiguration;
+    private String localDirectoryConfiguration;
 
 }
diff --git a/jams-common/src/main/java/net/jami/jams/common/utils/Validator.java b/jams-common/src/main/java/net/jami/jams/common/utils/Validator.java
new file mode 100644
index 00000000..ae9ce1e4
--- /dev/null
+++ b/jams-common/src/main/java/net/jami/jams/common/utils/Validator.java
@@ -0,0 +1,28 @@
+package net.jami.jams.common.utils;
+
+import net.jami.jams.common.authentication.AuthenticationSource;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+import net.jami.jams.common.objects.requests.CreateCARequest;
+
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+public class Validator {
+
+    public static boolean validateCARequests(CreateCARequest request){
+        if(request.getCertificate() != null && request.getPrivateKey() != null){
+            if(request.getCertificate().getBasicConstraints() != -1){
+                RSAPublicKey rsaPublicKey = (RSAPublicKey) request.getCertificate().getPublicKey();
+                RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) request.getPrivateKey();
+                return rsaPublicKey.getModulus().equals( rsaPrivateKey.getModulus() )
+                        && BigInteger.valueOf( 2 ).modPow( rsaPublicKey.getPublicExponent()
+                                .multiply( rsaPrivateKey.getPrivateExponent() ).subtract( BigInteger.ONE ),
+                        rsaPublicKey.getModulus() ).equals( BigInteger.ONE );
+            }
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/Server.java b/jams-server/src/main/java/net/jami/jams/server/Server.java
index ae941021..24119dbf 100644
--- a/jams-server/src/main/java/net/jami/jams/server/Server.java
+++ b/jams-server/src/main/java/net/jami/jams/server/Server.java
@@ -3,7 +3,7 @@ package net.jami.jams.server;
 import com.jsoniter.JsonIterator;
 import lombok.extern.slf4j.Slf4j;
 import net.jami.datastore.main.DataStore;
-import net.jami.jams.common.authentication.AuthenticationSource;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
 import net.jami.jams.common.authmodule.AuthenticationModule;
 import net.jami.jams.common.cryptoengineapi.CertificateAuthority;
 import net.jami.jams.common.serialization.JsoniterRegistry;
@@ -16,16 +16,11 @@ import net.jami.jams.server.startup.CryptoEngineLoader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 @Slf4j
 public class Server {
 
-    public static List<String> authModuleClasses = new ArrayList<>();
-    public static HashMap<String, AuthenticationSource> authenticationSources = new HashMap<>();
     public static AtomicBoolean isInstalled = new AtomicBoolean(false);
 
     static {
@@ -49,8 +44,6 @@ public class Server {
         //Step 1: Create the data store.
         dataStore = new DataStore("jdbc:derby:jams;create=true");
 
-
-
         isInstalled.set(new File(System.getProperty("user.dir") + File.separator + "config.json").exists());
         log.info("Server is already installed: " + isInstalled.get());
         ServerSettings serverSettings = null;
@@ -60,6 +53,14 @@ public class Server {
                 serverSettings = JsonIterator.deserialize(path.readAllBytes(),ServerSettings.class);
                 certificateAuthority = CryptoEngineLoader.loadCertificateAuthority(serverSettings.getCaConfiguration(),dataStore);
                 userAuthenticationModule = AuthModuleLoader.loadAuthenticationModule(dataStore,certificateAuthority);
+                if(serverSettings.getLdapConfiguration() != null)
+                    userAuthenticationModule.attachAuthSource(AuthenticationSourceType.LDAP,
+                            serverSettings.getLdapConfiguration()
+                    );
+                if(serverSettings.getActiveDirectoryConfiguration() != null){
+                    userAuthenticationModule.attachAuthSource(AuthenticationSourceType.AD,
+                            serverSettings.getActiveDirectoryConfiguration());
+                }
             }
             catch (Exception e){
                 log.error("Could not load configuration file or initialize some components - this is critical");
diff --git a/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java b/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java
new file mode 100644
index 00000000..4d2aac96
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/core/workflows/InstallationFinalizer.java
@@ -0,0 +1,78 @@
+package net.jami.jams.server.core.workflows;
+
+import com.jsoniter.output.JsonStream;
+import lombok.extern.slf4j.Slf4j;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+import net.jami.jams.common.objects.roots.X509Fields;
+import net.jami.jams.common.objects.system.SystemAccount;
+import net.jami.jams.common.objects.system.SystemAccountType;
+import net.jami.jams.common.server.ServerSettings;
+import net.jami.jams.server.Server;
+import net.jami.jams.server.servlets.api.install.CachedObjects;
+import net.jami.jams.server.startup.AuthModuleLoader;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+
+import static net.jami.jams.server.Server.*;
+
+@Slf4j
+public class InstallationFinalizer {
+
+    public boolean finalizeInstallation() {
+        //Basically here we build the config and flush it.
+        try {
+            log.info("Building configuration from submitted variables...");
+            ServerSettings serverSettings = new ServerSettings();
+            serverSettings.setCaConfiguration(JsonStream.serialize(CachedObjects.certificateAuthorityConfig));
+            if (CachedObjects.activeDirectorySettings != null)
+                serverSettings.setActiveDirectoryConfiguration(JsonStream.serialize(CachedObjects.activeDirectorySettings));
+            if (CachedObjects.ldapSettings != null)
+                serverSettings.setLdapConfiguration(JsonStream.serialize(CachedObjects.ldapSettings));
+            if (CachedObjects.localAuthSettings != null)
+                serverSettings.setLocalDirectoryConfiguration(JsonStream.serialize(CachedObjects.localAuthSettings));
+
+            //Now flush the server settings.
+            OutputStream os = new FileOutputStream(new File("config.json"));
+            os.write(JsonStream.serialize(serverSettings).getBytes());
+            os.flush();
+            os.close();
+            log.info("Settings succesfully saved to configuration file...");
+            log.info("Attempting to save the CA and generate the OCSP certificate...");
+            if (CachedObjects.createCARequest.getFields() != null) {
+                SystemAccount caAccount = new SystemAccount();
+                caAccount.setSystemAccountType(SystemAccountType.CA);
+                caAccount.setX509Fields(CachedObjects.createCARequest.getFields());
+                certificateAuthority.getSignedCertificate(caAccount);
+                dataStore.getSystemDao().storeObject(caAccount);
+                log.info("Succesfully stored CA");
+                certificateAuthority.init(serverSettings.getCaConfiguration(), caAccount, null);
+                SystemAccount ocspAccount = new SystemAccount();
+                ocspAccount.setX509Fields(new X509Fields());
+                ocspAccount.getX509Fields().setCommonName("OCSP Server Certificate");
+                ocspAccount.setSystemAccountType(SystemAccountType.OCSP);
+                ocspAccount.getX509Fields().setLifetime(caAccount.getX509Fields().getLifetime());
+                certificateAuthority.getSignedCertificate(ocspAccount);
+                dataStore.getSystemDao().storeObject(ocspAccount);
+                log.info("Successfully created and stored the OCSP certificate");
+                certificateAuthority.init(serverSettings.getCaConfiguration(), caAccount, ocspAccount);
+                log.info("Succesfully inited the certificate authority with the appropriate settings...");
+            }
+            log.info("Initializing the selected authentication providers");
+            userAuthenticationModule = AuthModuleLoader.loadAuthenticationModule(dataStore, certificateAuthority);
+            if(serverSettings.getActiveDirectoryConfiguration() != null)
+                userAuthenticationModule.attachAuthSource(AuthenticationSourceType.AD,serverSettings.getActiveDirectoryConfiguration());
+            if(serverSettings.getLdapConfiguration() != null)
+                userAuthenticationModule.attachAuthSource(AuthenticationSourceType.LDAP,serverSettings.getLdapConfiguration());
+            Server.isInstalled.set(true);
+            log.info("The installation has completed succesfully, you can now use JAMS!");
+        } catch (Exception e) {
+            log.error("Could not save settings to disk with error: " + e.toString());
+            return false;
+        }
+        return true;
+    }
+
+
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CachedObjects.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CachedObjects.java
new file mode 100644
index 00000000..939fef55
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CachedObjects.java
@@ -0,0 +1,17 @@
+package net.jami.jams.server.servlets.api.install;
+
+import net.jami.jams.common.authentication.activedirectory.ActiveDirectorySettings;
+import net.jami.jams.common.authentication.ldap.LDAPSettings;
+import net.jami.jams.common.authentication.local.LocalAuthSettings;
+import net.jami.jams.common.cryptoengineapi.CertificateAuthorityConfig;
+import net.jami.jams.common.objects.requests.CreateCARequest;
+
+public class CachedObjects {
+
+    public static String endpoint = "start";
+    public static CertificateAuthorityConfig certificateAuthorityConfig;
+    public static CreateCARequest createCARequest;
+    public static LDAPSettings ldapSettings;
+    public static ActiveDirectorySettings activeDirectorySettings;
+    public static LocalAuthSettings localAuthSettings;
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateAuthSourceServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateAuthSourceServlet.java
index 6cf14b18..018ab94b 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateAuthSourceServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateAuthSourceServlet.java
@@ -1,13 +1,21 @@
 package net.jami.jams.server.servlets.api.install;
 
+import com.jsoniter.JsonIterator;
+import com.jsoniter.output.JsonStream;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.annotation.WebServlet;
 import jakarta.servlet.http.HttpServlet;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import net.jami.jams.common.authentication.AuthenticationSourceType;
+import net.jami.jams.common.objects.requests.CreateAuthSourceRequest;
+import net.jami.jams.common.objects.requests.CreateCARequest;
+import net.jami.jams.common.utils.Validator;
 
 import java.io.IOException;
 
+import static net.jami.jams.server.Server.userAuthenticationModule;
+
 @WebServlet("/api/install/auth")
 public class CreateAuthSourceServlet extends HttpServlet {
 
@@ -18,6 +26,32 @@ public class CreateAuthSourceServlet extends HttpServlet {
 
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doPost(req, resp);
+        CreateAuthSourceRequest authSourceRequest = JsonIterator.deserialize(
+                req.getInputStream().readAllBytes(),CreateAuthSourceRequest.class);
+        CachedObjects.localAuthSettings = null;
+        CachedObjects.activeDirectorySettings = null;
+        CachedObjects.ldapSettings = null;
+        boolean error = false;
+        switch (authSourceRequest.getType()){
+            case LOCAL:
+                CachedObjects.localAuthSettings = authSourceRequest.getLocalAuthSettings();
+                break;
+            case LDAP:
+                if(userAuthenticationModule.testModuleConfiguration(AuthenticationSourceType.LDAP,
+                        JsonStream.serialize(authSourceRequest.getLdapSettings()))){
+                    CachedObjects.ldapSettings = authSourceRequest.getLdapSettings();
+                }
+                else error = true;
+                break;
+            case AD:
+                if(userAuthenticationModule.testModuleConfiguration(AuthenticationSourceType.AD,
+                        JsonStream.serialize(authSourceRequest.getActiveDirectorySettings()))) {
+                    CachedObjects.activeDirectorySettings = authSourceRequest.getActiveDirectorySettings();
+                }
+                else error = true;
+                break;
+        }
+        if(error) resp.sendError(500,"The supplied configuration is invalid or the connectivity tests has failed");
+        else CachedObjects.endpoint = "/api/install/settings";
     }
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateCAServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateCAServlet.java
index 30a5c6fd..63faac21 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateCAServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateCAServlet.java
@@ -1,10 +1,13 @@
 package net.jami.jams.server.servlets.api.install;
 
+import com.jsoniter.JsonIterator;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.annotation.WebServlet;
 import jakarta.servlet.http.HttpServlet;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import net.jami.jams.common.objects.requests.CreateCARequest;
+import net.jami.jams.common.utils.Validator;
 
 import java.io.IOException;
 
@@ -18,6 +21,13 @@ public class CreateCAServlet extends HttpServlet {
 
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doPost(req, resp);
+        CreateCARequest caRequest = JsonIterator.deserialize(req.getInputStream().readAllBytes(),CreateCARequest.class);
+        if(!Validator.validateCARequests(caRequest)){
+            resp.sendError(500,"Certificate was either not a CA or the private key did not match the certificate");
+        }
+        else{
+            CachedObjects.createCARequest = caRequest;
+            CachedObjects.endpoint = "/api/install/auth";
+        }
     }
 }
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateGeneralSettingsServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateGeneralSettingsServlet.java
deleted file mode 100644
index e6529d42..00000000
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateGeneralSettingsServlet.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package net.jami.jams.server.servlets.api.install;
-
-import jakarta.servlet.ServletException;
-import jakarta.servlet.annotation.WebServlet;
-import jakarta.servlet.http.HttpServlet;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-import java.io.IOException;
-
-@WebServlet("/api/install/settings")
-public class CreateGeneralSettingsServlet extends HttpServlet {
-
-    @Override
-    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doGet(req, resp);
-    }
-
-    @Override
-    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        super.doPost(req, resp);
-    }
-}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateServerSettingsServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateServerSettingsServlet.java
new file mode 100644
index 00000000..4fdc6399
--- /dev/null
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/CreateServerSettingsServlet.java
@@ -0,0 +1,35 @@
+package net.jami.jams.server.servlets.api.install;
+
+import com.jsoniter.JsonIterator;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.annotation.WebServlet;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import net.jami.jams.common.cryptoengineapi.CertificateAuthorityConfig;
+import net.jami.jams.server.core.workflows.InstallationFinalizer;
+
+import java.io.IOException;
+
+@WebServlet("/api/install/settings")
+public class CreateServerSettingsServlet extends HttpServlet {
+
+    InstallationFinalizer finalizer = new InstallationFinalizer();
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        super.doGet(req, resp);
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        CertificateAuthorityConfig config = JsonIterator.deserialize(
+                req.getInputStream().readAllBytes(),CertificateAuthorityConfig.class);
+        CachedObjects.certificateAuthorityConfig = config;
+        if(!finalizer.finalizeInstallation()) {
+            resp.sendError(500, "Could not store settings, a problem occured with finishing the installation");
+            return;
+        }
+        resp.sendRedirect("/");
+    }
+}
diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/StartInstallServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/StartInstallServlet.java
index d6739ecf..c5e451e8 100644
--- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/StartInstallServlet.java
+++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/install/StartInstallServlet.java
@@ -1,5 +1,6 @@
 package net.jami.jams.server.servlets.api.install;
 
+import com.jsoniter.JsonIterator;
 import com.jsoniter.output.JsonStream;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.annotation.WebServlet;
@@ -9,6 +10,7 @@ import jakarta.servlet.http.HttpServletResponse;
 import net.jami.jams.common.authentication.AuthenticationSourceType;
 import net.jami.jams.common.authmodule.AuthenticationResult;
 import net.jami.jams.common.dao.StatementList;
+import net.jami.jams.common.objects.requests.CredentialsRequest;
 import net.jami.jams.common.objects.user.AccessLevel;
 import net.jami.jams.common.objects.user.User;
 
@@ -31,10 +33,12 @@ public class StartInstallServlet extends HttpServlet {
 
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        CredentialsRequest credentialsRequest = JsonIterator.deserialize(req.getInputStream().readAllBytes(),CredentialsRequest.class);
         AuthenticationResult res = null;
-        if(req.getParameter("username") != null && req.getParameter("password") != null){
-            res = processUsernamePasswordAuth(req.getParameter("username"),req.getParameter("password"));
+        if(credentialsRequest.getUsername() != null && credentialsRequest.getPassword() != null){
+            res = processUsernamePasswordAuth(credentialsRequest.getUsername(),credentialsRequest.getPassword());
         }
+        resp.setHeader("endpoint",CachedObjects.endpoint);
         resp.getOutputStream().write(JsonStream.serialize(res).getBytes());
     }
 
@@ -47,15 +51,17 @@ public class StartInstallServlet extends HttpServlet {
             resp.sendError(500,"We have tried to create an administrative account where one already exists!");
             return;
         }
+        CredentialsRequest credentialsRequest = JsonIterator.deserialize(req.getInputStream().readAllBytes(),CredentialsRequest.class);
         //The admin user has no X509 properties.
         User user = new User();
-        user.setUsername(req.getParameter("username"));
-        user.setPassword(req.getParameter("password"));
+        user.setUsername(credentialsRequest.getUsername());
+        user.setPassword(credentialsRequest.getPassword());
         user.setUserType(AuthenticationSourceType.LOCAL);
         user.setRealm("LOCAL");
         user.setAccessLevel(AccessLevel.ADMIN);
         dataStore.getUserDao().storeObject(user);
         AuthenticationResult res = processUsernamePasswordAuth(user.getUsername(),user.getPassword());
         resp.getOutputStream().write(JsonStream.serialize(res).getBytes());
+        CachedObjects.endpoint = "/api/install/ca";
     }
 }
diff --git a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/LDAPConnector.java b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/LDAPConnector.java
index ac6cd0cf..6865ba19 100644
--- a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/LDAPConnector.java
+++ b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/LDAPConnector.java
@@ -60,10 +60,11 @@ public class LDAPConnector implements AuthenticationSource {
     }
 
     @Override
-    public boolean testConfiguration(String configuration) {
-        return false;
+    public boolean test() {
+        return (getUserProfile("*","LOGON_NAME").length != 0);
     }
 
+
     @Override
     public boolean updatePassword(User user, String password) {
         return false;
diff --git a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java
index b760025b..fd881025 100644
--- a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java
+++ b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java
@@ -32,8 +32,10 @@ public class UserProfileService {
                 SearchResponse res = search.execute(buildRequest(queryString,field));
                 if (res.getEntries().size() > 0) profiles = new UserProfile[res.getEntries().size()];
                 Iterator<LdapEntry> iterator = res.getEntries().iterator();
-                for(int i=0; i< profiles.length; i++){
+                int i = 0;
+                while(iterator.hasNext()){
                     profiles[i] = profileFromResponse(iterator.next());
+                    i++;
                 }
                 return profiles;
             } catch (Exception e) {
-- 
GitLab