diff --git a/internal/dataprovider/configs.go b/internal/dataprovider/configs.go index 74862700..dae19cba 100644 --- a/internal/dataprovider/configs.go +++ b/internal/dataprovider/configs.go @@ -197,19 +197,19 @@ func (c *SMTPOAuth2) validate() error { if c.ClientID == "" { return util.NewI18nError( util.NewValidationError("smtp oauth2: client id is required"), - util.I18nErrorSMTPClientIDRequired, + util.I18nErrorClientIDRequired, ) } - if c.ClientSecret == nil { + if c.ClientSecret == nil || c.ClientSecret.IsEmpty() { return util.NewI18nError( util.NewValidationError("smtp oauth2: client secret is required"), - util.I18nErrorSMTPClientSecretRequired, + util.I18nErrorClientSecretRequired, ) } - if c.RefreshToken == nil { + if c.RefreshToken == nil || c.RefreshToken.IsEmpty() { return util.NewI18nError( util.NewValidationError("smtp oauth2: refresh token is required"), - util.I18nErrorSMTPRefreshTokenRequired, + util.I18nErrorRefreshTokenRequired, ) } if err := validateSMTPSecret(c.ClientSecret, "oauth2 client secret"); err != nil { diff --git a/internal/httpd/httpd_test.go b/internal/httpd/httpd_test.go index 77f6a267..f2a1085e 100644 --- a/internal/httpd/httpd_test.go +++ b/internal/httpd/httpd_test.go @@ -26685,6 +26685,7 @@ func startOIDCMockServer() { fmt.Fprintf(w, "OK\n") }) http.HandleFunc("/auth/realms/sftpgo/.well-known/openid-configuration", func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{"issuer":"http://127.0.0.1:11111/auth/realms/sftpgo","authorization_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/auth","token_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/token","introspection_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/token/introspect","userinfo_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/userinfo","end_session_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/logout","frontchannel_logout_session_supported":true,"frontchannel_logout_supported":true,"jwks_uri":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/certs","check_session_iframe":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/login-status-iframe.html","grant_types_supported":["authorization_code","implicit","refresh_token","password","client_credentials","urn:ietf:params:oauth:grant-type:device_code","urn:openid:params:grant-type:ciba"],"response_types_supported":["code","none","id_token","token","id_token token","code id_token","code token","code id_token token"],"subject_types_supported":["public","pairwise"],"id_token_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"id_token_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"id_token_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"userinfo_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512","none"],"request_object_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512","none"],"request_object_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"request_object_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"response_modes_supported":["query","fragment","form_post","query.jwt","fragment.jwt","form_post.jwt","jwt"],"registration_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/clients-registrations/openid-connect","token_endpoint_auth_methods_supported":["private_key_jwt","client_secret_basic","client_secret_post","tls_client_auth","client_secret_jwt"],"token_endpoint_auth_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"introspection_endpoint_auth_methods_supported":["private_key_jwt","client_secret_basic","client_secret_post","tls_client_auth","client_secret_jwt"],"introspection_endpoint_auth_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"authorization_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"authorization_encryption_alg_values_supported":["RSA-OAEP","RSA-OAEP-256","RSA1_5"],"authorization_encryption_enc_values_supported":["A256GCM","A192GCM","A128GCM","A128CBC-HS256","A192CBC-HS384","A256CBC-HS512"],"claims_supported":["aud","sub","iss","auth_time","name","given_name","family_name","preferred_username","email","acr"],"claim_types_supported":["normal"],"claims_parameter_supported":true,"scopes_supported":["openid","phone","email","web-origins","offline_access","microprofile-jwt","profile","address","roles"],"request_parameter_supported":true,"request_uri_parameter_supported":true,"require_request_uri_registration":true,"code_challenge_methods_supported":["plain","S256"],"tls_client_certificate_bound_access_tokens":true,"revocation_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/revoke","revocation_endpoint_auth_methods_supported":["private_key_jwt","client_secret_basic","client_secret_post","tls_client_auth","client_secret_jwt"],"revocation_endpoint_auth_signing_alg_values_supported":["PS384","ES384","RS384","HS256","HS512","ES256","RS256","HS384","ES512","PS256","PS512","RS512"],"backchannel_logout_supported":true,"backchannel_logout_session_supported":true,"device_authorization_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/auth/device","backchannel_token_delivery_modes_supported":["poll","ping"],"backchannel_authentication_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/ext/ciba/auth","backchannel_authentication_request_signing_alg_values_supported":["PS384","ES384","RS384","ES256","RS256","ES512","PS256","PS512","RS512"],"require_pushed_authorization_requests":false,"pushed_authorization_request_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/ext/par/request","mtls_endpoint_aliases":{"token_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/token","revocation_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/revoke","introspection_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/token/introspect","device_authorization_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/auth/device","registration_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/clients-registrations/openid-connect","userinfo_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/userinfo","pushed_authorization_request_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/ext/par/request","backchannel_authentication_endpoint":"http://127.0.0.1:11111/auth/realms/sftpgo/protocol/openid-connect/ext/ciba/auth"}}`) }) http.HandleFunc("/404", func(w http.ResponseWriter, _ *http.Request) { diff --git a/internal/httpd/webadmin.go b/internal/httpd/webadmin.go index c71e1f5e..00d8deaf 100644 --- a/internal/httpd/webadmin.go +++ b/internal/httpd/webadmin.go @@ -4361,12 +4361,12 @@ func (s *httpdServer) handleWebConfigsPost(w http.ResponseWriter, r *http.Reques case "branding_submit": configSection = 4 brandingConfigs, err := getBrandingConfigFromPostFields(r, configs.Branding) + configs.Branding = brandingConfigs if err != nil { logger.Info(logSender, "", "unable to get branding config: %v", err) s.renderConfigsPage(w, r, configs, err, configSection) return } - configs.Branding = brandingConfigs default: s.renderBadRequestPage(w, r, errors.New("unsupported form action")) return @@ -4445,6 +4445,9 @@ func (s *httpdServer) handleOAuth2TokenRedirect(w http.ResponseWriter, r *http.R } func updateSMTPSecrets(newConfigs, currentConfigs *dataprovider.SMTPConfigs) { + if currentConfigs == nil { + currentConfigs = &dataprovider.SMTPConfigs{} + } if newConfigs.Password.IsNotPlainAndNotEmpty() { newConfigs.Password = currentConfigs.Password } diff --git a/internal/util/i18n.go b/internal/util/i18n.go index a3cb927e..9475963a 100644 --- a/internal/util/i18n.go +++ b/internal/util/i18n.go @@ -240,9 +240,9 @@ const ( I18nErrorRestore = "maintenance.restore_error" I18nErrorACMEGeneric = "acme.generic_error" I18nErrorSMTPRequiredFields = "smtp.err_required_fields" - I18nErrorSMTPClientIDRequired = "smtp.client_id_required" - I18nErrorSMTPClientSecretRequired = "smtp.client_secret_required" - I18nErrorSMTPRefreshTokenRequired = "smtp.refresh_token_required" + I18nErrorClientIDRequired = "oauth2.client_id_required" + I18nErrorClientSecretRequired = "oauth2.client_secret_required" + I18nErrorRefreshTokenRequired = "oauth2.refresh_token_required" I18nErrorURLRequired = "actions.http_url_required" I18nErrorURLInvalid = "actions.http_url_invalid" I18nErrorHTTPPartNameRequired = "actions.http_part_name_required" diff --git a/static/locales/en/translation.json b/static/locales/en/translation.json index 225c8880..a263165c 100644 --- a/static/locales/en/translation.json +++ b/static/locales/en/translation.json @@ -672,7 +672,26 @@ "token_invalid": "Invalid OpenID token", "role_admin_err": "Incorrect OpenID role, logged in user is not an administrator", "role_user_err": "Incorrect OpenID role, logged in user is an administrator", - "get_user_err": "Failed to get user associated with OpenID token" + "get_user_err": "Failed to get user associated with OpenID token", + "title": "OpenID Connect", + "help": "From this section you can configure OpenID Connect integration with your Identity Provider. A service restart is required to apply the changes", + "client_id": "Client ID", + "client_secret": "Client Secret", + "config_url": "Config URL", + "config_url_help": "The \"/.well-known/openid-configuration\" suffix is automatically added. This URL must return the OpenID configuration", + "redirect_base_url": "Redirect base URL", + "username_field": "Username claim", + "username_field_help": "ID Token claim to use as username for SFTPGo users/admin, e.g. \"preferred_username\"", + "role_field": "Role claim", + "implicit_roles": "Implicit roles", + "scopes": "Scopes", + "scopes_help": "Comma separated scopes, openid scope is automatically added", + "custom_fields": "Custom claims", + "custom_fields_help": "Comma separated custom claims", + "config_url_required": "Config URL is required", + "config_fetch_error": "Unable to get OpenID configuration from the provided configuration URL", + "redirect_base_url_required": "Redirect base URL is required", + "username_field_required": "Username claim is required" }, "oauth2": { "auth_verify_error": "Unable to verify OAuth2 code", @@ -680,7 +699,10 @@ "auth_invalid": "Invalid OAuth2 code", "token_exchange_err": "Unable to get OAuth2 token from authorization code", "no_refresh_token": "The OAuth2 provider returned an empty token. Some providers only return the token when the user first authorizes. If you have already registered SFTPGo with this user in the past, revoke access and try again. This way you will invalidate the previous token", - "success": "Copy the following string, without the quotes, into SMTP OAuth2 Token configuration field:" + "success": "Copy the following string, without the quotes, into SMTP OAuth2 Token configuration field:", + "client_id_required": "Client ID is required", + "client_secret_required": "Client Secret is required", + "refresh_token_required": "Refresh Token is required" }, "filters": { "password_strength": "Password strength", @@ -858,9 +880,6 @@ "smtp": { "title": "SMTP", "err_required_fields": "From address and Username cannot be both empty", - "client_id_required": "Client ID is required", - "client_secret_required": "Client Secret is required", - "refresh_token_required": "Refresh Token is required", "help": "Set the SMTP configuration replacing the one defined using env vars or config file if any", "host": "Server name", "host_help": "If blank the configuration is disabled", diff --git a/static/locales/it/translation.json b/static/locales/it/translation.json index d7fbd70f..07d78b20 100644 --- a/static/locales/it/translation.json +++ b/static/locales/it/translation.json @@ -672,7 +672,26 @@ "token_invalid": "Token OpenID non valido", "role_admin_err": "Ruolo OpenID errato, l'utente che ha effettuato l'accesso non è un amministratore", "role_user_err": "Ruolo OpenID errato, l'utente che ha effettuato l'accesso è un amministratore", - "get_user_err": "Impossibile ottenere l'utente associato al token OpenID" + "get_user_err": "Impossibile ottenere l'utente associato al token OpenID", + "title": "OpenID Connect", + "help": "Da questa sezione puoi configurare l'integrazione OpenID Connect con il tuo Identity Provider. È necessario un riavvio del servizio per applicare le modifiche", + "client_id": "Client ID", + "client_secret": "Client Secret", + "config_url": "URL configurazione", + "config_url_help": "Il suffisso \"/.well-known/openid-configuration\" è aggiunto automaticamente. Questo URL deve tornare la configurazione per OpenID", + "redirect_base_url": "URL di reindirizzamento", + "username_field": "Claim per nome utente", + "username_field_help": "Il claim dell'ID Token da utilizzare come nome per utenti/amministratori SFTPGo, ad es. \"preferred_username\"", + "role_field": "Claim per ruolo", + "implicit_roles": "Ruoli impliciti", + "scopes": "Scopi", + "scopes_help": "Scopi separati da virgola, openid è aggiunto automaticamente", + "custom_fields": "Claim personalizzati", + "custom_fields_help": "Claim personalizzati separati da virgola", + "config_url_required": "L'URL configurazione è obbligatorio", + "config_fetch_error": "Impossibile ottenere la configurazione OpenID dall'URL di configurazione fornito", + "redirect_base_url_required": "L'URL di reindirizzamento è obbligatorio", + "username_field_required": "Il claim per il nome utente è obbligatorio" }, "oauth2": { "auth_verify_error": "Impossibile verificare il codice OAuth2", @@ -680,7 +699,10 @@ "auth_invalid": "Codice OAuth2 non valido", "token_exchange_err": "Impossibile ottenere il token OAuth2 dal codice di autorizzazione", "no_refresh_token": "Il provider OAuth2 ha restituito un token vuoto. Alcuni provider restituiscono il token solo dopo la prima autorizzazione dell'utente. Se hai già registrato SFTPGo con questo utente in passato, revoca l'accesso e riprova. In questo modo invaliderai il token precedente", - "success": "Copia la seguente stringa, senza virgolette, nel campo di configurazione del token SMTP OAuth2:" + "success": "Copia la seguente stringa, senza virgolette, nel campo di configurazione del token SMTP OAuth2:", + "client_id_required": "Il Client ID è obbligatorio", + "client_secret_required": "Il Client Secret è obbligatorio", + "refresh_token_required": "Il Refresh Token è obbligatorio" }, "filters": { "password_strength": "Sicurezza password", @@ -858,9 +880,6 @@ "smtp": { "title": "SMTP", "err_required_fields": "L'indirizzo del mittente e lo username non possono essere entrambi vuoti", - "client_id_required": "Il Client ID è obbligatorio", - "client_secret_required": "Il Client Secret è obbligatorio", - "refresh_token_required": "Il Refresh Token è obbligatorio", "help": "Imposta la configurazione SMTP sostituendo quella definita utilizzando env vars o il file di configurazione, se presente", "host": "Nome server", "host_help": "Se vuoto la configurazione è disabilitata", diff --git a/templates/webadmin/configs.html b/templates/webadmin/configs.html index 2ad3b9fa..6ddcf269 100644 --- a/templates/webadmin/configs.html +++ b/templates/webadmin/configs.html @@ -626,7 +626,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com). let clientSecret = $('#idSMTPOAuth2ClientSecret').val(); if (!clientID){ ModalAlert.fire({ - text: $.t('smtp.client_id_required'), + text: $.t('oauth2.client_id_required'), icon: "warning", confirmButtonText: $.t('general.ok'), customClass: { @@ -637,7 +637,7 @@ explicit grant from the SFTPGo Team (support@sftpgo.com). } if (!clientSecret){ ModalAlert.fire({ - text: $.t('smtp.client_secret_required'), + text: $.t('oauth2.client_secret_required'), icon: "warning", confirmButtonText: $.t('general.ok'), customClass: { @@ -723,13 +723,13 @@ explicit grant from the SFTPGo Team (support@sftpgo.com). if (authType === 3){ let message; if (!clientID){ - message = "smtp.client_id_required"; + message = "oauth2.client_id_required"; } if (!clientSecret){ - message = "smtp.client_secret_required"; + message = "oauth2.client_secret_required"; } if (!refreshToken){ - message = "smtp.refresh_token_required" + message = "oauth2.refresh_token_required" } if (message){ ModalAlert.fire({