280 lines
11 KiB
Python
280 lines
11 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Script pour corriger la configuration du client unionflow-mobile
|
|
Spécifiquement les redirect_uri pour l'application mobile
|
|
"""
|
|
|
|
import requests
|
|
import json
|
|
|
|
class ClientRedirectFixer:
|
|
def __init__(self, base_url: str = "http://localhost:8180"):
|
|
self.base_url = base_url
|
|
self.session = requests.Session()
|
|
self.admin_token = None
|
|
|
|
def get_admin_token(self) -> bool:
|
|
"""Obtient le token admin"""
|
|
try:
|
|
data = {
|
|
"username": "admin",
|
|
"password": "admin",
|
|
"grant_type": "password",
|
|
"client_id": "admin-cli"
|
|
}
|
|
|
|
response = self.session.post(
|
|
f"{self.base_url}/realms/master/protocol/openid-connect/token",
|
|
data=data,
|
|
headers={"Content-Type": "application/x-www-form-urlencoded"}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
token_data = response.json()
|
|
self.admin_token = token_data.get("access_token")
|
|
return self.admin_token is not None
|
|
|
|
except Exception as e:
|
|
print(f"Erreur obtention token: {e}")
|
|
|
|
return False
|
|
|
|
def get_client_internal_id(self, realm_name: str, client_id: str) -> str:
|
|
"""Obtient l'ID interne du client"""
|
|
try:
|
|
response = self.session.get(
|
|
f"{self.base_url}/admin/realms/{realm_name}/clients",
|
|
headers={"Authorization": f"Bearer {self.admin_token}"}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
clients = response.json()
|
|
for client in clients:
|
|
if client.get("clientId") == client_id:
|
|
return client.get("id")
|
|
|
|
except Exception as e:
|
|
print(f"Erreur récupération client ID: {e}")
|
|
|
|
return None
|
|
|
|
def fix_client_configuration(self, realm_name: str = "unionflow", client_id: str = "unionflow-mobile") -> bool:
|
|
"""Corrige la configuration du client pour mobile"""
|
|
print(f"🔧 Correction de la configuration du client {client_id}...")
|
|
|
|
# 1. Obtenir l'ID interne du client
|
|
internal_id = self.get_client_internal_id(realm_name, client_id)
|
|
if not internal_id:
|
|
print(f" ❌ Client {client_id} non trouvé")
|
|
return False
|
|
|
|
print(f" ✓ Client trouvé (ID interne: {internal_id})")
|
|
|
|
# 2. Configuration correcte pour une application mobile
|
|
client_config = {
|
|
"id": internal_id,
|
|
"clientId": client_id,
|
|
"name": "UnionFlow Mobile App",
|
|
"description": "Client pour l'application mobile UnionFlow",
|
|
"enabled": True,
|
|
"clientAuthenticatorType": "client-secret",
|
|
"secret": "",
|
|
"redirectUris": [
|
|
"http://localhost:*",
|
|
"http://127.0.0.1:*",
|
|
"http://192.168.1.11:*",
|
|
"unionflow://oauth/callback",
|
|
"unionflow://login",
|
|
"com.unionflow.mobile://oauth",
|
|
"urn:ietf:wg:oauth:2.0:oob"
|
|
],
|
|
"webOrigins": [
|
|
"http://localhost",
|
|
"http://127.0.0.1",
|
|
"http://192.168.1.11",
|
|
"+"
|
|
],
|
|
"notBefore": 0,
|
|
"bearerOnly": False,
|
|
"consentRequired": False,
|
|
"standardFlowEnabled": True,
|
|
"implicitFlowEnabled": False,
|
|
"directAccessGrantsEnabled": True,
|
|
"serviceAccountsEnabled": False,
|
|
"publicClient": True,
|
|
"frontchannelLogout": False,
|
|
"protocol": "openid-connect",
|
|
"attributes": {
|
|
"saml.assertion.signature": "false",
|
|
"saml.force.post.binding": "false",
|
|
"saml.multivalued.roles": "false",
|
|
"saml.encrypt": "false",
|
|
"saml.server.signature": "false",
|
|
"saml.server.signature.keyinfo.ext": "false",
|
|
"exclude.session.state.from.auth.response": "false",
|
|
"saml_force_name_id_format": "false",
|
|
"saml.client.signature": "false",
|
|
"tls.client.certificate.bound.access.tokens": "false",
|
|
"saml.authnstatement": "false",
|
|
"display.on.consent.screen": "false",
|
|
"saml.onetimeuse.condition": "false",
|
|
"access.token.lifespan": "300",
|
|
"client_credentials.use_refresh_token": "false",
|
|
"oauth2.device.authorization.grant.enabled": "false",
|
|
"oidc.ciba.grant.enabled": "false"
|
|
},
|
|
"authenticationFlowBindingOverrides": {},
|
|
"fullScopeAllowed": True,
|
|
"nodeReRegistrationTimeout": -1,
|
|
"defaultClientScopes": ["web-origins", "role_list", "profile", "roles", "email"],
|
|
"optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"]
|
|
}
|
|
|
|
try:
|
|
# 3. Mettre à jour la configuration
|
|
response = self.session.put(
|
|
f"{self.base_url}/admin/realms/{realm_name}/clients/{internal_id}",
|
|
json=client_config,
|
|
headers={
|
|
"Authorization": f"Bearer {self.admin_token}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
)
|
|
|
|
if response.status_code == 204:
|
|
print(f" ✅ Configuration du client mise à jour")
|
|
|
|
# 4. Vérifier la configuration
|
|
verify_response = self.session.get(
|
|
f"{self.base_url}/admin/realms/{realm_name}/clients/{internal_id}",
|
|
headers={"Authorization": f"Bearer {self.admin_token}"}
|
|
)
|
|
|
|
if verify_response.status_code == 200:
|
|
config = verify_response.json()
|
|
print(f" ✓ Configuration vérifiée:")
|
|
print(f" - Public Client: {config.get('publicClient')}")
|
|
print(f" - Direct Access Grants: {config.get('directAccessGrantsEnabled')}")
|
|
print(f" - Standard Flow: {config.get('standardFlowEnabled')}")
|
|
print(f" - Redirect URIs: {len(config.get('redirectUris', []))} configurées")
|
|
print(f" - Web Origins: {len(config.get('webOrigins', []))} configurées")
|
|
|
|
# Afficher les redirect URIs
|
|
print(f" ✓ Redirect URIs configurées:")
|
|
for uri in config.get('redirectUris', []):
|
|
print(f" - {uri}")
|
|
|
|
return True
|
|
else:
|
|
print(f" ❌ Erreur mise à jour: {response.status_code}")
|
|
print(f" Réponse: {response.text}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f" ❌ Exception: {e}")
|
|
return False
|
|
|
|
def test_client_after_fix(self, realm_name: str = "unionflow", client_id: str = "unionflow-mobile") -> bool:
|
|
"""Teste le client après correction"""
|
|
print(f"🧪 Test du client après correction...")
|
|
|
|
# Test d'authentification simple (Resource Owner Password Credentials)
|
|
test_data = {
|
|
"username": "marie.active",
|
|
"password": "Marie123!",
|
|
"grant_type": "password",
|
|
"client_id": client_id
|
|
}
|
|
|
|
try:
|
|
response = self.session.post(
|
|
f"{self.base_url}/realms/{realm_name}/protocol/openid-connect/token",
|
|
data=test_data,
|
|
headers={"Content-Type": "application/x-www-form-urlencoded"}
|
|
)
|
|
|
|
print(f" Status: {response.status_code}")
|
|
|
|
if response.status_code == 200:
|
|
token_data = response.json()
|
|
if "access_token" in token_data:
|
|
print(f" ✅ AUTHENTIFICATION RÉUSSIE !")
|
|
print(f" ✓ Token reçu")
|
|
return True
|
|
else:
|
|
print(f" ❌ Token manquant")
|
|
else:
|
|
print(f" ❌ Authentification échouée")
|
|
print(f" Réponse: {response.text}")
|
|
|
|
except Exception as e:
|
|
print(f" ❌ Exception: {e}")
|
|
|
|
return False
|
|
|
|
def fix_complete(self):
|
|
"""Correction complète du client"""
|
|
print("=" * 80)
|
|
print("🔧 CORRECTION DU CLIENT UNIONFLOW-MOBILE")
|
|
print("=" * 80)
|
|
print()
|
|
|
|
if not self.get_admin_token():
|
|
print("❌ Impossible d'obtenir le token admin")
|
|
return False
|
|
|
|
print("✅ Token admin obtenu")
|
|
print()
|
|
|
|
# Corriger la configuration
|
|
if not self.fix_client_configuration():
|
|
print("❌ Échec de la correction du client")
|
|
return False
|
|
|
|
print()
|
|
|
|
# Tester le client
|
|
if self.test_client_after_fix():
|
|
print()
|
|
print("=" * 80)
|
|
print("🎉 CLIENT CORRIGÉ AVEC SUCCÈS !")
|
|
print("=" * 80)
|
|
print()
|
|
print("🚀 Le client unionflow-mobile est maintenant correctement configuré")
|
|
print(" pour votre application mobile avec les redirect URIs appropriées.")
|
|
print()
|
|
print("📱 REDIRECT URIs CONFIGURÉES :")
|
|
print(" • http://localhost:* (pour tests locaux)")
|
|
print(" • http://127.0.0.1:* (pour tests locaux)")
|
|
print(" • http://192.168.1.11:* (pour votre réseau)")
|
|
print(" • unionflow://oauth/callback (pour l'app mobile)")
|
|
print(" • unionflow://login (pour l'app mobile)")
|
|
print(" • com.unionflow.mobile://oauth (pour l'app mobile)")
|
|
print(" • urn:ietf:wg:oauth:2.0:oob (pour OAuth out-of-band)")
|
|
print()
|
|
print("✅ Votre application mobile peut maintenant s'authentifier !")
|
|
return True
|
|
else:
|
|
print()
|
|
print("=" * 80)
|
|
print("⚠️ CLIENT CORRIGÉ MAIS PROBLÈME D'AUTHENTIFICATION")
|
|
print("=" * 80)
|
|
print()
|
|
print("Le client a été reconfiguré mais l'authentification échoue encore.")
|
|
print("Cela peut être dû aux utilisateurs. Essayez la configuration manuelle :")
|
|
print()
|
|
print("1. Ouvrez http://localhost:8180/admin/")
|
|
print("2. Connectez-vous avec admin/admin")
|
|
print("3. Realm 'unionflow' > Users > marie.active")
|
|
print("4. Credentials > Set password > Marie123! (non temporaire)")
|
|
return False
|
|
|
|
|
|
def main():
|
|
fixer = ClientRedirectFixer()
|
|
fixer.fix_complete()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|