diff --git a/src/mod/auth/sso/forward/forward.go b/src/mod/auth/sso/forward/forward.go index 5f1989f..998b490 100644 --- a/src/mod/auth/sso/forward/forward.go +++ b/src/mod/auth/sso/forward/forward.go @@ -96,6 +96,8 @@ func (ar *AuthRouter) HandleAPIOptions(w http.ResponseWriter, r *http.Request) { ar.handleOptionsGET(w, r) case http.MethodPost: ar.handleOptionsPOST(w, r) + case http.MethodDelete: + ar.handleOptionsDelete(w, r) default: ar.handleOptionsMethodNotAllowed(w, r) } @@ -161,6 +163,28 @@ func (ar *AuthRouter) handleOptionsPOST(w http.ResponseWriter, r *http.Request) utils.SendOK(w) } +func (ar *AuthRouter) handleOptionsDelete(w http.ResponseWriter, r *http.Request) { + ar.options.Address = "" + ar.options.ResponseHeaders = nil + ar.options.ResponseClientHeaders = nil + ar.options.RequestHeaders = nil + ar.options.RequestIncludedCookies = nil + ar.options.RequestExcludedCookies = nil + ar.options.RequestIncludeBody = false + ar.options.UseXOriginalHeaders = false + + ar.options.Database.Delete(DatabaseTable, DatabaseKeyAddress) + ar.options.Database.Delete(DatabaseTable, DatabaseKeyResponseHeaders) + ar.options.Database.Delete(DatabaseTable, DatabaseKeyResponseClientHeaders) + ar.options.Database.Delete(DatabaseTable, DatabaseKeyRequestHeaders) + ar.options.Database.Delete(DatabaseTable, DatabaseKeyRequestIncludedCookies) + ar.options.Database.Delete(DatabaseTable, DatabaseKeyRequestExcludedCookies) + ar.options.Database.Delete(DatabaseTable, DatabaseKeyRequestIncludeBody) + ar.options.Database.Delete(DatabaseTable, DatabaseKeyUseXOriginalHeaders) + + utils.SendOK(w) +} + func (ar *AuthRouter) handleOptionsMethodNotAllowed(w http.ResponseWriter, r *http.Request) { http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) diff --git a/src/mod/auth/sso/oauth2/oauth2.go b/src/mod/auth/sso/oauth2/oauth2.go index 8cd519d..e06aec7 100644 --- a/src/mod/auth/sso/oauth2/oauth2.go +++ b/src/mod/auth/sso/oauth2/oauth2.go @@ -66,86 +66,117 @@ func NewOAuth2Router(options *OAuth2RouterOptions) *OAuth2Router { // 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, - "oauth2UserInfoUrl": ar.options.OAuth2UserInfoUrl, - "oauth2Scopes": ar.options.OAuth2Scopes, - "oauth2ClientSecret": ar.options.OAuth2ClientSecret, - "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 - } - } - - 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.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", "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 { + switch r.Method { + case http.MethodGet: + ar.handleSetOAuthSettingsGET(w, r) + case http.MethodPost: + ar.handleSetOAuthSettingsPOST(w, r) + case http.MethodDelete: + ar.handleSetOAuthSettingsDELETE(w, r) + default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + } +} + +func (ar *OAuth2Router) handleSetOAuthSettingsGET(w http.ResponseWriter, r *http.Request) { + //Return the current settings + js, _ := json.Marshal(map[string]interface{}{ + "oauth2WellKnownUrl": ar.options.OAuth2WellKnownUrl, + "oauth2ServerUrl": ar.options.OAuth2ServerURL, + "oauth2TokenUrl": ar.options.OAuth2TokenURL, + "oauth2UserInfoUrl": ar.options.OAuth2UserInfoUrl, + "oauth2Scopes": ar.options.OAuth2Scopes, + "oauth2ClientSecret": ar.options.OAuth2ClientSecret, + "oauth2ClientId": ar.options.OAuth2ClientId, + }) + + utils.SendJSONResponse(w, string(js)) +} + +func (ar *OAuth2Router) handleSetOAuthSettingsPOST(w http.ResponseWriter, r *http.Request) { + //Update the settings + var oauth2ServerUrl, oauth2TokenURL, oauth2Scopes, oauth2UserInfoUrl string + + 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 + } + + 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 + } + + oauth2UserInfoUrl, err = utils.PostPara(r, "oauth2UserInfoUrl") + if err != nil { + utils.SendErrorResponse(w, "oauth2UserInfoUrl not found") + return + } + + oauth2Scopes, err = utils.PostPara(r, "oauth2Scopes") + if err != nil { + utils.SendErrorResponse(w, "oauth2Scopes not found") + return + } + } else { + oauth2Scopes, _ = utils.PostPara(r, "oauth2Scopes") + } + + //Write changes to runtime + ar.options.OAuth2WellKnownUrl = oauth2WellKnownUrl + ar.options.OAuth2ServerURL = oauth2ServerUrl + ar.options.OAuth2TokenURL = oauth2TokenURL + 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", "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) +} + +func (ar *OAuth2Router) handleSetOAuthSettingsDELETE(w http.ResponseWriter, r *http.Request) { + ar.options.OAuth2WellKnownUrl = "" + ar.options.OAuth2ServerURL = "" + ar.options.OAuth2TokenURL = "" + ar.options.OAuth2UserInfoUrl = "" + ar.options.OAuth2ClientId = "" + ar.options.OAuth2ClientSecret = "" + ar.options.OAuth2Scopes = "" + + ar.options.Database.Delete("oauth2", "oauth2WellKnownUrl") + ar.options.Database.Delete("oauth2", "oauth2ServerUrl") + ar.options.Database.Delete("oauth2", "oauth2TokenUrl") + ar.options.Database.Delete("oauth2", "oauth2UserInfoUrl") + ar.options.Database.Delete("oauth2", "oauth2ClientId") + ar.options.Database.Delete("oauth2", "oauth2ClientSecret") + ar.options.Database.Delete("oauth2", "oauth2Scopes") + + utils.SendOK(w) } func (ar *OAuth2Router) fetchOAuth2Configuration(config *oauth2.Config) (*oauth2.Config, error) { diff --git a/src/web/components/sso.html b/src/web/components/sso.html index f8bf481..7271844 100644 --- a/src/web/components/sso.html +++ b/src/web/components/sso.html @@ -90,6 +90,7 @@ +
@@ -109,9 +110,9 @@ 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 to the OpenID Connect 1.0 Discovery document (usually ending with /.well-known/openid-configuration). Used to automatically fetch provider settings.
@@ -138,6 +139,7 @@ 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.
+
@@ -153,6 +155,18 @@ $(document).ready(function() { /* Load Forward Authz settings from backend */ + getForwardAuthSettings(); + + /* Load OAuth 2.0 settings from backend */ + getOAuth20Settings(); + + /* Add more initialization code here if needed */ + }); + + /* + Forward Auth settings fetcher. + */ + function getForwardAuthSettings() { $.cjax({ url: '/api/sso/forward-auth', method: 'GET', @@ -199,28 +213,7 @@ console.error('Error fetching SSO settings:', textStatus, errorThrown); } }); - - /* Load OAuth 2.0 settings from backend */ - $.cjax({ - url: '/api/sso/OAuth2', - method: 'GET', - dataType: 'json', - success: function(data) { - $('#oauth2WellKnownUrl').val(data.oauth2WellKnownUrl); - $('#oauth2ServerUrl').val(data.oauth2ServerUrl); - $('#oauth2TokenUrl').val(data.oauth2TokenUrl); - $('#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); - } - }); - - /* Add more initialization code here if needed */ - }); + } /* Forward Auth settings update handler. @@ -266,11 +259,73 @@ }); }); + $( "#forwardAuthClear" ).on( "click", function( event ) { + event.preventDefault(); + + $.cjax({ + url: '/api/sso/forward-auth', + method: 'DELETE', + success: function(data) { + if (data.error != undefined) { + msgbox(data.error, false); + return; + } + + getForwardAuthSettings(); + + msgbox('Forward Auth settings cleared', true); + console.log('Forward Auth settings cleared:', data); + }, + error: function(jqXHR, textStatus, errorThrown) { + console.error('Error clearing Forward Auth settings:', textStatus, errorThrown); + msgbox('Error clearing Forward Auth settings, check console', false); + } + }); + }); + + /* + OAuth 2.0 settings fetcher. + */ + function getOAuth20Settings() { + $.cjax({ + url: '/api/sso/OAuth2', + method: 'GET', + dataType: 'json', + success: function(data) { + $('#oauth2WellKnownUrl').val(data.oauth2WellKnownUrl); + $('#oauth2ServerUrl').val(data.oauth2ServerUrl); + $('#oauth2TokenUrl').val(data.oauth2TokenUrl); + $('#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); + } + }); + } + /* OAuth 2.0 settings update handler. */ $( "#oauth2Settings" ).on( "submit", function( event ) { event.preventDefault(); + + if ($('#oauth2ClientId').val().length === 0 || $('#oauth2ClientSecret').val().length === 0) { + msgbox("You must specify the Client ID and Client Secret.", false); + + return; + } + + if ($('#oauth2WellKnownUrl').val().length === 0) { + if ($('#oauth2ServerUrl').val().length === 0 || $('#oauth2TokenUrl').val().length === 0 || $('#oauth2UserInfoURL').val().length === 0 || $('#oauth2Scopes').val().length === 0) { + msgbox("You must specify either the Well Known URL or configure the Authorization URL, Token URL, User Info URL, and Scopes.", false); + + return; + } + } + $.cjax({ url: '/api/sso/OAuth2', method: 'POST', @@ -290,6 +345,30 @@ }); }); + $( "#oauth2Clear" ).on( "click", function( event ) { + event.preventDefault(); + + $.cjax({ + url: '/api/sso/OAuth2', + method: 'DELETE', + success: function(data) { + if (data.error != undefined) { + msgbox(data.error, false); + return; + } + + getOAuth20Settings(); + + msgbox('OAuth2 settings cleared', true); + console.log('OAuth2 settings cleared:', data); + }, + error: function(jqXHR, textStatus, errorThrown) { + console.error('Error clearing OAuth2 settings:', textStatus, errorThrown); + msgbox('Error clearing OAuth2 settings, check console', false); + } + }); + }); + /* Bind UI events */ $(".sso .advanceSettings").accordion(); \ No newline at end of file