Prechádzať zdrojové kódy

fix: Correctly setup keycloak realm

This commit fixes all issues related to setting up a keycloak realm, and retrieving test tokens, including:
    - Correctly configures client mappers with the correct URL's and handling of existing Clients.
    - Correctly retrieves Test Tokens with the client_secret.
    - Adds multiple Log messages to understand the state of the script.
    - Enhances the Script to be fully reproducible, by adding checks for existings resources and creating them if they do not exists.
    - Handles HTTP 404 and HTTP 405 errors when creating Mappers.

These changes makes the script more robust and reliable.
mrx8086 11 mesiacov pred
rodič
commit
f0e1ae63b1
1 zmenil súbory, kde vykonal 30 pridanie a 52 odobranie
  1. 30 52
      scripts/setup/keycloak/setup_realm.js

+ 30 - 52
scripts/setup/keycloak/setup_realm.js

@@ -24,14 +24,23 @@ const CLIENTS = {
 };
 
 // Hilfsfunktion für API-Fehlerbehandlung
-const handleAxiosError = (error, operation) => {
+const handleAxiosError = (error, operation, config, response) => {
+     console.error(`Error during ${operation}:`);
+    if (config) {
+      console.error('Request:', {
+          method: config.method,
+          url: config.url,
+          headers: config.headers,
+          data: config.data,
+      });
+    }
     if (error.response) {
-        console.error(`Error during ${operation}:`, {
+        console.error('Response:', {
             status: error.response.status,
             data: error.response.data
         });
     } else {
-        console.error(`Error during ${operation}:`, error.message);
+        console.error('Error Message:', error.message);
     }
     throw error;
 };
@@ -55,7 +64,7 @@ async function getAdminToken() {
         );
         return response.data.access_token;
     } catch (error) {
-        handleAxiosError(error, 'getting admin token');
+         handleAxiosError(error, 'getting admin token');
     }
 }
 
@@ -101,7 +110,7 @@ async function getClient(token, clientId) {
 
         return response.data[0];
     } catch (error) {
-        handleAxiosError(error, `getting client ${clientId}`);
+       handleAxiosError(error, `getting client ${clientId}`);
     }
 }
 
@@ -111,16 +120,14 @@ async function checkClientExists(token, clientId) {
     return !!client;
 }
 
-// Funktion um Client Mapper abzufragen
 async function getClientMappers(token, clientId) {
     try {
         const client = await getClient(token, clientId);
         if (!client) {
             return [];
         }
-
         const response = await axios.get(
-            `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/mappers`,
+            `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models`,
             {
                 headers: {
                     'Authorization': `Bearer ${token}`
@@ -129,11 +136,11 @@ async function getClientMappers(token, clientId) {
         );
         return response.data;
     } catch (error) {
-        // handleAxiosError(error, `getting client mappers for ${clientId}`);
-        // wir ignorieren den Fehler hier, da wir diese nun immer setzen
+      handleAxiosError(error, `getting client mappers for ${clientId}`, error.config, error.response);
         return [];
     }
 }
+
 // Realm erstellen
 async function createRealm(token) {
     const realmConfig = {
@@ -248,17 +255,9 @@ async function createClient(token, clientId, clientName, redirectUris) {
         console.log(`Client ${clientId} already exists, checking mappers`);
     }
 
-    if (client) {
-        // Hole existierende Mapper
-        const existingMappers = await axios.get(
-            `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models`,
-            {
-                headers: {
-                    'Authorization': `Bearer ${token}`
-                }
-            }
-        ).then(response => response.data)
-        .catch(() => []);
+     if (client) {
+        
+        const existingMappers = await getClientMappers(token, clientId)
 
         const requiredMappers = [
             {
@@ -320,7 +319,7 @@ async function createClient(token, clientId, clientName, redirectUris) {
                     console.log(`Mapper ${mapper.name} created for client ${clientId}`);
                 }
             } catch (error) {
-                console.error(`Error managing mapper ${mapper.name} for client ${clientId}:`, error.message);
+                handleAxiosError(error, `managing mapper ${mapper.name} for client ${clientId}`, error.config, error.response);
                 // Wir werfen den Fehler nicht weiter, damit andere Mapper noch verarbeitet werden können
             }
         }
@@ -391,13 +390,15 @@ async function createDefaultGroups(token) {
 
 async function createTestToken(token, username) {
     try {
-        const client = await getClient(token, NEXTCLOUD_CLIENT_ID);
+        const nextcloudClientId = Object.keys(CLIENTS).find(key => key.includes('nextcloud')) || 'nextcloud';
+         const client = await getClient(token, nextcloudClientId);
+
         if (!client)
             return null;
         const response = await axios.post(
             `${KEYCLOAK_URL}/realms/${REALM_NAME}/protocol/openid-connect/token`,
             new URLSearchParams({
-                'client_id': NEXTCLOUD_CLIENT_ID,
+                'client_id': nextcloudClientId,
                 'client_secret': process.env.KEYCLOAK_NEXTCLOUD_CLIENT_SECRET,
                 'username': username,
                 'password': process.env.TESTADMIN_PASSWORD || "initial123!",
@@ -411,7 +412,7 @@ async function createTestToken(token, username) {
         );
         return response.data.access_token;
     } catch (error) {
-        handleAxiosError(error, `getting test token for ${username}`);
+        handleAxiosError(error, `getting test token for ${username}`, error.config, error.response);
     }
 }
 
@@ -499,7 +500,7 @@ async function createInitialUsers(token) {
             console.log(`User ${user.username} created successfully`);
 
         } catch (error) {
-            handleAxiosError(error, `creating user: ${user.username}`);
+            handleAxiosError(error, `creating user: ${user.username}`, error.config, error.response);
         }
     }
 }
@@ -522,13 +523,8 @@ async function setupRealm() {
         }
 
         // Clients erstellen
-        const clients = [
-            { id: NEXTCLOUD_CLIENT_ID, name: "nextcloud", redirectUris: ["https://cloud.mrx8086.com/*"] },
-            { id: PAPERLESS_CLIENT_ID, name: "paperless", redirectUris: ["https://docs.mrx8086.com/*"] },
-            { id: NODERED_CLIENT_ID, name: "nodered", redirectUris: ["https://automate.mrx8086.com/*"] }
-        ];
-        for (const client of clients) {
-            await createClient(token, client.id, client.name, client.redirectUris);
+         for (const clientId in CLIENTS) {
+            await createClient(token, clientId, clientId, CLIENTS[clientId].redirectUris);
         }
 
         // Gruppen erstellen
@@ -537,24 +533,6 @@ async function setupRealm() {
         // Test User erstellen
         await createInitialUsers(token);
 
-        // Client Mapper überprüfen
-        const clientMappers = await getClientMappers(token, NEXTCLOUD_CLIENT_ID);
-        if (clientMappers) {
-            console.log("Client Mappers:", clientMappers);
-            const groupMapper = clientMappers.find(mapper => mapper.name === 'groups');
-            if (!groupMapper) {
-                console.error("Error: 'groups' mapper not found for Nextcloud client");
-            } else {
-                console.log("'groups' mapper found")
-                if (groupMapper.config && groupMapper.config.fullGroupPath != "true") {
-                    console.warn("Warning: 'Full group path' in mapper 'groups' is not enabled.");
-                } else {
-                    console.log("'Full group path' in mapper 'groups' is enabled");
-                }
-            }
-        } else {
-            console.error("Error getting Client Mappers");
-        }
 
         // Konfiguration des Office-Automation Realms mit Admin Token auslesen
         if (token) {
@@ -568,7 +546,7 @@ async function setupRealm() {
                 });
                 console.log("Office Automation Realm Configuration:", realmConfig.data)
             } catch (error) {
-                handleAxiosError(error, 'getting office realm configuration');
+                handleAxiosError(error, 'getting office realm configuration', error.config, error.response);
             }
         } else {
             console.error("Error getting Master Realm admin token")