diff --git a/admin-ui/app/locales/en/translation.json b/admin-ui/app/locales/en/translation.json index 282d67fdff..b6998808cf 100644 --- a/admin-ui/app/locales/en/translation.json +++ b/admin-ui/app/locales/en/translation.json @@ -619,7 +619,10 @@ "reloginToViewCedarlingChanges": "Please Re-login to view the cedarling changes.", "allAvailableHintsSelected": "All available hint options are selected", "noMatchingOptions": "No matching options", - "nothingToShowInTheList": "Nothing to show in the list" + "nothingToShowInTheList": "Nothing to show in the list", + "simple_password_auth": "Simple Password Authentication", + "basic_auth": "Basic Authentication", + "agama_auth": "Agama Authentication" }, "languages": { "french": "French", @@ -642,13 +645,14 @@ "config-api": "Config-API", "security": "Security", "authn": "Authn", + "webhooks": "Webhooks", "agama_flows": "Agama Flows", "default_acr": "Default ACR", "acrs": "ACRs", "aliases": "Aliases", "api_config": "Config API properties", - "builtIn": "Built-In", + "basic": "Basic", "securityDropdown": { "adminUiRoles": "Admin UI Roles", "capabilities": "Capabilities", @@ -688,6 +692,7 @@ "user_claims": "User Claims", "scopes": "Scopes", "scripts": "Scripts", + "ldap_servers": "LDAP Servers", "services": "Services", "sessions": "Sessions", "audit_logs": "Audit Logs", @@ -841,9 +846,74 @@ "product_version": "Version number of this database product", "driver_name": "Name of this JDBC driver", "driver_version": "Version number of this JDBC driver", - "followingPermissionRequiredToBeAdded": "We need to add the following essential permissions to the role to ensure users with this role can access the Admin UI." + "followingPermissionRequiredToBeAdded": "We need to add the following essential permissions to the role to ensure users with this role can access the Admin UI.", + "authn": { + "ldap": { + "fields": { + "acr": "ACR", + "bind_dn": "Bind DN", + "bind_password": "Bind Password", + "remote_ldap_server": "Remote LDAP Server", + "max_connections": "Max Connections", + "base_dns": "Base DNs", + "remote_primary_key": "Remote Primary Key", + "local_primary_key": "Local Primary Key", + "servers": "Servers", + "level": "Level", + "default_authn_method": "Default Authn Method", + "use_ssl": "Use SSL", + "enabled": "Enabled", + "enable": "Enabled", + "disable": "Disabled", + "status": "Status" + }, + "placeholders": { + "acr": "Enter ACR", + "bind_dn": "Enter Bind DN", + "bind_password": "Enter Bind Password", + "remote_ldap_server": "Enter Remote LDAP Server", + "max_connections": "Enter Max Connections", + "base_dns": "Enter Base DNs", + "remote_primary_key": "Enter Remote Primary Key", + "local_primary_key": "Enter Local Primary Key", + "level": "Enter Level", + "default_authn_method": "Enter Default Authn Method", + "action_commit_message": "Enter reason for change" + }, + "errors": { + "acr_required": "ACR is required!", + "bind_dn_required": "Bind DN is required!", + "bind_password_required": "Bind Password is required!", + "remote_ldap_server_required": "Remote LDAP Server is required!", + "remote_ldap_server_invalid": "Server must be a valid LDAP URL (http:// or https://)", + "max_connections_required": "Max Connections is required!", + "max_connections_type": "Max Connections must be a number", + "max_connections_positive": "Max connections must be a positive number", + "max_connections_integer": "Max connections must be an integer", + "base_dns_required": "Base DNs is required!", + "remote_primary_key_required": "Remote Primary Key is required!", + "local_primary_key_required": "Local Primary Key is required!", + "level_required": "Level is required!", + "level_type": "Level must be a number", + "level_min": "Level must be at least 1", + "level_integer": "Level must be an integer", + "default_authn_method_required": "Default Authn Method is required!" + } + } + } }, "placeholders": { + "acr": "Enter ACR", + "level": "Enter level", + "default_authn_method": "Select default authentication method", + "bind_dn": "Enter Bind DN", + "max_connections": "Enter max connections", + "local_primary_key": "Enter local primary key", + "base_dns": "Enter base DNs", + "enabled": "Enable or disable", + "remote_primary_key": "Enter the remote primary key", + "remote_ldap_server": "Enter the remote LDAP server", + "bind_password": "Enter the bind password", "id": "Enter id", "action_commit_message": "Provide the reason of this change", "activate_ldap_configuration": "Activate ldap configuration", @@ -898,7 +968,6 @@ "activate_sql_configuration": "Activate SQL configuration.", "script_path": "Enter script file path", "iconUrl": "Icon URL", - "level": "Level", "expires_after": "Expiration After Date", "expires_before": "Expiration Before Date", "charMoreThan512": "characters over limit (maximum 512)", @@ -908,6 +977,7 @@ "titles": { "activeTokens": "Active Tokens", "acrs": "ACRs", + "acr_management": "ACR Management", "active_users": "Actives Users && Access Token Stats", "assets": "Jans Assets", "asset_add": "Adding new Jans Asset", @@ -1077,7 +1147,59 @@ "hash_algorithm": "Hash Algorithim", "saml_acr": "The SAML parameter Authentication Context Requests", "primary_key": "Primary Key", - "description": "Description" + "description": "Description", + "ldap": { + "fields": { + "acr": "ACR", + "bind_dn": "Bind DN", + "bind_password": "Bind Password", + "remote_ldap_server": "Remote LDAP Server", + "max_connections": "Max Connections", + "base_dns": "Base DNs", + "remote_primary_key": "Remote Primary Key", + "local_primary_key": "Local Primary Key", + "servers": "Servers", + "level": "Level", + "default_authn_method": "Default Authn Method", + "use_ssl": "Use SSL", + "enabled": "Enabled", + "enable": "Enabled", + "disable": "Disabled", + "status": "Status" + }, + "placeholders": { + "acr": "Enter ACR", + "bind_dn": "Enter Bind DN", + "bind_password": "Enter Bind Password", + "remote_ldap_server": "Enter Remote LDAP Server", + "max_connections": "Enter Max Connections", + "base_dns": "Enter Base DNs", + "remote_primary_key": "Enter Remote Primary Key", + "local_primary_key": "Enter Local Primary Key", + "level": "Enter Level", + "default_authn_method": "Enter Default Authn Method", + "action_commit_message": "Enter reason for change" + }, + "errors": { + "acr_required": "ACR is required!", + "bind_dn_required": "Bind DN is required!", + "bind_password_required": "Bind Password is required!", + "remote_ldap_server_required": "Remote LDAP Server is required!", + "remote_ldap_server_invalid": "Server must be a valid LDAP URL (http:// or https://)", + "max_connections_required": "Max Connections is required!", + "max_connections_type": "Max Connections must be a number", + "max_connections_positive": "Max connections must be a positive number", + "max_connections_integer": "Max connections must be an integer", + "base_dns_required": "Base DNs is required!", + "remote_primary_key_required": "Remote Primary Key is required!", + "local_primary_key_required": "Local Primary Key is required!", + "level_required": "Level is required!", + "level_type": "Level must be a number", + "level_min": "Level must be at least 1", + "level_integer": "Level must be an integer", + "default_authn_method_required": "Default Authn Method is required!" + } + } }, "roles": { "name": "Role name", diff --git a/admin-ui/app/locales/es/translation.json b/admin-ui/app/locales/es/translation.json index bc0112cbcd..41ae5e4905 100644 --- a/admin-ui/app/locales/es/translation.json +++ b/admin-ui/app/locales/es/translation.json @@ -618,8 +618,11 @@ "showCedarLogs?": "¿Registro de Cedarling habilitado?", "reloginToViewCedarlingChanges": "Por favor, vuelve a iniciar sesión para ver los cambios de Cedarling.", "allAvailableHintsSelected": "Todas las opciones de sugerencia disponibles están seleccionadas", - "noMatchingOptions": "No hay opciones coincidentes", - "nothingToShowInTheList": "Nada que mostrar en la lista" + "noMatchingOptions": "No hay opciones que coincidan", + "nothingToShowInTheList": "Nada que mostrar en la lista", + "simple_password_auth": "Autenticación simple por contraseña", + "basic_auth": "Autenticación básica", + "agama_auth": "Autenticación Agama" }, "languages": { "french": "Frances", @@ -647,8 +650,8 @@ "default_acr": "ACR Predeterminado", "acrs": "ACRs", "aliases": "Alias", - "api_config": "Propiedades de la API de Configuración", - "builtIn": "Integrado", + "api_config": "Propiedades de la API de configuración", + "basic": "Integrado", "securityDropdown": { "adminUiRoles": "Roles de la Interfaz de Administración", "capabilities": "Capacidades", @@ -818,27 +821,91 @@ "role_already_exists": "El rol ya existe" }, "tooltips": { - "add_attribute": "Añadir atributo", - "add_ldap": "Añadir LDAP", - "advanced_search_options": "Opciones de búsqueda avanzada", - "delete_attribute": "Eliminar atributo", - "delete_record": "Eliminar registro", - "edit_ldap": "Editar LDAP", - "edit_attribute": "Editar atributo", - "refresh_data": "Actualizar datos", - "view_attribute": "Ver atributo", - "edit_sql": "Editar SQL", - "add_sql": "Añadir SQL", - "client_credentials_access_token_count": "Número de tokens de acceso de credenciales de cliente", - "authz_code_access_token_count": "Número de tokens de acceso de código Authz", - "authz_code_idtoken_count": "Número de tokens ID de código Authz", - "database_name": "Nombre actual del catálogo del objeto", - "schema_name": "Nombre actual del esquema del objeto", - "product_name": "Nombre de este producto de base de datos", - "product_version": "Número de versión de este producto de base de datos", - "driver_name": "Nombre de este controlador JDBC", - "driver_version": "Número de versión de este controlador JDBC", - "followingPermissionRequiredToBeAdded": "Necesitamos añadir los siguientes permisos esenciales al rol para asegurar que los usuarios con este rol puedan acceder a la Admin UI." + "add_user": "Agregar usuario", + "edit_user": "Editar usuario", + "delete_user": "Eliminar usuario", + "access_token_signing_alg": "Algoritmo utilizado para firmar tokens de acceso", + "add_base_dn": "Agrega una nueva base DN", + "add_mapping": "Agrega un nuevo mapeo de atributos", + "add_property": "Agrega una nueva propiedad", + "add_server": "Agrega un nuevo servidor", + "attribute_mappings": "Mapea atributos desde el origen al destino", + "authorization_code_access_token": "Token de acceso generado mediante código de autorización", + "client_credentials_access_token": "Token de acceso generado mediante credenciales de cliente", + "copy_configuration": "Copia la configuración actual", + "default_permission_in_token": "Permiso que se incluye por defecto en el token", + "deploy": "Despliega la configuración o aplicación", + "edit": "Edita el elemento seleccionado", + "remove": "Elimina el elemento seleccionado", + "reset": "Restaura la configuración a los valores predeterminados", + "save": "Guarda los cambios realizados", + "search": "Busca dentro de la lista o base de datos", + "submit": "Envía la información o cambios", + "test": "Prueba la configuración", + "view": "Visualiza los detalles del elemento", + "yes": "Confirma la acción", + "no": "Cancela la acción", + "delete": "Elimina el elemento definitivamente", + "revoke": "Revoca un token o permiso", + "try_again": "Intenta ejecutar nuevamente la acción", + "show_error": "Muestra los detalles del error", + "ok": "Confirma el mensaje", + "copy_to_clipboard": "Copia el valor al portapapeles", + "export_csv": "Exporta los datos en formato CSV", + "authn": { + "ldap": { + "fields": { + "acr": "ACR", + "bind_dn": "DN de Vinculación", + "bind_password": "Contraseña de Vinculación", + "remote_ldap_server": "Servidor LDAP Remoto", + "max_connections": "Conexiones Máximas", + "base_dns": "DNs Base", + "remote_primary_key": "Clave Primaria Remota", + "local_primary_key": "Clave Primaria Local", + "servers": "Servidores", + "level": "Nivel", + "default_authn_method": "Método de Autenticación Predeterminado", + "use_ssl": "Usar SSL", + "enabled": "Habilitado", + "enable": "Habilitado", + "disable": "Deshabilitado", + "status": "Estado" + }, + "placeholders": { + "acr": "Introducir ACR", + "bind_dn": "Introducir DN de Vinculación", + "bind_password": "Introducir Contraseña de Vinculación", + "remote_ldap_server": "Introducir Servidor LDAP Remoto", + "max_connections": "Introducir Conexiones Máximas", + "base_dns": "Introducir DNs Base", + "remote_primary_key": "Introducir Clave Primaria Remota", + "local_primary_key": "Introducir Clave Primaria Local", + "level": "Introducir Nivel", + "default_authn_method": "Introducir Método de Autenticación Predeterminado", + "action_commit_message": "Introducir motivo del cambio" + }, + "errors": { + "acr_required": "¡Se requiere ACR!", + "bind_dn_required": "¡Se requiere DN de Vinculación!", + "bind_password_required": "¡Se requiere Contraseña de Vinculación!", + "remote_ldap_server_required": "¡Se requiere Servidor LDAP Remoto!", + "remote_ldap_server_invalid": "El servidor debe ser una URL LDAP válida (ldap:// o ldaps://)", + "max_connections_required": "¡Se requieren Conexiones Máximas!", + "max_connections_type": "Las Conexiones Máximas deben ser un número", + "max_connections_positive": "Las conexiones máximas deben ser un número positivo", + "max_connections_integer": "Las conexiones máximas deben ser un número entero", + "base_dns_required": "¡Se requieren DNs Base!", + "remote_primary_key_required": "¡Se requiere Clave Primaria Remota!", + "local_primary_key_required": "¡Se requiere Clave Primaria Local!", + "level_required": "¡Se requiere Nivel!", + "level_type": "El Nivel debe ser un número", + "level_min": "El nivel debe ser al menos 1", + "level_integer": "El nivel debe ser un número entero", + "default_authn_method_required": "¡Se requiere Método de Autenticación Predeterminado!" + } + } + } }, "placeholders": { "id": "Introduce el id", @@ -905,13 +972,14 @@ "titles": { "activeTokens": "Tokens activos", "acrs": "ACRs", - "active_users": "Usuarios activos y estadísticas de tokens de acceso", - "assets": "Jans Assets", - "asset_add": "Añadiendo nuevo Jans Asset", - "asset_edit": "Editando Jans Asset", - "introspection_object": "Objeto de introspección", - "acrs_logging": "ACRs y Logging", - "algorithmic_keys": "Claves algorítmicas", + "acr_management": "Gestión de ACR", + "active_users": "Estádisticas de Usuarios Activos & Token de accesos", + "assets": "Activos Jans", + "asset_add": "Añadir un Nuevo Activo Jans", + "asset_edit": "Editar un Activo Jans", + "introspection_object": "Instrospección de Objeto", + "acrs_logging": "ACRs & Registro", + "algorithmic_keys": "Llaves Algoritmicas", "jans_lock": "Jans Lock", "config_api_configuration": "Configuración de Config API", "database_information": "Información de la base de datos", @@ -1071,10 +1139,62 @@ "acr": "Referencia de Clase de Contexto de Autenticación", "level": "Nivel de aseguramiento de autenticación", "password_attribute": "Contraseña", - "hash_algorithm": "Algoritmo de Hash", - "saml_acr": "Parámetro SAML de solicitudes de contexto de autenticación", - "primary_key": "Clave primaria", - "description": "Descripción" + "hash_algorithm": "Hash del Algoritmo", + "saml_acr": "El Parametro de SAML en Contexto de Solicitud de Antenticación", + "primary_key": "Llave Primaria", + "description": "Descripción", + "ldap": { + "fields": { + "acr": "ACR", + "bind_dn": "DN de Vinculación", + "bind_password": "Contraseña de Vinculación", + "remote_ldap_server": "Servidor LDAP Remoto", + "max_connections": "Conexiones Máximas", + "base_dns": "DNs Base", + "remote_primary_key": "Clave Primaria Remota", + "local_primary_key": "Clave Primaria Local", + "servers": "Servidores", + "level": "Nivel", + "default_authn_method": "Método de Autenticación Predeterminado", + "use_ssl": "Usar SSL", + "enabled": "Habilitado", + "enable": "Habilitado", + "disable": "Deshabilitado", + "status": "Estado" + }, + "placeholders": { + "acr": "Introducir ACR", + "bind_dn": "Introducir DN de Vinculación", + "bind_password": "Introducir Contraseña de Vinculación", + "remote_ldap_server": "Introducir Servidor LDAP Remoto", + "max_connections": "Introducir Conexiones Máximas", + "base_dns": "Introducir DNs Base", + "remote_primary_key": "Introducir Clave Primaria Remota", + "local_primary_key": "Introducir Clave Primaria Local", + "level": "Introducir Nivel", + "default_authn_method": "Introducir Método de Autenticación Predeterminado", + "action_commit_message": "Introducir motivo del cambio" + }, + "errors": { + "acr_required": "¡Se requiere ACR!", + "bind_dn_required": "¡Se requiere DN de Vinculación!", + "bind_password_required": "¡Se requiere Contraseña de Vinculación!", + "remote_ldap_server_required": "¡Se requiere Servidor LDAP Remoto!", + "remote_ldap_server_invalid": "El servidor debe ser una URL LDAP válida (ldap:// o ldaps://)", + "max_connections_required": "¡Se requieren Conexiones Máximas!", + "max_connections_type": "Las Conexiones Máximas deben ser un número", + "max_connections_positive": "Las conexiones máximas deben ser un número positivo", + "max_connections_integer": "Las conexiones máximas deben ser un número entero", + "base_dns_required": "¡Se requieren DNs Base!", + "remote_primary_key_required": "¡Se requiere Clave Primaria Remota!", + "local_primary_key_required": "¡Se requiere Clave Primaria Local!", + "level_required": "¡Se requiere Nivel!", + "level_type": "El Nivel debe ser un número", + "level_min": "El nivel debe ser al menos 1", + "level_integer": "El nivel debe ser un número entero", + "default_authn_method_required": "¡Se requiere Método de Autenticación Predeterminado!" + } + } }, "roles": { "name": "Nombre del rol", diff --git a/admin-ui/app/locales/fr/translation.json b/admin-ui/app/locales/fr/translation.json index c9f005fc83..b39919959a 100644 --- a/admin-ui/app/locales/fr/translation.json +++ b/admin-ui/app/locales/fr/translation.json @@ -53,10 +53,11 @@ "agama_flows": "Flux Agama", "default_acr": "ACR par défaut", "acrs": "ACRs", + "acr_management": "Gestion des ACR", "aliases": "Aliases", "trust_relationships": "Relations de confiance", "api_config": "Configurer les propriétés de l'API", - "builtIn": "Intégré", + "basic": "Basique", "securityDropdown": { "adminUiRoles": "Rôles de l'interface utilisateur d'administration", "capabilities": "Capacités", @@ -520,6 +521,7 @@ "scope_type": "Type de portée", "scopes:": "Portées", "scripts": "Scénarios", + "ldap_servers": "Serveurs LDAP", "script_type": "Type de script", "select_date_range": "Sélectionnez une plage de dates", "sector_uri": "Identificateur de secteur URI", @@ -650,6 +652,9 @@ "allAvailableHintsSelected": "Toutes les options d'indice disponibles sont sélectionnées.", "noMatchingOptions": "Aucune option correspondante", "nothingToShowInTheList": "Rien à montrer dans la liste", + "simple_password_auth": "Authentification simple par mot de passe", + "basic_auth": "Authentification de base", + "agama_auth": "Authentification Agama", "disable_logger_timer": "Désactiver le Minuteur du Journal", "skip_defined_password_validation": "Ignorer la Validation du Mot de Passe Défini" }, @@ -765,6 +770,60 @@ "delete_record": "Supprimer l'enregistrement", "edit_ldap": "Modifier LDAP", "edit_attribute": "Modifier l'attribut", + "authn": { + "ldap": { + "fields": { + "acr": "ACR", + "bind_dn": "DN de liaison", + "bind_password": "Mot de passe de liaison", + "remote_ldap_server": "Serveur LDAP distant", + "max_connections": "Connexions maximales", + "base_dns": "DN de base", + "remote_primary_key": "Clé primaire distante", + "local_primary_key": "Clé primaire locale", + "servers": "Serveurs", + "level": "Niveau", + "default_authn_method": "Méthode d'authentification par défaut", + "use_ssl": "Utiliser SSL", + "enabled": "Activé", + "enable": "Activé", + "disable": "Désactivé", + "status": "Statut" + }, + "placeholders": { + "acr": "Entrez ACR", + "bind_dn": "Entrez DN de liaison", + "bind_password": "Entrez le mot de passe de liaison", + "remote_ldap_server": "Entrez le serveur LDAP distant", + "max_connections": "Entrez les connexions maximales", + "base_dns": "Entrez les DN de base", + "remote_primary_key": "Entrez la clé primaire distante", + "local_primary_key": "Entrez la clé primaire locale", + "level": "Entrez le niveau", + "default_authn_method": "Entrez la méthode d'authentification par défaut", + "action_commit_message": "Entrez la raison du changement" + }, + "errors": { + "acr_required": "ACR est requis!", + "bind_dn_required": "DN de liaison est requis!", + "bind_password_required": "Mot de passe de liaison est requis!", + "remote_ldap_server_required": "Serveur LDAP distant est requis!", + "remote_ldap_server_invalid": "Le serveur doit être une URL LDAP valide (ldap:// ou ldaps://)", + "max_connections_required": "Connexions maximales sont requises!", + "max_connections_type": "Les connexions maximales doivent être un nombre", + "max_connections_positive": "Les connexions maximales doivent être un nombre positif", + "max_connections_integer": "Les connexions maximales doivent être un nombre entier", + "base_dns_required": "DN de base sont requis!", + "remote_primary_key_required": "Clé primaire distante est requise!", + "local_primary_key_required": "Clé primaire locale est requise!", + "level_required": "Niveau est requis!", + "level_type": "Le niveau doit être un nombre", + "level_min": "Le niveau doit être au moins 1", + "level_integer": "Le niveau doit être un nombre entier", + "default_authn_method_required": "Méthode d'authentification par défaut est requise!" + } + } + }, "refresh_data": "Actualiser les données", "view_attribute": "Afficher l'attribut", "client_credentials_access_token_count": "Nombre de jetons d'accès aux informations d'identification du client", @@ -779,6 +838,17 @@ "followingPermissionRequiredToBeAdded": "Nous devons ajouter les autorisations essentielles suivantes au rôle pour garantir que les utilisateurs disposant de ce rôle peuvent accéder à l'interface utilisateur d'administration." }, "placeholders": { + "acr": "Entrez ACR", + "level": "Entrez le niveau", + "default_authn_method": "Sélectionnez la méthode d'authentification par défaut", + "bind_dn": "Entrez le Bind DN", + "max_connections": "Entrez le nombre maximum de connexions", + "local_primary_key": "Entrez la clé primaire locale", + "base_dns": "Entrez les base DNs", + "enabled": "Activer ou désactiver", + "remote_primary_key": "Entrez la clé primaire distante", + "remote_ldap_server": "Entrez le serveur LDAP distant", + "bind_password": "Entrez le mot de passe de liaison", "id": "Enter id", "action_commit_message": "Fournir la raison de ce changement", "activate_ldap_configuration": "Activer la configuration LDAP", @@ -1466,7 +1536,59 @@ "status": "Statut du SSA (ACTIF, UTILISÉ, EXPIRÉ ou RÉVOQUÉ)" }, "authn": { - "acr": "Référence de classe de contexte d'authentification" + "acr": "Référence de classe de contexte d'authentification", + "ldap": { + "fields": { + "acr": "ACR", + "bind_dn": "DN de liaison", + "bind_password": "Mot de passe de liaison", + "remote_ldap_server": "Serveur LDAP distant", + "max_connections": "Connexions maximales", + "base_dns": "DN de base", + "remote_primary_key": "Clé primaire distante", + "local_primary_key": "Clé primaire locale", + "servers": "Serveurs", + "level": "Niveau", + "default_authn_method": "Méthode d'authentification par défaut", + "use_ssl": "Utiliser SSL", + "enabled": "Activé", + "enable": "Activé", + "disable": "Désactivé", + "status": "Statut" + }, + "placeholders": { + "acr": "Entrez ACR", + "bind_dn": "Entrez DN de liaison", + "bind_password": "Entrez le mot de passe de liaison", + "remote_ldap_server": "Entrez le serveur LDAP distant", + "max_connections": "Entrez les connexions maximales", + "base_dns": "Entrez les DN de base", + "remote_primary_key": "Entrez la clé primaire distante", + "local_primary_key": "Entrez la clé primaire locale", + "level": "Entrez le niveau", + "default_authn_method": "Entrez la méthode d'authentification par défaut", + "action_commit_message": "Entrez la raison du changement" + }, + "errors": { + "acr_required": "ACR est requis!", + "bind_dn_required": "DN de liaison est requis!", + "bind_password_required": "Mot de passe de liaison est requis!", + "remote_ldap_server_required": "Serveur LDAP distant est requis!", + "remote_ldap_server_invalid": "Le serveur doit être une URL LDAP valide (ldap:// ou ldaps://)", + "max_connections_required": "Connexions maximales sont requises!", + "max_connections_type": "Les connexions maximales doivent être un nombre", + "max_connections_positive": "Les connexions maximales doivent être un nombre positif", + "max_connections_integer": "Les connexions maximales doivent être un nombre entier", + "base_dns_required": "DN de base sont requis!", + "remote_primary_key_required": "Clé primaire distante est requise!", + "local_primary_key_required": "Clé primaire locale est requise!", + "level_required": "Niveau est requis!", + "level_type": "Le niveau doit être un nombre", + "level_min": "Le niveau doit être au moins 1", + "level_integer": "Le niveau doit être un nombre entier", + "default_authn_method_required": "Méthode d'authentification par défaut est requise!" + } + } }, "openid_client": { "displayName": "Nom du client à présenter à l'utilisateur final.", diff --git a/admin-ui/app/locales/pt/translation.json b/admin-ui/app/locales/pt/translation.json index d6fc5f3036..b87c56565f 100644 --- a/admin-ui/app/locales/pt/translation.json +++ b/admin-ui/app/locales/pt/translation.json @@ -56,7 +56,7 @@ "default_acr": "ACR padrão", "acrs": "ACRs", "aliases": "Aliases", - "builtIn": "Integrado", + "basic": "Básico", "api_config": "Configurar propriedades da API", "securityDropdown": { "adminUiRoles": "Funções da interface do administrador", @@ -355,6 +355,7 @@ "base_dns": "DNs de base", "bind_dn": "Vincular DN", "base_dn": "DN Base", + "ldap_servers": "Servidores LDAP", "client_password": "Senha do Cliente", "message_consumer_type": "Tipo de Consumidor de Mensagens", "openid_issuer": "Emissor OpenID", @@ -645,6 +646,9 @@ "allAvailableHintsSelected": "Todas as opções de dica disponíveis estão selecionadas", "noMatchingOptions": "Nenhuma opção correspondente", "nothingToShowInTheList": "Nada a mostrar na lista", + "simple_password_auth": "Autenticação simples por senha", + "basic_auth": "Autenticação básica", + "agama_auth": "Autenticação Agama", "disable_logger_timer": "Desativar Temporizador de Logs", "skip_defined_password_validation": "Pular Validação de Senha Definida" }, @@ -755,6 +759,60 @@ "edit_user": "Editar usuário", "delete_user": "Excluir usuário", "add_ldap": "Adicionar LDAP", + "authn": { + "ldap": { + "fields": { + "acr": "ACR", + "bind_dn": "DN de Ligação", + "bind_password": "Senha de Ligação", + "remote_ldap_server": "Servidor LDAP Remoto", + "max_connections": "Conexões Máximas", + "base_dns": "DNs Base", + "remote_primary_key": "Chave Primária Remota", + "local_primary_key": "Chave Primária Local", + "servers": "Servidores", + "level": "Nível", + "default_authn_method": "Método de Autenticação Padrão", + "use_ssl": "Usar SSL", + "enabled": "Ativado", + "enable": "Ativado", + "disable": "Desativado", + "status": "Status" + }, + "placeholders": { + "acr": "Insira ACR", + "bind_dn": "Insira DN de Ligação", + "bind_password": "Insira Senha de Ligação", + "remote_ldap_server": "Insira Servidor LDAP Remoto", + "max_connections": "Insira Conexões Máximas", + "base_dns": "Insira DNs Base", + "remote_primary_key": "Insira Chave Primária Remota", + "local_primary_key": "Insira Chave Primária Local", + "level": "Insira Nível", + "default_authn_method": "Insira Método de Autenticação Padrão", + "action_commit_message": "Insira o motivo da mudança" + }, + "errors": { + "acr_required": "ACR é obrigatório!", + "bind_dn_required": "DN de Ligação é obrigatório!", + "bind_password_required": "Senha de Ligação é obrigatória!", + "remote_ldap_server_required": "Servidor LDAP Remoto é obrigatório!", + "remote_ldap_server_invalid": "O servidor deve ser uma URL LDAP válida (ldap:// ou ldaps://)", + "max_connections_required": "Conexões Máximas são obrigatórias!", + "max_connections_type": "Conexões Máximas devem ser um número", + "max_connections_positive": "As conexões máximas devem ser um número positivo", + "max_connections_integer": "As conexões máximas devem ser um número inteiro", + "base_dns_required": "DNs Base são obrigatórios!", + "remote_primary_key_required": "Chave Primária Remota é obrigatória!", + "local_primary_key_required": "Chave Primária Local é obrigatória!", + "level_required": "Nível é obrigatório!", + "level_type": "O Nível deve ser um número", + "level_min": "O nível deve ser pelo menos 1", + "level_integer": "O nível deve ser um número inteiro", + "default_authn_method_required": "Método de Autenticação Padrão é obrigatório!" + } + } + }, "advanced_search_options": "Opções de pesquisa avançada", "delete_attribute": "Apagar atributo", "delete_record": "Apagar registro", @@ -774,6 +832,17 @@ "followingPermissionRequiredToBeAdded": "Precisamos adicionar as seguintes permissões essenciais à função para garantir que os usuários com essa função possam acessar a interface do usuário do administrador." }, "placeholders": { + "acr": "Insira o ACR", + "level": "Insira o nível", + "default_authn_method": "Selecione o método de autenticação padrão", + "bind_dn": "Insira o Bind DN", + "max_connections": "Insira o número máximo de conexões", + "local_primary_key": "Insira a chave primária local", + "base_dns": "Insira os base DNs", + "enabled": "Ativar ou desativar", + "remote_primary_key": "Insira a chave primária remota", + "remote_ldap_server": "Insira o servidor LDAP remoto", + "bind_password": "Digite a senha de ligação", "id": "Enter id", "action_commit_message": "Forneça o motivo desta mudança", "activate_ldap_configuration": "Ativar configuração ldap", @@ -827,6 +896,7 @@ }, "titles": { "acrs": "ACRs", + "acr_management": "Gerenciamento de ACR", "assets": "Jans Assets", "asset_add": "Adding new Jans Asset", "asset_edit": "Editing new Jans Asset", @@ -1560,7 +1630,59 @@ "status": "Status do SSA (ATIVO, USADO, EXPIRADO ou REVOGADO)" }, "authn": { - "acr": "Référence de classe de contexte d'authentification" + "acr": "Référence de classe de contexte d'authentification", + "ldap": { + "fields": { + "acr": "ACR", + "bind_dn": "DN de Ligação", + "bind_password": "Senha de Ligação", + "remote_ldap_server": "Servidor LDAP Remoto", + "max_connections": "Conexões Máximas", + "base_dns": "DNs Base", + "remote_primary_key": "Chave Primária Remota", + "local_primary_key": "Chave Primária Local", + "servers": "Servidores", + "level": "Nível", + "default_authn_method": "Método de Autenticação Padrão", + "use_ssl": "Usar SSL", + "enabled": "Ativado", + "enable": "Ativado", + "disable": "Desativado", + "status": "Status" + }, + "placeholders": { + "acr": "Insira ACR", + "bind_dn": "Insira DN de Ligação", + "bind_password": "Insira Senha de Ligação", + "remote_ldap_server": "Insira Servidor LDAP Remoto", + "max_connections": "Insira Conexões Máximas", + "base_dns": "Insira DNs Base", + "remote_primary_key": "Insira Chave Primária Remota", + "local_primary_key": "Insira Chave Primária Local", + "level": "Insira Nível", + "default_authn_method": "Insira Método de Autenticação Padrão", + "action_commit_message": "Insira o motivo da mudança" + }, + "errors": { + "acr_required": "ACR é obrigatório!", + "bind_dn_required": "DN de Ligação é obrigatório!", + "bind_password_required": "Senha de Ligação é obrigatória!", + "remote_ldap_server_required": "Servidor LDAP Remoto é obrigatório!", + "remote_ldap_server_invalid": "O servidor deve ser uma URL LDAP válida (ldap:// ou ldaps://)", + "max_connections_required": "Conexões Máximas são obrigatórias!", + "max_connections_type": "Conexões Máximas devem ser um número", + "max_connections_positive": "As conexões máximas devem ser um número positivo", + "max_connections_integer": "As conexões máximas devem ser um número inteiro", + "base_dns_required": "DNs Base são obrigatórios!", + "remote_primary_key_required": "Chave Primária Remota é obrigatória!", + "local_primary_key_required": "Chave Primária Local é obrigatória!", + "level_required": "Nível é obrigatório!", + "level_type": "O Nível deve ser um número", + "level_min": "O nível deve ser pelo menos 1", + "level_integer": "O nível deve ser um número inteiro", + "default_authn_method_required": "Método de Autenticação Padrão é obrigatório!" + } + } } }, "script": { diff --git a/admin-ui/app/utils/ApiResources.ts b/admin-ui/app/utils/ApiResources.ts index 63024f6112..d31ea5ad6e 100644 --- a/admin-ui/app/utils/ApiResources.ts +++ b/admin-ui/app/utils/ApiResources.ts @@ -7,6 +7,7 @@ export const JSON_CONFIG = 'json_properties' export const SETTINGS = 'settings' export const LICENSE = 'license' export const LDAP = 'ldap' +export const BASIC = 'basic' export const SQL = 'sql' export const COUCHBASE = 'couchbase' export const CACHE = 'cache' diff --git a/admin-ui/plugins/auth-server/components/Agama/AgamaAliasListPage.js b/admin-ui/plugins/auth-server/components/Agama/AgamaAliasListPage.js index cf6157ad34..d0e1a81d7b 100644 --- a/admin-ui/plugins/auth-server/components/Agama/AgamaAliasListPage.js +++ b/admin-ui/plugins/auth-server/components/Agama/AgamaAliasListPage.js @@ -8,6 +8,7 @@ import { useCedarling } from '@/cedarling' import GluuViewWrapper from 'Routes/Apps/Gluu/GluuViewWrapper' import MaterialTable from '@material-table/core' import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap' +import GluuDialog from 'Routes/Apps/Gluu/GluuDialog' import CircularProgress from '@mui/material/CircularProgress' import { ThemeContext } from 'Context/theme/themeContext' import { useFormik } from 'formik' @@ -18,6 +19,10 @@ import TablePagination from '@mui/material/TablePagination' import Paper from '@mui/material/Paper' import { getJsonConfig, patchJsonConfig } from 'Plugins/auth-server/redux/features/jsonConfigSlice' import customColors from '@/customColors' +import { AGAMA_ALIAS_STRINGS } from './helper/constants' +import { AgamaAliasDetailRow } from './helper/util' +import GluuCommitDialog from '@/routes/Apps/Gluu/GluuCommitDialog' +import SetTitle from '@/utils/SetTitle' function AliasesListPage() { const { hasCedarPermission, authorize } = useCedarling() @@ -35,16 +40,21 @@ function AliasesListPage() { mapping: '', }) + SetTitle('Aliases') + const { t } = useTranslation() const dispatch = useDispatch() + const [limit] = useState(10) const [listData, setListData] = useState([]) const [showAddModal, setShowAddModal] = useState(false) + const [showCommitDialog, setShowCommitDialog] = useState(false) const [pageNumber] = useState(0) const [isEdit, setIsEdit] = useState(false) const [selectedRow, setSelectedRow] = useState(null) const [myActions, setMyActions] = useState([]) + const [showDeleteDialog, setShowDeleteDialog] = useState(false) + const [rowToDelete, setRowToDelete] = useState(null) - // Permission initialization useEffect(() => { const authorizePermissions = async () => { const permissions = [SCOPE_READ, SCOPE_WRITE] @@ -61,14 +71,24 @@ function AliasesListPage() { dispatch(getJsonConfig({ action: {} })) }, [dispatch]) - // Build actions based on permissions + const handleEdit = useCallback( + (rowData) => { + setIsEdit(true) + formik.setFieldValue('source', rowData.source) + formik.setFieldValue('mapping', rowData.mapping) + setSelectedRow(rowData) + setShowAddModal(true) + }, + [formik], + ) + useEffect(() => { const actions = [] if (hasCedarPermission(SCOPE_WRITE)) { actions.push({ icon: 'add', - tooltip: `${t('actions.add_mapping')}`, + tooltip: t(AGAMA_ALIAS_STRINGS.actions.add_mapping), iconProps: { color: 'primary', style: { color: customColors.lightBlue } }, isFreeAction: true, onClick: () => { @@ -78,18 +98,36 @@ function AliasesListPage() { }, }) - actions.push(() => ({ + actions.push((_rowData) => ({ icon: 'edit', - iconProps: { - style: { color: customColors.darkGray }, - }, - tooltip: `${t('messages.edit_acr')}`, + iconProps: { style: { color: customColors.darkGray } }, + tooltip: t(AGAMA_ALIAS_STRINGS.actions.edit), onClick: (event, rowData) => handleEdit(rowData), })) + + actions.push((_rowData) => ({ + icon: 'delete_outline', + iconProps: { style: { color: customColors.red } }, + tooltip: t(AGAMA_ALIAS_STRINGS.actions.delete), + onClick: (event, rowData) => { + if (!hasCedarPermission(SCOPE_WRITE)) return + setRowToDelete(rowData) + setShowDeleteDialog(true) + }, + })) } setMyActions(actions) - }, [cedarPermissions]) + }, [ + cedarPermissions, + hasCedarPermission, + formik, + setIsEdit, + setShowAddModal, + handleEdit, + setRowToDelete, + setShowDeleteDialog, + ]) const validationSchema = Yup.object().shape({ source: Yup.string().required(`${t('fields.source')} is Required!`), @@ -107,16 +145,39 @@ function AliasesListPage() { }, }) - const handleSubmit = useCallback( - (values) => { + const handleSubmit = useCallback(() => { + setShowCommitDialog(true) + }, []) + + const handleDeleteAccept = (userMessage) => { + if (!rowToDelete) return + const userAction = {} + const postBody = {} + const value = { ...configuration?.acrMappings } + delete value[rowToDelete.mapping] + postBody['requestBody'] = [ + { + path: '/acrMappings', + value: value, + op: configuration?.acrMappings ? 'replace' : 'add', + }, + ] + buildPayload(userAction, userMessage, postBody) + dispatch(patchJsonConfig({ action: userAction })) + setShowDeleteDialog(false) + setRowToDelete(null) + } + + const handleCommitAccept = useCallback( + (userMessage) => { const userAction = {} const postBody = {} - let value = configuration.acrMappings + let value = { ...configuration.acrMappings } if (isEdit) { delete value[selectedRow.mapping] } - value = { ...value, [values.mapping]: values.source } + value = { ...value, [formik.values.mapping]: formik.values.source } postBody['requestBody'] = [ { path: '/acrMappings', @@ -125,22 +186,12 @@ function AliasesListPage() { }, ] - buildPayload(userAction, 'changes', postBody) + buildPayload(userAction, userMessage, postBody) dispatch(patchJsonConfig({ action: userAction })) setShowAddModal(false) + setShowCommitDialog(false) }, - [configuration, isEdit, selectedRow, dispatch], - ) - - const handleEdit = useCallback( - (rowData) => { - setIsEdit(true) - formik.setFieldValue('source', rowData.source) - formik.setFieldValue('mapping', rowData.mapping) - setSelectedRow(rowData) - setShowAddModal(true) - }, - [formik], + [configuration, isEdit, selectedRow, dispatch, formik.values], ) useEffect(() => { @@ -159,143 +210,130 @@ function AliasesListPage() { return ( <> - <> - - , - Pagination: () => ( - {}} - rowsPerPage={10} - onRowsPerPageChange={() => {}} + + , + Pagination: () => ( + {}} + rowsPerPage={10} + onRowsPerPageChange={() => {}} + /> + ), + DetailPanel: (rowData) => ( + + ), + }} + columns={AGAMA_ALIAS_STRINGS.fields.columns} + data={listData} + isLoading={loading} + title="" + actions={myActions} + options={{ + columnsButton: false, + search: false, + pageSize: limit, + rowStyle: (rowData) => ({ + backgroundColor: rowData.enabled ? customColors.lightGreen : customColors.white, + }), + headerStyle: { + ...applicationStyle.tableHeaderStyle, + ...bgThemeColor, + }, + actionsColumnIndex: -1, + }} + /> + + + setShowCommitDialog(false)} + modal={showCommitDialog} + onAccept={handleCommitAccept} + /> +
{ + event.preventDefault() + formik.handleSubmit(event) + }} + className="mt-4" + > + + {isEdit + ? t(AGAMA_ALIAS_STRINGS.titles.edit_alias) + : t(AGAMA_ALIAS_STRINGS.titles.add_alias)} + + + + + - ), - }} - columns={[ - { - title: `${t('fields.mapping')}`, - field: 'mapping', - }, - { - title: `${t('fields.source')}`, - field: 'source', - }, - ]} - data={listData} - isLoading={loading} - title="" - actions={myActions} - paging={false} - options={{ - search: false, - pagination: false, - - rowStyle: (rowData) => ({ - backgroundColor: rowData.enabled ? customColors.lightGreen : customColors.white, - }), - headerStyle: { - ...applicationStyle.tableHeaderStyle, - ...bgThemeColor, - }, - actionsColumnIndex: -1, - }} - editable={{ - isDeleteHidden: () => !hasCedarPermission(SCOPE_WRITE), - onRowDelete: (oldData) => { - try { - return new Promise((resolve) => { - const userAction = {} - const postBody = {} - - const value = { ...configuration?.acrMappings } - delete value[oldData.mapping] - - postBody['requestBody'] = [ - { - path: '/acrMappings', - value: value, - op: configuration?.acrMappings ? 'replace' : 'add', - }, - ] - - buildPayload(userAction, 'changes', postBody) - dispatch(patchJsonConfig({ action: userAction })) - resolve(true) - }) - } catch (error) { - console.error('Error deleting row:', error) - } - }, - }} - /> - - - { - event.preventDefault() - formik.handleSubmit(event) - }} - className="mt-4" - > - {isEdit ? t('titles.edit_alias') : t('titles.add_alias')} - - - - - - - - - - - - -   - - - - - + + + + + +
+ + +   + + + +
+ setShowDeleteDialog(false)} + modal={showDeleteDialog} + subject="agama-alias" + onAccept={(userMessage) => { + handleDeleteAccept(userMessage) + }} + feature={'agama_alias_delete'} + /> ) } diff --git a/admin-ui/plugins/auth-server/components/Agama/AgamaListPage.js b/admin-ui/plugins/auth-server/components/Agama/AgamaListPage.js index a71ec5bcfd..cc6ed2ffb6 100644 --- a/admin-ui/plugins/auth-server/components/Agama/AgamaListPage.js +++ b/admin-ui/plugins/auth-server/components/Agama/AgamaListPage.js @@ -36,6 +36,7 @@ import FormLabel from '@mui/material/FormLabel' import GluuTabs from 'Routes/Apps/Gluu/GluuTabs' import { toast } from 'react-toastify' import customColors from '@/customColors' +import { Box, Typography } from '@mui/material' const dateTimeFormatOptions = { year: '2-digit', @@ -226,7 +227,6 @@ function AgamaListPage() { const agamaList = useSelector((state) => state.agamaReducer.agamaList) SetTitle(t('titles.agama')) - useEffect(() => { dispatch(getAgama()) }, []) @@ -491,83 +491,66 @@ function AgamaListPage() { case t('menus.add_community_project'): return ( <> - + - - {t('titles.select_project_deploy')} - - -
- {fileLoading ? ( - - ) : agamaRepostoriesList?.projects?.length ? ( - agamaRepostoriesList?.projects?.map((item) => ( - - setRepoName( - repoName === item['repository-name'] - ? null - : item['repository-name'], - ) - } - sx={{ - transform: 'scale(1.5)', - paddingTop: '6px', - }} - /> - } - label={ -
-
{item['repository-name']}
-
- {item.description} -
-
- } - sx={{ - alignItems: 'flex-start', - marginBottom: '16px', - }} - /> - )) - ) : ( -
+ {fileLoading ? ( + + ) : ( + {t('messages.no_data_found')} + )} + + ) : ( + <> + + {t('titles.select_project_deploy')} + + + - {t('messages.no_data_found')} -
- )} -
+ {agamaRepostoriesList.projects.map((item) => { + const repo = item['repository-name'] + const isSelected = repoName === repo + + return ( + setRepoName(isSelected ? null : repo)} + sx={{ transform: 'scale(1.5)', pt: 0.75 }} + /> + } + label={ + + {repo} + {item.description && ( + + {item.description} + + )} + + } + /> + ) + })} + + + )}
+ + )} + + + + ) +} + +export default DefaultAcr diff --git a/admin-ui/plugins/auth-server/components/AuthN/LdapAddPage.js b/admin-ui/plugins/auth-server/components/AuthN/LdapAddPage.js new file mode 100644 index 0000000000..bc7ba569ec --- /dev/null +++ b/admin-ui/plugins/auth-server/components/AuthN/LdapAddPage.js @@ -0,0 +1,45 @@ +import React from 'react' +import { useSelector, useDispatch } from 'react-redux' +import { useNavigate } from 'react-router-dom' +import { Card, CardBody } from 'Components' +import GluuLoader from 'Routes/Apps/Gluu/GluuLoader' +import GluuAlert from 'Routes/Apps/Gluu/GluuAlert' +import { useTranslation } from 'react-i18next' +import applicationStyle from 'Routes/Apps/Gluu/styles/applicationstyle' +import LdapForm from './LdapForm' +import { useLocation } from 'react-router-dom' +import { ldapFormInitialState } from 'Plugins/auth-server/helper/utils' + +function LdapAddPage() { + const { t } = useTranslation() + const navigate = useNavigate() + const dispatch = useDispatch() + const location = useLocation() + + const { loading, saveStatus = 'idle', item } = useSelector((state) => state.authNLdap) + const isEdit = Boolean(location.state?.isEdit) + + const ldapConfig = React.useMemo(() => ldapFormInitialState(isEdit, item), [isEdit, item]) + + const handleSuccessApply = React.useCallback(() => { + dispatch({ type: 'authNLdap/getLdapList' }) + navigate('/auth-server/authn') + }, [dispatch, navigate]) + + return ( + + + + + + + + + ) +} + +export default LdapAddPage diff --git a/admin-ui/plugins/auth-server/components/AuthN/LdapForm.js b/admin-ui/plugins/auth-server/components/AuthN/LdapForm.js new file mode 100644 index 0000000000..4029bae508 --- /dev/null +++ b/admin-ui/plugins/auth-server/components/AuthN/LdapForm.js @@ -0,0 +1,222 @@ +import React, { useState, useCallback } from 'react' +import { useFormik } from 'formik' +import { Form, FormGroup } from 'Components' +import GluuInputRow from 'Routes/Apps/Gluu/GluuInputRow' +import GluuToogleRow from 'Routes/Apps/Gluu/GluuToogleRow' +import GluuCommitFooter from 'Routes/Apps/Gluu/GluuCommitFooter' +import GluuCommitDialog from 'Routes/Apps/Gluu/GluuCommitDialog' +import { useDispatch } from 'react-redux' +import { useTranslation } from 'react-i18next' +import { buildLdapPayload } from '../../helper' +import { getLdapValidationSchema } from '../../helper/validations' +import { STRINGS, ACTIONS, FEATURES } from '../../helper/constants' + +function LdapForm({ ldapConfig: initialValues, isEdit, onSuccessApply }) { + const [modal, setModal] = useState(false) + const { t } = useTranslation() + const formik = useFormik({ + initialValues, + validationSchema: getLdapValidationSchema(t), + onSubmit: ({ setSubmitting }) => { + setModal(true) + setSubmitting(false) + }, + }) + + const dispatch = useDispatch() + const handleDialogAccept = useCallback( + (userMessage) => { + const payload = buildLdapPayload(formik.values, userMessage) + dispatch({ type: isEdit ? ACTIONS.EDIT_LDAP : ACTIONS.ADD_LDAP, payload, onSuccessApply }) + setModal(false) + }, + [formik.values, isEdit, dispatch, onSuccessApply], + ) + + return ( + <> +
+ + + + + formik.setFieldValue('defaultAuthnMethod', !formik.values.defaultAuthnMethod) + } + /> + + + + + { + const arr = e.target.value + .split(',') + .map((s) => s.trim()) + .filter(Boolean) + formik.setFieldValue('servers', arr.length ? arr : ['']) + }} + onBlur={formik.handleBlur} + required + placeholder={STRINGS.authn.ldap.placeholders.remote_ldap_server} + showError={Boolean(formik.touched.servers && formik.errors.servers)} + errorMessage={ + Array.isArray(formik.errors.servers) + ? formik.errors.servers.join(', ') + : formik.errors.servers + } + /> + { + const arr = e.target.value + .split(',') + .map((s) => s.trim()) + .filter(Boolean) + formik.setFieldValue('baseDNs', arr.length ? arr : ['']) + }} + onBlur={formik.handleBlur} + required + placeholder={STRINGS.authn.ldap.placeholders.base_dns} + showError={Boolean(formik.touched.baseDNs && formik.errors.baseDNs)} + errorMessage={ + Array.isArray(formik.errors.baseDNs) + ? formik.errors.baseDNs.join(', ') + : formik.errors.baseDNs + } + /> + + + formik.setFieldValue('useSSL', !formik.values.useSSL)} + /> + + + formik.setFieldValue('enabled', !formik.values.enabled)} + /> + + + + setModal(false)} + modal={modal} + onAccept={handleDialogAccept} + formik={formik} + placeholderLabel={t(STRINGS.authn.ldap.placeholders.action_commit_message)} + inputType="textarea" + feature={FEATURES.LDAP_EDIT} + operations={[]} + isLicenseLabel={false} + /> + + ) +} + +export default LdapForm diff --git a/admin-ui/plugins/auth-server/components/AuthN/LdapListingPage.js b/admin-ui/plugins/auth-server/components/AuthN/LdapListingPage.js new file mode 100644 index 0000000000..5116ffd5fe --- /dev/null +++ b/admin-ui/plugins/auth-server/components/AuthN/LdapListingPage.js @@ -0,0 +1,226 @@ +import React, { useState, useEffect, useContext, useCallback } from 'react' +import MaterialTable from '@material-table/core' +import { Paper } from '@mui/material' +import { useDispatch, useSelector } from 'react-redux' +import applicationStyle from 'Routes/Apps/Gluu/styles/applicationstyle' +import { useTranslation } from 'react-i18next' +import { useCedarling } from '@/cedarling' +import { ThemeContext } from '@/context/theme/themeContext' +import getThemeColor from '@/context/theme/config' +import { getLdapList, setCurrentItem, deleteLdap } from '../../redux/features/authNLdapSlice' +import { useNavigate } from 'react-router-dom' +import customColors from '@/customColors' +import { LDAP_READ, LDAP_WRITE, LDAP_DELETE } from 'Utils/PermChecker' +import { STRINGS } from '../../helper/constants' +import GluuFormDetailRow from 'Routes/Apps/Gluu/GluuFormDetailRow' +import { Container, Row, Col } from 'Components' +import GluuViewWrapper from 'Routes/Apps/Gluu/GluuViewWrapper' +import GluuDialog from 'Routes/Apps/Gluu/GluuDialog' +import SetTitle from '@/utils/SetTitle' + +function LdapListingPage() { + const dispatch = useDispatch() + const { t } = useTranslation() + const { hasCedarPermission, authorize } = useCedarling() + + const [limit] = useState(10) + const theme = useContext(ThemeContext) + const selectedTheme = theme.state.theme + const themeColors = getThemeColor(selectedTheme) + const backgroundStyle = { backgroundColor: '#f5f5f5', padding: '20px' } + const bgThemeColor = { background: themeColors.background } + + const ldapListRaw = useSelector((state) => state.authNLdap.ldapList) + const loading = useSelector((state) => state.authNLdap.loading) + const [ldapList, setLdapList] = useState([]) + const [myActions, setMyActions] = useState([]) + const navigate = useNavigate() + + const [modal, setModal] = useState(false) + const [selectedRow, setSelectedRow] = useState(null) + const toggle = useCallback(() => setModal((m) => !m), []) + + SetTitle('LDAP Server') + + function LdapDetailRow({ label, value }) { + return ( + + + + + {label[1] && value[1] && ( + + + + )} + + ) + } + + useEffect(() => { + const initPermissions = async () => { + const ldapPerms = [LDAP_READ, LDAP_WRITE, LDAP_DELETE] + for (const permission of ldapPerms) { + await authorize([permission]) + } + } + initPermissions() + dispatch(getLdapList()) + }, [dispatch]) + + useEffect(() => { + const actions = [] + if (hasCedarPermission(LDAP_WRITE)) { + actions.push((rowData) => ({ + icon: 'edit', + iconProps: { id: 'editLdap' + rowData.configId }, + tooltip: `${t('actions.edit')}`, + onClick: () => { + dispatch(setCurrentItem({ item: rowData })) + navigate('/auth-server/authn/ldap/new', { + state: { isEdit: true }, + }) + }, + disabled: !hasCedarPermission(LDAP_WRITE), + })) + actions.push({ + icon: 'add', + tooltip: `${t('tooltips.add_ldap')}`, + iconProps: { color: 'primary', style: { color: customColors.lightBlue } }, + isFreeAction: true, + onClick: () => { + navigate('/auth-server/authn/ldap/new', { + state: { isEdit: false }, + }) + }, + disabled: !hasCedarPermission(LDAP_WRITE), + }) + } + if (hasCedarPermission(LDAP_DELETE)) { + actions.push((rowData) => ({ + icon: 'delete_outline', + iconProps: { + color: 'primary', + style: { + color: customColors.darkGray, + }, + id: 'deleteLdap' + rowData.configId, + }, + tooltip: `${t('actions.delete')}`, + onClick: (_event, rowData) => { + setSelectedRow(rowData) + setModal(true) + }, + disabled: !hasCedarPermission(LDAP_DELETE), + })) + } + setMyActions(actions) + }, [hasCedarPermission, t, dispatch, navigate]) + + useEffect(() => { + if (ldapListRaw && ldapListRaw.length > 0 && !loading) { + const processed = ldapListRaw.map((item) => ({ + ...item, + configId: item.configId, + bindDN: item.bindDN, + enabled: item.enabled, + })) + setLdapList(processed) + } else { + setLdapList([]) + } + }, [ldapListRaw, loading]) + + return ( + <> + + , + }} + columns={[ + { title: `ACR`, field: 'acrName' }, + { title: `Level`, field: 'level' }, + { title: `Bind DN`, field: 'bindDN' }, + { title: `Enabled`, field: 'enabled' }, + { title: `Remote Primary Key`, field: 'primaryKey' }, + ]} + data={ + loading + ? [] + : ldapList.map((item) => ({ + ...item, + acrName: item.configId, + level: item.level || 0, + })) + } + isLoading={loading} + title="" + actions={myActions} + options={{ + columnsButton: false, + search: false, + pageSize: limit, + headerStyle: { + ...applicationStyle.tableHeaderStyle, + ...bgThemeColor, + }, + actionsColumnIndex: -1, + }} + detailPanel={(rowData) => { + const row = rowData.rowData + return ( + + + + + + + + ) + }} + /> + + { + dispatch(deleteLdap({ configId: selectedRow?.configId, userMessage })) + setModal(false) + }} + feature={'ldap_delete'} + /> + + ) +} + +export default LdapListingPage diff --git a/admin-ui/plugins/auth-server/components/AuthN/ScriptsListPage.js b/admin-ui/plugins/auth-server/components/AuthN/ScriptsListPage.js new file mode 100644 index 0000000000..c672fcc7bd --- /dev/null +++ b/admin-ui/plugins/auth-server/components/AuthN/ScriptsListPage.js @@ -0,0 +1,131 @@ +import React, { useState, useEffect, useContext } from 'react' +import MaterialTable from '@material-table/core' +import { Paper } from '@mui/material' +import TablePagination from '@mui/material/TablePagination' +import { useSelector, useDispatch } from 'react-redux' +import { useCedarling } from '@/cedarling' +import GluuViewWrapper from 'Routes/Apps/Gluu/GluuViewWrapper' +import applicationStyle from 'Routes/Apps/Gluu/styles/applicationstyle' +import { useTranslation } from 'react-i18next' +import { SCOPE_READ } from 'Utils/PermChecker' +import SetTitle from 'Utils/SetTitle' +import { ThemeContext } from 'Context/theme/themeContext' +import getThemeColor from 'Context/theme/config' +import { getScripts } from 'Redux/features/initSlice' +import GluuFormDetailRow from 'Routes/Apps/Gluu/GluuFormDetailRow' +import { Container, Row, Col } from 'Components' +import customColors from '@/customColors' + +function ScriptsListPage() { + const { hasCedarPermission } = useCedarling() + const { t } = useTranslation() + const dispatch = useDispatch() + const [limit] = useState(10) + const theme = useContext(ThemeContext) + const selectedTheme = theme.state.theme + const themeColors = getThemeColor(selectedTheme) + const bgThemeColor = { background: themeColors.background } + const backgroundStyle = { backgroundColor: customColors.lightGray, padding: '20px' } + + const { scripts, loading: scriptsLoading } = useSelector((state) => state.initReducer) + + SetTitle('Scripts') + + function ScriptDetailRow({ label, value }) { + return ( + + + + + {label[1] && value[1] && ( + + + + )} + + ) + } + + SetTitle(t('titles.custom_scripts')) + + useEffect(() => { + if (hasCedarPermission(SCOPE_READ)) { + const userAction = {} + dispatch(getScripts({ action: userAction })) + } + }, [hasCedarPermission, dispatch]) + + const authScripts = scripts + .filter((script) => script?.scriptType === 'person_authentication' && script?.enabled) + .map((script) => ({ + ...script, + acrName: script?.name || 'N/A', + level: script.level || 0, + samlACR: script?.name || 'N/A', + })) + + console.log('Auth scripts:', authScripts) + + return ( + + , + Pagination: () => ( + {}} + rowsPerPage={10} + onRowsPerPageChange={() => {}} + /> + ), + }} + columns={[ + { title: `${t('fields.acr')}`, field: 'acrName' }, + { title: `${t('fields.saml_acr')}`, field: 'samlACR' }, + { title: `${t('fields.level')}`, field: 'level' }, + ]} + data={authScripts} + isLoading={scriptsLoading} + title="" + paging={false} + options={{ + columnsButton: false, + search: false, + pagination: false, + idSynonym: 'inum', + selection: false, + pageSize: limit, + headerStyle: { + ...applicationStyle.tableHeaderStyle, + ...bgThemeColor, + }, + actionsColumnIndex: -1, + }} + detailPanel={(rowData) => { + const row = rowData.rowData + return ( + + + + + + + ) + }} + /> + + ) +} + +export default ScriptsListPage diff --git a/admin-ui/plugins/auth-server/components/AuthN/helper/acrUtils.js b/admin-ui/plugins/auth-server/components/AuthN/helper/acrUtils.js new file mode 100644 index 0000000000..13ed6db1b9 --- /dev/null +++ b/admin-ui/plugins/auth-server/components/AuthN/helper/acrUtils.js @@ -0,0 +1,42 @@ +import { SIMPLE_PASSWORD_AUTH } from 'Plugins/auth-server/common/Constants' + +/** + * Build agama flows array from agama list + * Extracts individual flows that are not in noDirectLaunch and adds agama_ prefix + * Each flow becomes a separate entry + * @param {Array} agamaList - List of agama deployments + * @returns {Array} Array of qualified flow names + */ +export const buildAgamaFlowsArray = (agamaList) => { + const agamaFlows = [] + if (Array.isArray(agamaList)) { + agamaList.forEach((flow) => { + const configs = flow?.details?.projectMetadata?.configs + const noDirectLaunch = flow?.details?.projectMetadata?.noDirectLaunch || [] + + if (configs) { + Object.keys(configs).forEach((key) => { + if (!noDirectLaunch.includes(key)) { + const qualifiedName = `agama_${key}` + agamaFlows.push(qualifiedName) + } + }) + } + }) + } + return agamaFlows +} + +/** + * Build dropdown options array + * Combines scripts, SIMPLE_PASSWORD_AUTH, and individual agama flows into sorted array + * Each entry maps to itself (display name = value) + * @param {Array} filteredScripts - Filtered authentication scripts + * @param {Array} agamaFlows - Array of agama flows + * @returns {Array} Sorted array of dropdown options + */ +export const buildDropdownOptions = (filteredScripts, agamaFlows) => { + const scriptNames = filteredScripts.map((s) => s.key) + + return [...scriptNames, SIMPLE_PASSWORD_AUTH, ...agamaFlows].sort() +} diff --git a/admin-ui/plugins/auth-server/components/AuthN/index.js b/admin-ui/plugins/auth-server/components/AuthN/index.js index 7ad864712c..069a63e664 100644 --- a/admin-ui/plugins/auth-server/components/AuthN/index.js +++ b/admin-ui/plugins/auth-server/components/AuthN/index.js @@ -1,42 +1,40 @@ import React from 'react' -import AuthNListPage from './AuthNListPage' -import { useTranslation } from 'react-i18next' import GluuTabs from 'Routes/Apps/Gluu/GluuTabs' import { Card } from 'Components' import applicationStyle from 'Routes/Apps/Gluu/styles/applicationstyle' - import AgamaListPage from '../Agama/AgamaListPage' import AliasesListPage from '../Agama/AgamaAliasListPage' +import ScriptsListPage from './ScriptsListPage' +import LdapListingPage from './LdapListingPage' +import Basic from './Basic' +import DefaultAcr from './DefaultAcr' function AuthNPage() { - const { t } = useTranslation() - const tabNames = [ - { - name: t('menus.builtIn'), - path: '', - }, - { name: t('menus.acrs'), path: '' }, - { - name: t('menus.aliases'), - path: '', - }, - { - name: t('menus.agama_flows'), - path: '', - }, + { name: 'default acr', path: '' }, + { name: 'basic', path: '' }, + { name: 'ldap servers', path: '' }, + { name: 'scripts', path: '' }, + { name: 'aliases', path: '' }, + { name: 'agama flows', path: '' }, ] const tabToShow = (tabName) => { switch (tabName) { - case t('menus.builtIn'): - return - case t('menus.acrs'): - return - case t('menus.aliases'): + case 'default acr': + return + case 'basic': + return + case 'ldap servers': + return + case 'scripts': + return + case 'aliases': return - case t('menus.agama_flows'): + case 'agama flows': return + default: + return } } diff --git a/admin-ui/plugins/auth-server/components/Configuration/DefaultAcrInput.js b/admin-ui/plugins/auth-server/components/Configuration/DefaultAcrInput.js index 4c1e23899b..54dbc7809a 100644 --- a/admin-ui/plugins/auth-server/components/Configuration/DefaultAcrInput.js +++ b/admin-ui/plugins/auth-server/components/Configuration/DefaultAcrInput.js @@ -16,6 +16,7 @@ function DefaultAcrInput({ handler, options, path, + showSaveButtons = true, }) { const { t } = useTranslation() const theme = useContext(ThemeContext) @@ -33,6 +34,15 @@ function DefaultAcrInput({ const onValueChanged = (data) => { setShow(true) setData(data) + + if (!showSaveButtons && data) { + const put = {} + put[PATH] = path + put[VALUE] = isArray ? (Array.isArray(data) ? data : [data]) : data + put['op'] = 'replace' + handler(put) + setShow(false) + } } const onAccept = () => { const put = {} @@ -76,7 +86,9 @@ function DefaultAcrInput({ > {options.map((item, key) => ( - + ))} @@ -84,7 +96,7 @@ function DefaultAcrInput({ - {show && ( + {show && showSaveButtons && ( <>