- Replace flutter_appauth with custom WebView implementation to resolve deep link issues - Add KeycloakWebViewAuthService with integrated WebView for seamless authentication - Configure Android manifest for HTTP cleartext traffic support - Add network security config for development environment (192.168.1.11) - Update Keycloak client to use HTTP callback endpoint (http://192.168.1.11:8080/auth/callback) - Remove obsolete keycloak_auth_service.dart and temporary scripts - Clean up dependencies and regenerate injection configuration - Tested successfully on multiple Android devices (Xiaomi 2201116TG, SM A725F) BREAKING CHANGE: Authentication flow now uses WebView instead of external browser - Users will see Keycloak login page within the app instead of browser redirect - Resolves ERR_CLEARTEXT_NOT_PERMITTED and deep link state management issues - Maintains full OIDC compliance with PKCE flow and secure token storage Technical improvements: - WebView with custom navigation delegate for callback handling - Automatic token extraction and user info parsing from JWT - Proper error handling and user feedback - Consistent authentication state management across app lifecycle
299 lines
9.9 KiB
Bash
299 lines
9.9 KiB
Bash
#!/bin/bash
|
|
|
|
# Configuration complète de Keycloak pour UnionFlow
|
|
echo "🔐 Configuration complète de Keycloak pour UnionFlow"
|
|
echo "===================================================="
|
|
|
|
# Variables
|
|
KEYCLOAK_URL="http://localhost:8180"
|
|
REALM_NAME="unionflow"
|
|
CLIENT_ID="unionflow-server"
|
|
CLIENT_SECRET="unionflow-secret-2025"
|
|
|
|
# Couleurs
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m'
|
|
|
|
# Fonction pour obtenir un token admin
|
|
get_admin_token() {
|
|
echo -e "${YELLOW}📡 Obtention du token admin...${NC}"
|
|
|
|
TOKEN_RESPONSE=$(curl -s -X POST "$KEYCLOAK_URL/realms/master/protocol/openid-connect/token" \
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
-d "username=admin&password=admin&grant_type=password&client_id=admin-cli")
|
|
|
|
ACCESS_TOKEN=$(echo $TOKEN_RESPONSE | grep -o '"access_token":"[^"]*' | cut -d'"' -f4)
|
|
|
|
if [ -n "$ACCESS_TOKEN" ]; then
|
|
echo -e "${GREEN}✅ Token admin obtenu${NC}"
|
|
return 0
|
|
else
|
|
echo -e "${RED}❌ Impossible d'obtenir le token admin${NC}"
|
|
echo "Réponse: $TOKEN_RESPONSE"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Fonction pour supprimer et recréer le realm
|
|
recreate_realm() {
|
|
echo -e "${YELLOW}🏛️ Suppression et recréation du realm '$REALM_NAME'...${NC}"
|
|
|
|
# Supprimer le realm s'il existe
|
|
curl -s -X DELETE "$KEYCLOAK_URL/admin/realms/$REALM_NAME" \
|
|
-H "Authorization: Bearer $ACCESS_TOKEN" > /dev/null
|
|
|
|
sleep 2
|
|
|
|
# Créer le nouveau realm
|
|
REALM_CONFIG='{
|
|
"realm": "'$REALM_NAME'",
|
|
"displayName": "UnionFlow",
|
|
"enabled": true,
|
|
"registrationAllowed": false,
|
|
"registrationEmailAsUsername": true,
|
|
"rememberMe": true,
|
|
"verifyEmail": false,
|
|
"loginWithEmailAllowed": true,
|
|
"duplicateEmailsAllowed": false,
|
|
"resetPasswordAllowed": true,
|
|
"editUsernameAllowed": false,
|
|
"sslRequired": "external",
|
|
"defaultLocale": "fr"
|
|
}'
|
|
|
|
RESPONSE=$(curl -s -X POST "$KEYCLOAK_URL/admin/realms" \
|
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$REALM_CONFIG" \
|
|
-w "%{http_code}")
|
|
|
|
if [[ "$RESPONSE" == *"201"* ]]; then
|
|
echo -e "${GREEN}✅ Realm '$REALM_NAME' créé${NC}"
|
|
sleep 2
|
|
return 0
|
|
else
|
|
echo -e "${RED}❌ Erreur lors de la création du realm${NC}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Fonction pour créer le client
|
|
create_client() {
|
|
echo -e "${YELLOW}🔧 Création du client '$CLIENT_ID'...${NC}"
|
|
|
|
CLIENT_CONFIG='{
|
|
"clientId": "'$CLIENT_ID'",
|
|
"name": "UnionFlow Server API",
|
|
"enabled": true,
|
|
"clientAuthenticatorType": "client-secret",
|
|
"secret": "'$CLIENT_SECRET'",
|
|
"protocol": "openid-connect",
|
|
"publicClient": false,
|
|
"serviceAccountsEnabled": true,
|
|
"standardFlowEnabled": true,
|
|
"implicitFlowEnabled": false,
|
|
"directAccessGrantsEnabled": true,
|
|
"authorizationServicesEnabled": false,
|
|
"redirectUris": ["http://localhost:8080/*"],
|
|
"webOrigins": ["http://localhost:8080", "*"],
|
|
"fullScopeAllowed": true
|
|
}'
|
|
|
|
RESPONSE=$(curl -s -X POST "$KEYCLOAK_URL/admin/realms/$REALM_NAME/clients" \
|
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$CLIENT_CONFIG" \
|
|
-w "%{http_code}")
|
|
|
|
if [[ "$RESPONSE" == *"201"* ]]; then
|
|
echo -e "${GREEN}✅ Client '$CLIENT_ID' créé${NC}"
|
|
return 0
|
|
else
|
|
echo -e "${RED}❌ Erreur lors de la création du client${NC}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Fonction pour créer les rôles
|
|
create_roles() {
|
|
echo -e "${YELLOW}👥 Création des rôles...${NC}"
|
|
|
|
ROLES=("ADMIN" "PRESIDENT" "SECRETAIRE" "TRESORIER" "GESTIONNAIRE_MEMBRE" "ORGANISATEUR_EVENEMENT" "MEMBRE")
|
|
|
|
for ROLE_NAME in "${ROLES[@]}"; do
|
|
ROLE_CONFIG='{
|
|
"name": "'$ROLE_NAME'",
|
|
"description": "Rôle '$ROLE_NAME' pour UnionFlow"
|
|
}'
|
|
|
|
curl -s -X POST "$KEYCLOAK_URL/admin/realms/$REALM_NAME/roles" \
|
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$ROLE_CONFIG" > /dev/null
|
|
|
|
echo -e " ${GREEN}✅ Rôle '$ROLE_NAME' créé${NC}"
|
|
done
|
|
}
|
|
|
|
# Fonction pour créer un utilisateur de test
|
|
create_test_user() {
|
|
echo -e "${YELLOW}👤 Création de l'utilisateur de test...${NC}"
|
|
|
|
USER_CONFIG='{
|
|
"username": "testuser",
|
|
"email": "test@unionflow.dev",
|
|
"firstName": "Test",
|
|
"lastName": "User",
|
|
"enabled": true,
|
|
"emailVerified": true
|
|
}'
|
|
|
|
RESPONSE=$(curl -s -X POST "$KEYCLOAK_URL/admin/realms/$REALM_NAME/users" \
|
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$USER_CONFIG" \
|
|
-w "%{http_code}")
|
|
|
|
if [[ "$RESPONSE" == *"201"* ]]; then
|
|
echo -e "${GREEN}✅ Utilisateur créé${NC}"
|
|
|
|
# Récupérer l'ID de l'utilisateur
|
|
USER_ID=$(curl -s -X GET "$KEYCLOAK_URL/admin/realms/$REALM_NAME/users?username=testuser" \
|
|
-H "Authorization: Bearer $ACCESS_TOKEN" | \
|
|
grep -o '"id":"[^"]*' | head -1 | cut -d'"' -f4)
|
|
|
|
if [ -n "$USER_ID" ]; then
|
|
# Définir le mot de passe
|
|
PASSWORD_CONFIG='{
|
|
"type": "password",
|
|
"value": "test123",
|
|
"temporary": false
|
|
}'
|
|
|
|
curl -s -X PUT "$KEYCLOAK_URL/admin/realms/$REALM_NAME/users/$USER_ID/reset-password" \
|
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$PASSWORD_CONFIG"
|
|
|
|
echo -e "${GREEN}✅ Mot de passe défini${NC}"
|
|
|
|
# Assigner le rôle MEMBRE
|
|
ROLE_DATA=$(curl -s -X GET "$KEYCLOAK_URL/admin/realms/$REALM_NAME/roles/MEMBRE" \
|
|
-H "Authorization: Bearer $ACCESS_TOKEN")
|
|
|
|
if [[ "$ROLE_DATA" == *'"name"'* ]]; then
|
|
ROLE_ASSIGNMENT="[$ROLE_DATA]"
|
|
|
|
curl -s -X POST "$KEYCLOAK_URL/admin/realms/$REALM_NAME/users/$USER_ID/role-mappings/realm" \
|
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$ROLE_ASSIGNMENT"
|
|
|
|
echo -e "${GREEN}✅ Rôle MEMBRE assigné${NC}"
|
|
fi
|
|
fi
|
|
return 0
|
|
else
|
|
echo -e "${RED}❌ Erreur lors de la création de l'utilisateur${NC}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Fonction pour tester l'authentification
|
|
test_authentication() {
|
|
echo -e "${YELLOW}🧪 Test d'authentification...${NC}"
|
|
|
|
AUTH_RESPONSE=$(curl -s -X POST "$KEYCLOAK_URL/realms/$REALM_NAME/protocol/openid-connect/token" \
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
-d "username=testuser&password=test123&grant_type=password&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET")
|
|
|
|
AUTH_TOKEN=$(echo $AUTH_RESPONSE | grep -o '"access_token":"[^"]*' | cut -d'"' -f4)
|
|
|
|
if [ -n "$AUTH_TOKEN" ]; then
|
|
echo -e "${GREEN}✅ Authentification réussie !${NC}"
|
|
echo -e "${CYAN}🔑 Token obtenu (tronqué): ${AUTH_TOKEN:0:50}...${NC}"
|
|
|
|
# Test d'accès à l'API
|
|
echo -e "${YELLOW}🧪 Test d'accès à l'API UnionFlow...${NC}"
|
|
API_RESPONSE=$(curl -s -w "%{http_code}" -H "Authorization: Bearer $AUTH_TOKEN" "http://localhost:8080/api/organisations")
|
|
HTTP_CODE=$(echo "$API_RESPONSE" | tail -c 4)
|
|
|
|
if [ "$HTTP_CODE" = "200" ]; then
|
|
echo -e "${GREEN}✅ Accès API réussi !${NC}"
|
|
elif [ "$HTTP_CODE" = "403" ]; then
|
|
echo -e "${YELLOW}⚠️ Accès refusé - Permissions insuffisantes (normal pour un utilisateur MEMBRE)${NC}"
|
|
else
|
|
echo -e "${YELLOW}⚠️ Code de réponse: $HTTP_CODE${NC}"
|
|
fi
|
|
|
|
return 0
|
|
else
|
|
echo -e "${RED}❌ Échec de l'authentification${NC}"
|
|
echo "Réponse: $AUTH_RESPONSE"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Script principal
|
|
main() {
|
|
echo -e "${CYAN}🚀 Démarrage de la configuration complète...${NC}"
|
|
echo ""
|
|
|
|
# Obtenir le token admin
|
|
if ! get_admin_token; then
|
|
exit 1
|
|
fi
|
|
|
|
# Recréer le realm
|
|
if ! recreate_realm; then
|
|
exit 1
|
|
fi
|
|
|
|
# Créer le client
|
|
if ! create_client; then
|
|
exit 1
|
|
fi
|
|
|
|
# Créer les rôles
|
|
create_roles
|
|
|
|
# Créer l'utilisateur de test
|
|
if ! create_test_user; then
|
|
exit 1
|
|
fi
|
|
|
|
# Tester l'authentification
|
|
if test_authentication; then
|
|
echo ""
|
|
echo -e "${GREEN}🎉 CONFIGURATION KEYCLOAK TERMINÉE AVEC SUCCÈS !${NC}"
|
|
echo -e "${GREEN}===============================================${NC}"
|
|
echo -e "${CYAN}📋 Informations de configuration :${NC}"
|
|
echo -e " • Realm: $REALM_NAME"
|
|
echo -e " • Client ID: $CLIENT_ID"
|
|
echo -e " • Client Secret: $CLIENT_SECRET"
|
|
echo -e " • URL Auth Server: $KEYCLOAK_URL/realms/$REALM_NAME"
|
|
echo ""
|
|
echo -e "${CYAN}👤 Utilisateur de test :${NC}"
|
|
echo -e " • Username: testuser"
|
|
echo -e " • Password: test123"
|
|
echo -e " • Rôle: MEMBRE"
|
|
echo ""
|
|
echo -e "${CYAN}🔗 URLs importantes :${NC}"
|
|
echo -e " • UnionFlow API: http://localhost:8080"
|
|
echo -e " • Swagger UI: http://localhost:8080/q/swagger-ui"
|
|
echo -e " • Health Check: http://localhost:8080/health"
|
|
echo -e " • Keycloak Admin: http://localhost:8180/admin"
|
|
echo ""
|
|
echo -e "${GREEN}✅ L'intégration Keycloak avec UnionFlow est maintenant fonctionnelle !${NC}"
|
|
else
|
|
echo -e "${RED}❌ Échec de la configuration${NC}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Exécuter le script principal
|
|
main
|