import dotenv from 'dotenv'; import axios from 'axios'; // Lade Umgebungsvariablen dotenv.config(); // Konfigurationskonstanten const KEYCLOAK_URL = process.env.KEYCLOAK_URL || 'https://auth.mrx8086.com'; const ADMIN_USERNAME = process.env.KEYCLOAK_ADMIN_USER; const ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD; const REALM_NAME = 'office-automation'; // Client IDs aus Umgebungsvariablen const NEXTCLOUD_CLIENT_ID = process.env.NEXTCLOUD_CLIENT_ID || 'nextcloud'; const PAPERLESS_CLIENT_ID = process.env.PAPERLESS_CLIENT_ID || 'paperless'; const NODERED_CLIENT_ID = process.env.NODERED_CLIENT_ID || 'nodered'; // Hilfsfunktion für API-Fehlerbehandlung 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('Response:', { status: error.response.status, data: error.response.data }); } else { console.error('Error Message:', error.message); } throw error; }; // Admin Token abrufen async function getAdminToken() { try { const response = await axios.post( `${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token`, new URLSearchParams({ 'client_id': 'admin-cli', 'username': ADMIN_USERNAME, 'password': ADMIN_PASSWORD, 'grant_type': 'password' }), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); return response.data.access_token; } catch (error) { handleAxiosError(error, 'getting admin token'); } } // Funktion um Client Infos abzufragen async function getClient(token, clientId) { try { const response = await axios.get( `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients`, { headers: { 'Authorization': `Bearer ${token}` }, params: { clientId: clientId } } ); if (response.data.length === 0) { console.error(`Client ${clientId} not found`); return null; } return response.data[0]; } catch (error) { handleAxiosError(error, `getting client ${clientId}`); } } // 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}/protocol-mappers/models`, { headers: { 'Authorization': `Bearer ${token}` } } ); return response.data; } catch (error) { handleAxiosError(error, `getting client mappers for ${clientId}`, error.config, error.response); return []; } } async function ensureClientMappers(token, clientId) { const client = await getClient(token, clientId); if (!client) { return console.error(`Client ${clientId} not found, can't create mappers.`); } let existingMappers = await getClientMappers(token, clientId) const requiredMappers = [ { name: "groups", protocol: "openid-connect", protocolMapper: "oidc-group-membership-mapper", config: { "full.path": "true", "id.token.claim": "true", "access.token.claim": "true", "userinfo.token.claim": "true", "claim.name": "groups" } }, { name: "realm roles", protocol: "openid-connect", protocolMapper: "oidc-usermodel-realm-role-mapper", config: { "id.token.claim": "true", "access.token.claim": "true", "userinfo.token.claim": "true", "claim.name": "roles", "jsonType.label": "String", "multivalued": "true" } } ]; for (const mapper of requiredMappers) { const existingMapper = existingMappers.find(m => m.name === mapper.name); try { if (existingMapper) { // Update existierenden Mapper await axios.put( `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models/${existingMapper.id}`, { ...existingMapper, ...mapper }, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } } ); console.log(`Mapper ${mapper.name} updated for client ${clientId}`); } else { // Erstelle neuen Mapper await axios.post( `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models`, mapper, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } } ); console.log(`Mapper ${mapper.name} created for client ${clientId}`); } } catch (error) { 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 } } // Get Mappers and log existingMappers = await getClientMappers(token, clientId); console.log(`Current Mappers for Client ${clientId}:`, existingMappers.map(mapper => ({name: mapper.name, id: mapper.id}))); } // Hauptfunktion async function main() { try { console.log('Starting Client Mapper Check...'); const token = await getAdminToken(); // Clients erstellen const clients = [ NEXTCLOUD_CLIENT_ID, PAPERLESS_CLIENT_ID, NODERED_CLIENT_ID ]; for (const client of clients) { await ensureClientMappers(token, client); } console.log('Client Mapper Check completed successfully'); } catch (error) { console.error('Client Mapper Check failed:', error); process.exit(1); } } // Script ausführen main();