From 61b873451f140ddce2e539315bad287e06ff73a1 Mon Sep 17 00:00:00 2001 From: Krzysztof Jagosz Date: Tue, 29 Apr 2025 01:05:48 +0200 Subject: [PATCH] Added OAuth2 support for SSO --- .gitignore | 6 + src/api.go | 1 + src/def.go | 2 + src/go.mod | 2 +- src/mod/auth/sso/authentik/authentik.go | 2 +- src/mod/auth/sso/oauth2/oauth2.go | 297 ++++++++++++++++++++++++ src/mod/dynamicproxy/authProviders.go | 10 + src/mod/dynamicproxy/typedef.go | 4 +- src/mod/sshprox/embed.go | 8 +- src/reverseproxy.go | 3 +- src/start.go | 6 + src/web/components/httprp.html | 8 +- src/web/components/sso.html | 140 ++++++++--- src/web/index.html | 2 +- 14 files changed, 454 insertions(+), 37 deletions(-) create mode 100644 src/mod/auth/sso/oauth2/oauth2.go diff --git a/.gitignore b/.gitignore index 5c9767d..fabfcb3 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,9 @@ src/log/ example/plugins/ztnc/ztnc.db example/plugins/ztnc/authtoken.secret example/plugins/ztnc/ztnc.db.lock +.idea +conf +log +tmp +sys.* +www/html/index.html diff --git a/src/api.go b/src/api.go index 01adf20..a997737 100644 --- a/src/api.go +++ b/src/api.go @@ -84,6 +84,7 @@ func RegisterTLSAPIs(authRouter *auth.RouterDef) { func RegisterAuthenticationHandlerAPIs(authRouter *auth.RouterDef) { authRouter.HandleFunc("/api/sso/Authelia", autheliaRouter.HandleSetAutheliaURLAndHTTPS) authRouter.HandleFunc("/api/sso/Authentik", authentikRouter.HandleSetAuthentikURLAndHTTPS) + authRouter.HandleFunc("/api/sso/OAuth2", oauth2Router.HandleSetOAuth2Settings) } // Register the APIs for redirection rules management functions diff --git a/src/def.go b/src/def.go index 7efd638..60aacdd 100644 --- a/src/def.go +++ b/src/def.go @@ -10,6 +10,7 @@ package main import ( "embed" "flag" + "imuslab.com/zoraxy/mod/auth/sso/oauth2" "net/http" "time" @@ -146,6 +147,7 @@ var ( //Authentication Provider autheliaRouter *authelia.AutheliaRouter //Authelia router for Authelia authentication authentikRouter *authentik.AuthentikRouter //Authentik router for Authentik authentication + oauth2Router *oauth2.OAuth2Router //OAuth2Router router for OAuth2Router authentication //Helper modules EmailSender *email.Sender //Email sender that handle email sending diff --git a/src/go.mod b/src/go.mod index e722aa9..3b0d5e4 100644 --- a/src/go.mod +++ b/src/go.mod @@ -16,6 +16,7 @@ require ( github.com/grandcat/zeroconf v1.0.0 github.com/likexian/whois v1.15.1 github.com/microcosm-cc/bluemonday v1.0.26 + github.com/monperrus/crawler-user-agents v1.1.0 github.com/shirou/gopsutil/v4 v4.25.1 github.com/syndtr/goleveldb v1.0.0 golang.org/x/net v0.33.0 @@ -32,7 +33,6 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.128 // indirect - github.com/monperrus/crawler-user-agents v1.1.0 // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/peterhellberg/link v1.2.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect diff --git a/src/mod/auth/sso/authentik/authentik.go b/src/mod/auth/sso/authentik/authentik.go index 795b0b3..a4abbc6 100644 --- a/src/mod/auth/sso/authentik/authentik.go +++ b/src/mod/auth/sso/authentik/authentik.go @@ -56,7 +56,7 @@ func (ar *AuthentikRouter) HandleSetAuthentikURLAndHTTPS(w http.ResponseWriter, return } - useHTTPS, err := utils.PostBool(r, "useHTTPS") + useHTTPS, err := utils.PostBool(r, "authentikUseHttps") if err != nil { useHTTPS = false } diff --git a/src/mod/auth/sso/oauth2/oauth2.go b/src/mod/auth/sso/oauth2/oauth2.go new file mode 100644 index 0000000..e036d6f --- /dev/null +++ b/src/mod/auth/sso/oauth2/oauth2.go @@ -0,0 +1,297 @@ +package oauth2 + +import ( + "context" + "encoding/json" + "errors" + "golang.org/x/oauth2" + "imuslab.com/zoraxy/mod/database" + "imuslab.com/zoraxy/mod/info/logger" + "imuslab.com/zoraxy/mod/utils" + "net/http" + "net/url" + "strings" +) + +type OAuth2RouterOptions struct { + OAuth2ServerURL string //The URL of the OAuth 2.0 server server + OAuth2TokenURL string //The URL of the OAuth 2.0 token server + OAuth2RedirectUrl string //The redirect URL of the OAuth 2.0 token server + OAuth2ClientId string //The client id for OAuth 2.0 Application + OAuth2ClientSecret string //The client secret for OAuth 2.0 Application + OAuth2WellKnownUrl string //The well-known url for OAuth 2.0 server + OAuth2UserInfoUrl string //The URL of the OAuth 2.0 user info endpoint + OAuth2Scopes string //The scopes for OAuth 2.0 Application + Logger *logger.Logger + Database *database.Database +} + +type OIDCDiscoveryDocument struct { + AuthorizationEndpoint string `json:"authorization_endpoint"` + ClaimsSupported []string `json:"claims_supported"` + CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"` + GrantTypesSupported []string `json:"grant_types_supported"` + IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"` + Issuer string `json:"issuer"` + JwksURI string `json:"jwks_uri"` + ResponseTypesSupported []string `json:"response_types_supported"` + ScopesSupported []string `json:"scopes_supported"` + SubjectTypesSupported []string `json:"subject_types_supported"` + TokenEndpoint string `json:"token_endpoint"` + TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"` + UserinfoEndpoint string `json:"userinfo_endpoint"` +} + +type OAuth2Router struct { + options *OAuth2RouterOptions +} + +// NewOAuth2Router creates a new OAuth2Router object +func NewOAuth2Router(options *OAuth2RouterOptions) *OAuth2Router { + options.Database.NewTable("oauth2") + + //Read settings from database, if exists + options.Database.Read("oauth2", "oauth2WellKnownUrl", &options.OAuth2WellKnownUrl) + options.Database.Read("oauth2", "oauth2ServerUrl", &options.OAuth2ServerURL) + options.Database.Read("oauth2", "oauth2TokenUrl", &options.OAuth2TokenURL) + options.Database.Read("oauth2", "oauth2ClientId", &options.OAuth2ClientId) + options.Database.Read("oauth2", "oauth2ClientSecret", &options.OAuth2ClientSecret) + options.Database.Read("oauth2", "oauth2RedirectURL", &options.OAuth2RedirectUrl) + options.Database.Read("oauth2", "oauth2UserInfoUrl", &options.OAuth2UserInfoUrl) + options.Database.Read("oauth2", "oauth2Scopes", &options.OAuth2Scopes) + + return &OAuth2Router{ + options: options, + } +} + +// HandleSetOAuth2Settings is the internal handler for setting the OAuth URL and HTTPS +func (ar *OAuth2Router) HandleSetOAuth2Settings(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet { + //Return the current settings + js, _ := json.Marshal(map[string]interface{}{ + "oauth2WellKnownUrl": ar.options.OAuth2WellKnownUrl, + "oauth2ServerUrl": ar.options.OAuth2ServerURL, + "oauth2TokenUrl": ar.options.OAuth2TokenURL, + "oauth2Scopes": ar.options.OAuth2Scopes, + "oauth2ClientSecret": ar.options.OAuth2ClientSecret, + "oauth2RedirectURL": ar.options.OAuth2RedirectUrl, + "oauth2UserInfoURL": ar.options.OAuth2UserInfoUrl, + "oauth2ClientId": ar.options.OAuth2ClientId, + }) + + utils.SendJSONResponse(w, string(js)) + return + } else if r.Method == http.MethodPost { + //Update the settings + var oauth2ServerUrl, oauth2TokenURL, oauth2Scopes, oauth2UserInfoUrl string + oauth2WellKnownUrl, err := utils.PostPara(r, "oauth2WellKnownUrl") + if err != nil { + oauth2ServerUrl, err = utils.PostPara(r, "oauth2ServerUrl") + if err != nil { + utils.SendErrorResponse(w, "oauth2ServerUrl not found") + return + } + + oauth2TokenURL, err = utils.PostPara(r, "oauth2TokenUrl") + if err != nil { + utils.SendErrorResponse(w, "oauth2TokenUrl not found") + return + } + + oauth2Scopes, err = utils.PostPara(r, "oauth2Scopes") + if err != nil { + utils.SendErrorResponse(w, "oauth2Scopes not found") + return + } + + oauth2UserInfoUrl, err = utils.PostPara(r, "oauth2UserInfoUrl") + if err != nil { + utils.SendErrorResponse(w, "oauth2UserInfoUrl not found") + return + } + } + + oauth2RedirectUrl, err := utils.PostPara(r, "oauth2RedirectUrl") + if err != nil { + utils.SendErrorResponse(w, "oauth2RedirectUrl not found") + return + } + + oauth2ClientId, err := utils.PostPara(r, "oauth2ClientId") + if err != nil { + utils.SendErrorResponse(w, "oauth2ClientId not found") + return + } + + oauth2ClientSecret, err := utils.PostPara(r, "oauth2ClientSecret") + if err != nil { + utils.SendErrorResponse(w, "oauth2ClientSecret not found") + return + } + + //Write changes to runtime + ar.options.OAuth2WellKnownUrl = oauth2WellKnownUrl + ar.options.OAuth2ServerURL = oauth2ServerUrl + ar.options.OAuth2TokenURL = oauth2TokenURL + ar.options.OAuth2RedirectUrl = oauth2RedirectUrl + ar.options.OAuth2UserInfoUrl = oauth2UserInfoUrl + ar.options.OAuth2ClientId = oauth2ClientId + ar.options.OAuth2ClientSecret = oauth2ClientSecret + ar.options.OAuth2Scopes = oauth2Scopes + + //Write changes to database + ar.options.Database.Write("oauth2", "oauth2WellKnownUrl", oauth2WellKnownUrl) + ar.options.Database.Write("oauth2", "oauth2ServerUrl", oauth2ServerUrl) + ar.options.Database.Write("oauth2", "oauth2TokenUrl", oauth2TokenURL) + ar.options.Database.Write("oauth2", "oauth2RedirectUrl", oauth2RedirectUrl) + ar.options.Database.Write("oauth2", "oauth2UserInfoUrl", oauth2UserInfoUrl) + ar.options.Database.Write("oauth2", "oauth2ClientId", oauth2ClientId) + ar.options.Database.Write("oauth2", "oauth2ClientSecret", oauth2ClientSecret) + ar.options.Database.Write("oauth2", "oauth2Scopes", oauth2Scopes) + + utils.SendOK(w) + } else { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + +} + +func (ar *OAuth2Router) fetchOAuth2Configuration(config *oauth2.Config) (*oauth2.Config, error) { + req, err := http.NewRequest("GET", ar.options.OAuth2WellKnownUrl, nil) + if err != nil { + return nil, err + } + client := &http.Client{} + if resp, err := client.Do(req); err != nil { + return nil, err + } else { + defer resp.Body.Close() + + oidcDiscoveryDocument := OIDCDiscoveryDocument{} + if err := json.NewDecoder(resp.Body).Decode(&oidcDiscoveryDocument); err != nil { + return nil, err + } + + if len(config.Scopes) == 0 { + config.Scopes = oidcDiscoveryDocument.ScopesSupported + } + + if config.Endpoint.AuthURL == "" { + config.Endpoint.AuthURL = oidcDiscoveryDocument.AuthorizationEndpoint + } + + if config.Endpoint.TokenURL == "" { + config.Endpoint.TokenURL = oidcDiscoveryDocument.TokenEndpoint + } + + if ar.options.OAuth2UserInfoUrl == "" { + ar.options.OAuth2UserInfoUrl = oidcDiscoveryDocument.UserinfoEndpoint + } + + } + return config, nil +} + +func (ar *OAuth2Router) newOAuth2Conf(redirectUrl string) (*oauth2.Config, error) { + config := &oauth2.Config{ + ClientID: ar.options.OAuth2ClientId, + ClientSecret: ar.options.OAuth2ClientSecret, + RedirectURL: redirectUrl, + Endpoint: oauth2.Endpoint{ + AuthURL: ar.options.OAuth2ServerURL, + TokenURL: ar.options.OAuth2TokenURL, + }, + } + if ar.options.OAuth2Scopes != "" { + config.Scopes = strings.Split(ar.options.OAuth2Scopes, ",") + } + if ar.options.OAuth2WellKnownUrl != "" && (config.Endpoint.AuthURL == "" || config.Endpoint.TokenURL == "" || + ar.options.OAuth2UserInfoUrl == "") { + return ar.fetchOAuth2Configuration(config) + } + return config, nil +} + +// HandleOAuth2Auth is the internal handler for OAuth authentication +// Set useHTTPS to true if your OAuth server is using HTTPS +// Set OAuthURL to the URL of the OAuth server, e.g. OAuth.example.com +func (ar *OAuth2Router) HandleOAuth2Auth(w http.ResponseWriter, r *http.Request) error { + const callbackPrefix = "/internal/oauth2" + const tokenCookie = "z-token" + scheme := "http" + if r.TLS != nil { + scheme = "https" + } + reqUrl := scheme + "://" + r.Host + r.RequestURI + oauthConfig, err := ar.newOAuth2Conf(scheme + "://" + r.Host + callbackPrefix) + if err != nil { + ar.options.Logger.PrintAndLog("OAuth2Router", "Failed to fetch OIDC configuration:", err) + w.WriteHeader(500) + return errors.New("failed to fetch OIDC configuration") + } + + if oauthConfig.Endpoint.AuthURL == "" || oauthConfig.Endpoint.TokenURL == "" || ar.options.OAuth2UserInfoUrl == "" { + ar.options.Logger.PrintAndLog("OAuth2Router", "Invalid OAuth2 configuration", nil) + w.WriteHeader(500) + return errors.New("invalid OAuth2 configuration") + } + + code := r.URL.Query().Get("code") + state := r.URL.Query().Get("state") + if r.Method == http.MethodGet && strings.HasPrefix(r.RequestURI, callbackPrefix) && code != "" && state != "" { + ctx := context.Background() + token, err := oauthConfig.Exchange(ctx, code) + if err != nil { + ar.options.Logger.PrintAndLog("OAuth2", "Token exchange failed", err) + w.WriteHeader(401) + return errors.New("unauthorized") + } + + if !token.Valid() { + ar.options.Logger.PrintAndLog("OAuth2", "Invalid token", err) + w.WriteHeader(401) + return errors.New("unauthorized") + } + + cookie := http.Cookie{Name: tokenCookie, Value: token.AccessToken, Path: "/"} + if scheme == "https" { + cookie.Secure = true + cookie.SameSite = http.SameSiteLaxMode + } + w.Header().Add("Set-Cookie", cookie.String()) + http.Redirect(w, r, state, http.StatusTemporaryRedirect) + return errors.New("authorized") + } + unauthorized := false + cookie, err := r.Cookie(tokenCookie) + if err == nil { + if cookie.Value == "" { + unauthorized = true + } else { + ctx := context.Background() + client := oauthConfig.Client(ctx, &oauth2.Token{AccessToken: cookie.Value}) + req, err := client.Get(ar.options.OAuth2UserInfoUrl) + if err != nil { + ar.options.Logger.PrintAndLog("OAuth2", "Failed to get user info", err) + unauthorized = true + } + defer req.Body.Close() + if req.StatusCode != http.StatusOK { + ar.options.Logger.PrintAndLog("OAuth2", "Failed to get user info", err) + unauthorized = true + } + } + } else { + unauthorized = true + } + if unauthorized { + state := url.QueryEscape(reqUrl) + url := oauthConfig.AuthCodeURL(state, oauth2.AccessTypeOffline) + http.Redirect(w, r, url, http.StatusFound) + + return errors.New("unauthorized") + } + return nil +} diff --git a/src/mod/dynamicproxy/authProviders.go b/src/mod/dynamicproxy/authProviders.go index 8099b55..a296e14 100644 --- a/src/mod/dynamicproxy/authProviders.go +++ b/src/mod/dynamicproxy/authProviders.go @@ -50,6 +50,12 @@ func handleAuthProviderRouting(sep *ProxyEndpoint, w http.ResponseWriter, r *htt h.Parent.Option.Logger.LogHTTPRequest(r, "host-http", 401, requestHostname, "") return true } + } else if sep.AuthenticationProvider.AuthMethod == AuthMethodOAuth2 { + err := h.handleOAuth2Auth(w, r) + if err != nil { + h.Parent.Option.Logger.LogHTTPRequest(r, "host-http", 401, requestHostname, "") + return true + } } //No authentication provider, do not need to handle @@ -116,3 +122,7 @@ func (h *ProxyHandler) handleAutheliaAuth(w http.ResponseWriter, r *http.Request func (h *ProxyHandler) handleAuthentikAuth(w http.ResponseWriter, r *http.Request) error { return h.Parent.Option.AuthentikRouter.HandleAuthentikAuth(w, r) } + +func (h *ProxyHandler) handleOAuth2Auth(w http.ResponseWriter, r *http.Request) error { + return h.Parent.Option.OAuth2Router.HandleOAuth2Auth(w, r) +} diff --git a/src/mod/dynamicproxy/typedef.go b/src/mod/dynamicproxy/typedef.go index 29d20ad..d7fdb9e 100644 --- a/src/mod/dynamicproxy/typedef.go +++ b/src/mod/dynamicproxy/typedef.go @@ -10,6 +10,7 @@ package dynamicproxy import ( _ "embed" "imuslab.com/zoraxy/mod/auth/sso/authentik" + "imuslab.com/zoraxy/mod/auth/sso/oauth2" "net" "net/http" "sync" @@ -66,6 +67,7 @@ type RouterOption struct { /* Authentication Providers */ AutheliaRouter *authelia.AutheliaRouter //Authelia router for Authelia authentication AuthentikRouter *authentik.AuthentikRouter //Authentik router for Authentik authentication + OAuth2Router *oauth2.OAuth2Router //OAuth2Router router for OAuth2Router authentication /* Utilities */ Logger *logger.Logger //Logger for reverse proxy requets @@ -144,7 +146,7 @@ const ( AuthMethodNone AuthMethod = iota //No authentication required AuthMethodBasic //Basic Auth AuthMethodAuthelia //Authelia - AuthMethodOauth2 //Oauth2 + AuthMethodOAuth2 //Oauth2 AuthMethodAuthentik ) diff --git a/src/mod/sshprox/embed.go b/src/mod/sshprox/embed.go index 4c5fe2d..b5ac80d 100644 --- a/src/mod/sshprox/embed.go +++ b/src/mod/sshprox/embed.go @@ -1,14 +1,14 @@ -//go:build (windows && amd64) || (linux && mipsle) || (linux && riscv64) || (freebsd && amd64) -// +build windows,amd64 linux,mipsle linux,riscv64 freebsd,amd64 +//go:build (windows && amd64) || (linux && mipsle) || (linux && riscv64) || (freebsd && amd64) || (darwin && arm64) +// +build windows,amd64 linux,mipsle linux,riscv64 freebsd,amd64 darwin,arm64 package sshprox import "embed" /* - Binary embedding +Binary embedding - Make sure when compile, gotty binary exists in static.gotty +Make sure when compile, gotty binary exists in static.gotty */ var ( //go:embed gotty/LICENSE diff --git a/src/reverseproxy.go b/src/reverseproxy.go index d00b606..83e3d21 100644 --- a/src/reverseproxy.go +++ b/src/reverseproxy.go @@ -117,6 +117,7 @@ func ReverseProxtInit() { AccessController: accessController, AutheliaRouter: autheliaRouter, AuthentikRouter: authentikRouter, + OAuth2Router: oauth2Router, LoadBalancer: loadBalancer, PluginManager: pluginManager, /* Utilities */ @@ -587,7 +588,7 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) { } else if authProviderType == 2 { newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodAuthelia } else if authProviderType == 3 { - newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodOauth2 + newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodOAuth2 } else if authProviderType == 4 { newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodAuthentik } else { diff --git a/src/start.go b/src/start.go index 0fadc05..16ab97e 100644 --- a/src/start.go +++ b/src/start.go @@ -1,6 +1,7 @@ package main import ( + "imuslab.com/zoraxy/mod/auth/sso/oauth2" "log" "net/http" "os" @@ -157,6 +158,11 @@ func startupSequence() { Database: sysdb, }) + oauth2Router = oauth2.NewOAuth2Router(&oauth2.OAuth2RouterOptions{ + Logger: SystemWideLogger, + Database: sysdb, + }) + //Create a statistic collector statisticCollector, err = statistic.NewStatisticCollector(statistic.CollectorOption{ Database: sysdb, diff --git a/src/web/components/httprp.html b/src/web/components/httprp.html index 1a9d653..a7afa4e 100644 --- a/src/web/components/httprp.html +++ b/src/web/components/httprp.html @@ -186,7 +186,7 @@ ${subd.AuthenticationProvider.AuthMethod == 0x1?` Basic Auth`:``} ${subd.AuthenticationProvider.AuthMethod == 0x2?` Authelia`:``} - ${subd.AuthenticationProvider.AuthMethod == 0x3?` Oauth2`:``} + ${subd.AuthenticationProvider.AuthMethod == 0x3?` OAuth2`:``} ${subd.AuthenticationProvider.AuthMethod == 0x4?` Authentik`:``} ${subd.AuthenticationProvider.AuthMethod != 0x0 && subd.RequireRateLimit?"
":""} ${subd.RequireRateLimit?` Rate Limit @ ${subd.RateLimit} req/s`:``} @@ -396,6 +396,12 @@ +
+
+ + +
+
diff --git a/src/web/components/sso.html b/src/web/components/sso.html index 820735a..5061ebc 100644 --- a/src/web/components/sso.html +++ b/src/web/components/sso.html @@ -17,10 +17,10 @@

Authelia

Configuration settings for Authelia authentication provider.

-
+
- - + + Example: auth.example.com
@@ -30,7 +30,61 @@ Check this if your authelia server uses HTTPS
- + + +
+
+
+

OAuth 2.0

+

Configuration settings for OAuth 2.0 authentication provider.

+ +
+
+ + + Public identifier of the OAuth2 application +
+
+ + + Secret key of the OAuth2 application +
+
+ + + URL to the OIDC discovery document (usually ending with /.well-known/openid-configuration). Used to automatically fetch provider settings. +
+ +
+ + + URL used to authenticate against the OAuth2 provider. Will redirect the user to the OAuth2 provider login view. Optional if Well-Known url is configured. +
+ +
+ + + URL used by Zoraxy to exchange a valid OAuth2 authentication code for an access token. Optional if Well-Known url is configured. +
+ +
+ + + URL used by the OAuth2 provider to redirect the user after successful authentication. Should be set to your Zoraxy instance URL +
+ +
+ + + URL used by the OAuth2 provider to validate generated token. Optional if Well-Known url is configured. +
+ +
+ + + Scopes required by the OAuth2 provider to retrieve information about the authenticated user. Refer to your OAuth2 provider documentation for more information about this. Optional if Well-Known url is configured. +
+
@@ -38,10 +92,10 @@

Authentik

Configuration settings for Authentik authentication provider.

-
+
- - + + Example: auth.example.com
@@ -51,7 +105,7 @@ Check this if your Authentik server uses HTTPS
- +
@@ -83,22 +137,35 @@ console.error('Error fetching SSO settings:', textStatus, errorThrown); } }); + $.cjax({ + url: '/api/sso/OAuth2', + method: 'GET', + dataType: 'json', + success: function(data) { + $('#oauth2WellKnownUrl').val(data.oauth2WellKnownUrl); + $('#oauth2ServerUrl').val(data.oauth2ServerUrl); + $('#oauth2TokenUrl').val(data.oauth2TokenUrl); + $('#oauth2RedirectUrl').val(data.oauth2RedirectUrl); + $('#oauth2UserInfoUrl').val(data.oauth2UserInfoUrl); + $('#oauth2ClientId').val(data.oauth2ClientId); + $('#oauth2ClientSecret').val(data.oauth2ClientSecret); + $('#oauth2Scopes').val(data.oauth2Scopes); + }, + error: function(jqXHR, textStatus, errorThrown) { + console.error('Error fetching SSO settings:', textStatus, errorThrown); + } + }); }); - function updateAutheliaSettings(){ - var autheliaServerUrl = $('#autheliaServerUrl').val(); - var useHttps = $('#useHttps').prop('checked'); - + $( "#autheliaSettings" ).on( "submit", function( event ) { + event.preventDefault(); $.cjax({ url: '/api/sso/Authelia', method: 'POST', - data: { - autheliaURL: autheliaServerUrl, - useHTTPS: useHttps - }, + data: $( this ).serialize(), success: function(data) { if (data.error != undefined) { - $.msgbox(data.error, false); + msgbox(data.error, false); return; } msgbox('Authelia settings updated', true); @@ -106,23 +173,20 @@ }, error: function(jqXHR, textStatus, errorThrown) { console.error('Error updating Authelia settings:', textStatus, errorThrown); + msgbox('Error updating Authelia settings, check console', false); } }); - } - function updateAuthentikSettings(){ - var authentikServerUrl = $('#authentikServerUrl').val(); - var useHttps = $('#authentikUseHttps').prop('checked'); + }); + $( "#authentikSettings" ).on( "submit", function( event ) { + event.preventDefault(); $.cjax({ url: '/api/sso/Authentik', method: 'POST', - data: { - authentikURL: authentikServerUrl, - useHTTPS: useHttps - }, + data: $( this ).serialize(), success: function(data) { if (data.error != undefined) { - $.msgbox(data.error, false); + msgbox(data.error, false); return; } msgbox('Authentik settings updated', true); @@ -130,7 +194,29 @@ }, error: function(jqXHR, textStatus, errorThrown) { console.error('Error updating Authentik settings:', textStatus, errorThrown); + msgbox('Error updating Authentik settings, check console', false); } }); - } + }); + + $( "#oauth2Settings" ).on( "submit", function( event ) { + event.preventDefault(); + $.cjax({ + url: '/api/sso/OAuth2', + method: 'POST', + data: $( this ).serialize(), + success: function(data) { + if (data.error != undefined) { + msgbox(data.error, false); + return; + } + msgbox('OAuth2 settings updated', true); + console.log('OAuth2 settings updated:', data); + }, + error: function(jqXHR, textStatus, errorThrown) { + console.error('Error updating OAuth2 settings:', textStatus, errorThrown); + msgbox('Error updating OAuth2 settings, check console', false); + } + }); + }); \ No newline at end of file diff --git a/src/web/index.html b/src/web/index.html index 98ea85b..fb8df92 100644 --- a/src/web/index.html +++ b/src/web/index.html @@ -72,7 +72,7 @@ TLS / SSL certificates - SSO / Oauth + SSO / OAuth2