Merge pull request #789 from james-d-elliott/feat-sso-clear

feat(sso): clear settings
This commit is contained in:
Toby Chui
2025-09-06 13:22:49 +08:00
committed by GitHub
3 changed files with 234 additions and 100 deletions

View File

@@ -96,6 +96,8 @@ func (ar *AuthRouter) HandleAPIOptions(w http.ResponseWriter, r *http.Request) {
ar.handleOptionsGET(w, r) ar.handleOptionsGET(w, r)
case http.MethodPost: case http.MethodPost:
ar.handleOptionsPOST(w, r) ar.handleOptionsPOST(w, r)
case http.MethodDelete:
ar.handleOptionsDelete(w, r)
default: default:
ar.handleOptionsMethodNotAllowed(w, r) ar.handleOptionsMethodNotAllowed(w, r)
} }
@@ -161,6 +163,28 @@ func (ar *AuthRouter) handleOptionsPOST(w http.ResponseWriter, r *http.Request)
utils.SendOK(w) 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) { func (ar *AuthRouter) handleOptionsMethodNotAllowed(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)

View File

@@ -66,7 +66,19 @@ func NewOAuth2Router(options *OAuth2RouterOptions) *OAuth2Router {
// HandleSetOAuth2Settings is the internal handler for setting the OAuth URL and HTTPS // HandleSetOAuth2Settings is the internal handler for setting the OAuth URL and HTTPS
func (ar *OAuth2Router) HandleSetOAuth2Settings(w http.ResponseWriter, r *http.Request) { func (ar *OAuth2Router) HandleSetOAuth2Settings(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet { 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 //Return the current settings
js, _ := json.Marshal(map[string]interface{}{ js, _ := json.Marshal(map[string]interface{}{
"oauth2WellKnownUrl": ar.options.OAuth2WellKnownUrl, "oauth2WellKnownUrl": ar.options.OAuth2WellKnownUrl,
@@ -79,10 +91,24 @@ func (ar *OAuth2Router) HandleSetOAuth2Settings(w http.ResponseWriter, r *http.R
}) })
utils.SendJSONResponse(w, string(js)) utils.SendJSONResponse(w, string(js))
return }
} else if r.Method == http.MethodPost {
func (ar *OAuth2Router) handleSetOAuthSettingsPOST(w http.ResponseWriter, r *http.Request) {
//Update the settings //Update the settings
var oauth2ServerUrl, oauth2TokenURL, oauth2Scopes, oauth2UserInfoUrl string 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") oauth2WellKnownUrl, err := utils.PostPara(r, "oauth2WellKnownUrl")
if err != nil { if err != nil {
oauth2ServerUrl, err = utils.PostPara(r, "oauth2ServerUrl") oauth2ServerUrl, err = utils.PostPara(r, "oauth2ServerUrl")
@@ -97,29 +123,19 @@ func (ar *OAuth2Router) HandleSetOAuth2Settings(w http.ResponseWriter, r *http.R
return return
} }
oauth2Scopes, err = utils.PostPara(r, "oauth2Scopes")
if err != nil {
utils.SendErrorResponse(w, "oauth2Scopes not found")
return
}
oauth2UserInfoUrl, err = utils.PostPara(r, "oauth2UserInfoUrl") oauth2UserInfoUrl, err = utils.PostPara(r, "oauth2UserInfoUrl")
if err != nil { if err != nil {
utils.SendErrorResponse(w, "oauth2UserInfoUrl not found") utils.SendErrorResponse(w, "oauth2UserInfoUrl not found")
return return
} }
}
oauth2ClientId, err := utils.PostPara(r, "oauth2ClientId") oauth2Scopes, err = utils.PostPara(r, "oauth2Scopes")
if err != nil { if err != nil {
utils.SendErrorResponse(w, "oauth2ClientId not found") utils.SendErrorResponse(w, "oauth2Scopes not found")
return return
} }
} else {
oauth2ClientSecret, err := utils.PostPara(r, "oauth2ClientSecret") oauth2Scopes, _ = utils.PostPara(r, "oauth2Scopes")
if err != nil {
utils.SendErrorResponse(w, "oauth2ClientSecret not found")
return
} }
//Write changes to runtime //Write changes to runtime
@@ -141,11 +157,26 @@ func (ar *OAuth2Router) HandleSetOAuth2Settings(w http.ResponseWriter, r *http.R
ar.options.Database.Write("oauth2", "oauth2Scopes", oauth2Scopes) ar.options.Database.Write("oauth2", "oauth2Scopes", oauth2Scopes)
utils.SendOK(w) utils.SendOK(w)
} else {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
} }
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) { func (ar *OAuth2Router) fetchOAuth2Configuration(config *oauth2.Config) (*oauth2.Config, error) {

View File

@@ -90,6 +90,7 @@
</div> </div>
</div> </div>
<button class="ui basic button" type="submit"><i class="green check icon"></i> Apply Change</button> <button class="ui basic button" type="submit"><i class="green check icon"></i> Apply Change</button>
<button class="ui basic button" type="button" id="forwardAuthClear"><i class="red trash icon"></i> Clear</button>
</form> </form>
</div> </div>
<div class="ui bottom attached tab segment" data-tab="oauth2_tab"> <div class="ui bottom attached tab segment" data-tab="oauth2_tab">
@@ -109,9 +110,9 @@
<small>Secret key of the OAuth2 application</small> <small>Secret key of the OAuth2 application</small>
</div> </div>
<div class="field"> <div class="field">
<label for="oauth2WellKnownUrl">OIDC well-known URL</label> <label for="oauth2WellKnownUrl">Discovery URL</label>
<input type="text" id="oauth2WellKnownUrl" name="oauth2WellKnownUrl" placeholder="Enter Well-Known URL"> <input type="text" id="oauth2WellKnownUrl" name="oauth2WellKnownUrl" placeholder="Enter Well-Known URL">
<small>URL to the OIDC discovery document (usually ending with /.well-known/openid-configuration). Used to automatically fetch provider settings.</small> <small>URL to the OpenID Connect 1.0 Discovery document (usually ending with /.well-known/openid-configuration). Used to automatically fetch provider settings.</small>
</div> </div>
<div class="field"> <div class="field">
@@ -138,6 +139,7 @@
<small>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.</small> <small>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.</small>
</div> </div>
<button class="ui basic button" type="submit"><i class="green check icon"></i> Apply Change</button> <button class="ui basic button" type="submit"><i class="green check icon"></i> Apply Change</button>
<button class="ui basic button" type="button" id="oauth2Clear"><i class="red trash icon"></i> Clear</button>
</form> </form>
</div> </div>
<div class="ui bottom attached tab segment" data-tab="zoraxy_sso_tab"> <div class="ui bottom attached tab segment" data-tab="zoraxy_sso_tab">
@@ -153,6 +155,18 @@
$(document).ready(function() { $(document).ready(function() {
/* Load Forward Authz settings from backend */ /* 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({ $.cjax({
url: '/api/sso/forward-auth', url: '/api/sso/forward-auth',
method: 'GET', method: 'GET',
@@ -199,28 +213,7 @@
console.error('Error fetching SSO settings:', textStatus, errorThrown); 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. 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. OAuth 2.0 settings update handler.
*/ */
$( "#oauth2Settings" ).on( "submit", function( event ) { $( "#oauth2Settings" ).on( "submit", function( event ) {
event.preventDefault(); 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({ $.cjax({
url: '/api/sso/OAuth2', url: '/api/sso/OAuth2',
method: 'POST', 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 */ /* Bind UI events */
$(".sso .advanceSettings").accordion(); $(".sso .advanceSettings").accordion();
</script> </script>