#!/bin/bash # Configuration automatique du client mobile Keycloak pour UnionFlow # Ce script configure le client unionflow-mobile dans Keycloak set -e # Configuration KEYCLOAK_URL="http://localhost:8180" REALM="unionflow" ADMIN_USER="admin" ADMIN_PASSWORD="admin" CLIENT_ID="unionflow-mobile" echo "🔧 Configuration automatique du client mobile Keycloak..." echo "📍 Keycloak URL: $KEYCLOAK_URL" echo "🏛️ Realm: $REALM" echo "📱 Client ID: $CLIENT_ID" echo "" # Fonction pour obtenir le token d'administration get_admin_token() { echo "🔑 Obtention du token d'administration..." ADMIN_TOKEN=$(curl -s -X POST "$KEYCLOAK_URL/realms/master/protocol/openid-connect/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=$ADMIN_USER" \ -d "password=$ADMIN_PASSWORD" \ -d "grant_type=password" \ -d "client_id=admin-cli" | jq -r '.access_token') if [ "$ADMIN_TOKEN" = "null" ] || [ -z "$ADMIN_TOKEN" ]; then echo "❌ Erreur: Impossible d'obtenir le token d'administration" echo "Vérifiez les credentials Keycloak (admin/admin)" exit 1 fi echo "✅ Token d'administration obtenu" } # Fonction pour vérifier si le client existe déjà check_client_exists() { echo "🔍 Vérification de l'existence du client $CLIENT_ID..." CLIENT_EXISTS=$(curl -s -X GET "$KEYCLOAK_URL/admin/realms/$REALM/clients" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" | jq -r ".[] | select(.clientId==\"$CLIENT_ID\") | .id") if [ -n "$CLIENT_EXISTS" ] && [ "$CLIENT_EXISTS" != "null" ]; then echo "⚠️ Client $CLIENT_ID existe déjà (ID: $CLIENT_EXISTS)" return 0 else echo "ℹ️ Client $CLIENT_ID n'existe pas, création nécessaire" return 1 fi } # Fonction pour créer le client mobile create_mobile_client() { echo "📱 Création du client mobile $CLIENT_ID..." CLIENT_CONFIG='{ "clientId": "'$CLIENT_ID'", "name": "UnionFlow Mobile App", "description": "Application mobile UnionFlow avec authentification OIDC", "enabled": true, "clientAuthenticatorType": "client-secret", "publicClient": true, "standardFlowEnabled": true, "implicitFlowEnabled": false, "directAccessGrantsEnabled": false, "serviceAccountsEnabled": false, "authorizationServicesEnabled": false, "rootUrl": "com.unionflow.mobile://", "baseUrl": "com.unionflow.mobile://home", "redirectUris": [ "com.unionflow.mobile://login-callback", "com.unionflow.mobile://login-callback/*" ], "postLogoutRedirectUris": [ "com.unionflow.mobile://logout-callback", "com.unionflow.mobile://logout-callback/*" ], "webOrigins": ["+"], "attributes": { "pkce.code.challenge.method": "S256", "access.token.lifespan": "900", "client.session.idle.timeout": "1800", "client.session.max.lifespan": "43200" }, "defaultClientScopes": ["openid", "profile", "email", "roles"], "optionalClientScopes": [] }' RESPONSE=$(curl -s -w "%{http_code}" -X POST "$KEYCLOAK_URL/admin/realms/$REALM/clients" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d "$CLIENT_CONFIG") HTTP_CODE="${RESPONSE: -3}" if [ "$HTTP_CODE" = "201" ]; then echo "✅ Client mobile créé avec succès" # Récupérer l'ID du client créé CLIENT_UUID=$(curl -s -X GET "$KEYCLOAK_URL/admin/realms/$REALM/clients" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" | jq -r ".[] | select(.clientId==\"$CLIENT_ID\") | .id") echo "📋 Client UUID: $CLIENT_UUID" return 0 else echo "❌ Erreur lors de la création du client (HTTP: $HTTP_CODE)" echo "Response: ${RESPONSE%???}" return 1 fi } # Fonction pour configurer les mappers de rôles configure_role_mappers() { echo "🎭 Configuration des mappers de rôles..." # Mapper pour l'audience AUDIENCE_MAPPER='{ "name": "audience-mapper", "protocol": "openid-connect", "protocolMapper": "oidc-audience-mapper", "config": { "included.client.audience": "unionflow-server", "access.token.claim": "true" } }' # Mapper pour les rôles client ROLES_MAPPER='{ "name": "client-roles-mapper", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-client-role-mapper", "config": { "client.id": "unionflow-server", "claim.name": "resource_access.unionflow-server.roles", "access.token.claim": "true", "id.token.claim": "false", "userinfo.token.claim": "false", "multivalued": "true" } }' # Ajouter le mapper d'audience curl -s -X POST "$KEYCLOAK_URL/admin/realms/$REALM/clients/$CLIENT_UUID/protocol-mappers/models" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d "$AUDIENCE_MAPPER" > /dev/null # Ajouter le mapper de rôles curl -s -X POST "$KEYCLOAK_URL/admin/realms/$REALM/clients/$CLIENT_UUID/protocol-mappers/models" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d "$ROLES_MAPPER" > /dev/null echo "✅ Mappers de rôles configurés" } # Fonction pour tester la configuration test_configuration() { echo "🧪 Test de la configuration..." # Test de l'endpoint d'autorisation AUTH_URL="$KEYCLOAK_URL/realms/$REALM/protocol/openid-connect/auth" echo "📍 URL d'autorisation: $AUTH_URL" # Test de l'endpoint de token TOKEN_URL="$KEYCLOAK_URL/realms/$REALM/protocol/openid-connect/token" echo "📍 URL de token: $TOKEN_URL" # Vérifier que les endpoints répondent AUTH_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$AUTH_URL?client_id=$CLIENT_ID&response_type=code&redirect_uri=com.unionflow.mobile://login-callback") if [ "$AUTH_STATUS" = "200" ] || [ "$AUTH_STATUS" = "302" ]; then echo "✅ Endpoint d'autorisation accessible" else echo "⚠️ Endpoint d'autorisation: HTTP $AUTH_STATUS" fi echo "✅ Configuration testée" } # Fonction principale main() { echo "🚀 Début de la configuration automatique..." echo "" # Vérifier que jq est installé if ! command -v jq &> /dev/null; then echo "❌ Erreur: jq n'est pas installé" echo "Installez jq avec: sudo apt-get install jq (Ubuntu) ou brew install jq (macOS)" exit 1 fi # Obtenir le token d'administration get_admin_token # Vérifier si le client existe déjà if check_client_exists; then echo "ℹ️ Client existant trouvé, récupération de l'UUID..." CLIENT_UUID="$CLIENT_EXISTS" else # Créer le client mobile if create_mobile_client; then CLIENT_UUID=$(curl -s -X GET "$KEYCLOAK_URL/admin/realms/$REALM/clients" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" | jq -r ".[] | select(.clientId==\"$CLIENT_ID\") | .id") else echo "❌ Échec de la création du client" exit 1 fi fi # Configurer les mappers de rôles configure_role_mappers # Tester la configuration test_configuration echo "" echo "🎉 Configuration terminée avec succès !" echo "" echo "📋 Résumé de la configuration:" echo " • Client ID: $CLIENT_ID" echo " • Client UUID: $CLIENT_UUID" echo " • Type: Public (PKCE activé)" echo " • Redirect URI: com.unionflow.mobile://login-callback" echo " • Logout URI: com.unionflow.mobile://logout-callback" echo "" echo "🔗 URLs importantes:" echo " • Authorization: $KEYCLOAK_URL/realms/$REALM/protocol/openid-connect/auth" echo " • Token: $KEYCLOAK_URL/realms/$REALM/protocol/openid-connect/token" echo " • Logout: $KEYCLOAK_URL/realms/$REALM/protocol/openid-connect/logout" echo "" echo "✅ L'application mobile peut maintenant s'authentifier avec Keycloak !" } # Exécuter le script principal main "$@"