Fixed early renew day not passed into auto renewer config bug
This commit is contained in:
Toby Chui 2024-09-26 22:57:49 +08:00
parent 5c56da1180
commit cab2f4e63a
14 changed files with 143186 additions and 22426 deletions

View File

@ -97,11 +97,13 @@ func initAPIs(targetMux *http.ServeMux) {
//SSO and Oauth //SSO and Oauth
authRouter.HandleFunc("/api/sso/status", ssoHandler.HandleSSOStatus) authRouter.HandleFunc("/api/sso/status", ssoHandler.HandleSSOStatus)
authRouter.HandleFunc("/api/sso/start", ssoHandler.HandleStartSSOPortal) authRouter.HandleFunc("/api/sso/enable", ssoHandler.HandleSSOEnable)
authRouter.HandleFunc("/api/sso/stop", ssoHandler.HandleStopSSOPortal)
authRouter.HandleFunc("/api/sso/setPort", ssoHandler.HandlePortChange) authRouter.HandleFunc("/api/sso/setPort", ssoHandler.HandlePortChange)
authRouter.HandleFunc("/api/sso/setAuthURL", ssoHandler.HandleSetAuthURL) authRouter.HandleFunc("/api/sso/setAuthURL", ssoHandler.HandleSetAuthURL)
//authRouter.HandleFunc("/api/sso/registerApp", ssoHandler.HandleRegisterApp)
authRouter.HandleFunc("/api/sso/app/register", ssoHandler.HandleRegisterApp)
//authRouter.HandleFunc("/api/sso/app/list", ssoHandler.HandleListApp)
//authRouter.HandleFunc("/api/sso/app/remove", ssoHandler.HandleRemoveApp)
authRouter.HandleFunc("/api/sso/user/list", ssoHandler.HandleListUser) authRouter.HandleFunc("/api/sso/user/list", ssoHandler.HandleListUser)
authRouter.HandleFunc("/api/sso/user/add", ssoHandler.HandleAddUser) authRouter.HandleFunc("/api/sso/user/add", ssoHandler.HandleAddUser)

View File

@ -88,9 +88,12 @@ func NewAutoRenewer(config string, certFolder string, renewCheckInterval int64,
AcmeHandler: AcmeHandler, AcmeHandler: AcmeHandler,
RenewerConfig: &renewerConfig, RenewerConfig: &renewerConfig,
RenewTickInterval: renewCheckInterval, RenewTickInterval: renewCheckInterval,
EarlyRenewDays: earlyRenewDays,
Logger: logger, Logger: logger,
} }
thisRenewer.Logf("ACME early renew set to "+fmt.Sprint(earlyRenewDays)+" days and check interval set to "+fmt.Sprint(renewCheckInterval)+" seconds", nil)
if thisRenewer.RenewerConfig.Enabled { if thisRenewer.RenewerConfig.Enabled {
//Start the renew ticker //Start the renew ticker
thisRenewer.StartAutoRenewTicker() thisRenewer.StartAutoRenewTicker()
@ -103,7 +106,7 @@ func NewAutoRenewer(config string, certFolder string, renewCheckInterval int64,
} }
func (a *AutoRenewer) Logf(message string, err error) { func (a *AutoRenewer) Logf(message string, err error) {
a.Logger.PrintAndLog("CertRenew", message, err) a.Logger.PrintAndLog("cert-renew", message, err)
} }
func (a *AutoRenewer) StartAutoRenewTicker() { func (a *AutoRenewer) StartAutoRenewTicker() {

View File

@ -5,14 +5,14 @@ import (
"encoding/pem" "encoding/pem"
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "os"
"time" "time"
) )
// Get the issuer name from pem file // Get the issuer name from pem file
func ExtractIssuerNameFromPEM(pemFilePath string) (string, error) { func ExtractIssuerNameFromPEM(pemFilePath string) (string, error) {
// Read the PEM file // Read the PEM file
pemData, err := ioutil.ReadFile(pemFilePath) pemData, err := os.ReadFile(pemFilePath)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -37,16 +37,46 @@ func (s *SSOHandler) HandleSSOStatus(w http.ResponseWriter, r *http.Request) {
utils.SendJSONResponse(w, string(js)) utils.SendJSONResponse(w, string(js))
} }
// HandleStartSSOPortal handle the request to start the SSO portal server // Wrapper for starting and stopping the SSO portal server
func (s *SSOHandler) HandleStartSSOPortal(w http.ResponseWriter, r *http.Request) { // require POST request with key "enable" and value "true" or "false"
err := s.StartSSOPortal() func (s *SSOHandler) HandleSSOEnable(w http.ResponseWriter, r *http.Request) {
enable, err := utils.PostBool(r, "enable")
if err != nil { if err != nil {
s.Log("Failed to start SSO portal server", err) utils.SendErrorResponse(w, "invalid enable value")
utils.SendErrorResponse(w, "failed to start SSO portal server")
return return
} }
if enable {
s.HandleStartSSOPortal(w, r)
} else {
s.HandleStopSSOPortal(w, r)
}
}
// HandleStartSSOPortal handle the request to start the SSO portal server
func (s *SSOHandler) HandleStartSSOPortal(w http.ResponseWriter, r *http.Request) {
if s.ssoPortalServer != nil {
//Already enabled. Do restart instead.
err := s.RestartSSOServer()
if err != nil {
utils.SendErrorResponse(w, "failed to start SSO server")
return
}
utils.SendOK(w)
return
}
//Check if the authURL is set correctly. If not, return error
if s.Config.AuthURL == "" {
utils.SendErrorResponse(w, "auth URL not set")
return
}
//Start the SSO portal server in go routine
go s.StartSSOPortal()
//Write current state to database //Write current state to database
err = s.Config.Database.Write("sso_conf", "enabled", true) err := s.Config.Database.Write("sso_conf", "enabled", true)
if err != nil { if err != nil {
utils.SendErrorResponse(w, "failed to update SSO state") utils.SendErrorResponse(w, "failed to update SSO state")
return return
@ -56,6 +86,12 @@ func (s *SSOHandler) HandleStartSSOPortal(w http.ResponseWriter, r *http.Request
// HandleStopSSOPortal handle the request to stop the SSO portal server // HandleStopSSOPortal handle the request to stop the SSO portal server
func (s *SSOHandler) HandleStopSSOPortal(w http.ResponseWriter, r *http.Request) { func (s *SSOHandler) HandleStopSSOPortal(w http.ResponseWriter, r *http.Request) {
if s.ssoPortalServer == nil {
//Already disabled
utils.SendOK(w)
return
}
err := s.ssoPortalServer.Close() err := s.ssoPortalServer.Close()
if err != nil { if err != nil {
s.Log("Failed to stop SSO portal server", err) s.Log("Failed to stop SSO portal server", err)
@ -70,13 +106,6 @@ func (s *SSOHandler) HandleStopSSOPortal(w http.ResponseWriter, r *http.Request)
utils.SendErrorResponse(w, "failed to update SSO state") utils.SendErrorResponse(w, "failed to update SSO state")
return return
} }
//Clear the cookie store and restart the server
err = s.RestartSSOServer()
if err != nil {
utils.SendErrorResponse(w, "failed to restart SSO server")
return
}
utils.SendOK(w) utils.SendOK(w)
} }
@ -104,11 +133,13 @@ func (s *SSOHandler) HandlePortChange(w http.ResponseWriter, r *http.Request) {
return return
} }
//Clear the cookie store and restart the server if s.IsRunning() {
err = s.RestartSSOServer() //Restart the server if it is running
if err != nil { err = s.RestartSSOServer()
utils.SendErrorResponse(w, "failed to restart SSO server") if err != nil {
return utils.SendErrorResponse(w, "failed to restart SSO server")
return
}
} }
utils.SendOK(w) utils.SendOK(w)
} }

View File

@ -0,0 +1,58 @@
package sso
import (
"encoding/json"
"net/http"
"strings"
)
type OpenIDConfiguration struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
JwksUri string `json:"jwks_uri"`
ResponseTypesSupported []string `json:"response_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
ClaimsSupported []string `json:"claims_supported"`
}
func (h *SSOHandler) HandleDiscoveryRequest(w http.ResponseWriter, r *http.Request) {
//Prepend https:// if not present
authBaseURL := h.Config.AuthURL
if !strings.HasPrefix(authBaseURL, "http://") && !strings.HasPrefix(authBaseURL, "https://") {
authBaseURL = "https://" + authBaseURL
}
//Handle the discovery request
discovery := OpenIDConfiguration{
Issuer: authBaseURL,
AuthorizationEndpoint: authBaseURL + "/oauth2/authorize",
TokenEndpoint: authBaseURL + "/oauth2/token",
JwksUri: authBaseURL + "/jwks.json",
ResponseTypesSupported: []string{"code", "token"},
SubjectTypesSupported: []string{"public"},
IDTokenSigningAlgValuesSupported: []string{
"RS256",
},
ClaimsSupported: []string{
"sub", //Subject, usually the user ID
"iss", //Issuer, usually the server URL
"aud", //Audience, usually the client ID
"exp", //Expiration Time
"iat", //Issued At
"email", //Email
"locale", //Locale
"name", //Full Name
"nickname", //Nickname
"preferred_username", //Preferred Username
"website", //Website
},
}
//Write the response
js, _ := json.Marshal(discovery)
w.Header().Set("Content-Type", "application/json")
w.Write(js)
}

View File

@ -6,6 +6,7 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/go-oauth2/oauth2/v4/errors"
"imuslab.com/zoraxy/mod/utils" "imuslab.com/zoraxy/mod/utils"
) )
@ -30,21 +31,26 @@ func (h *SSOHandler) InitSSOPortal(portalServerPort int) {
//Register API endpoint for the SSO portal //Register API endpoint for the SSO portal
pmux.HandleFunc("/sso/login", h.HandleLogin) pmux.HandleFunc("/sso/login", h.HandleLogin)
//Register API endpoint for autodiscovery
pmux.HandleFunc("/.well-known/openid-configuration", h.HandleDiscoveryRequest)
//Register OAuth2 endpoints //Register OAuth2 endpoints
h.Oauth2Server.RegisterOauthEndpoints(pmux) h.Oauth2Server.RegisterOauthEndpoints(pmux)
h.ssoPortalMux = pmux h.ssoPortalMux = pmux
} }
// StartSSOPortal start the SSO portal server // StartSSOPortal start the SSO portal server
// This function will block the main thread, call it in a goroutine // This function will block the main thread, call it in a goroutine
func (h *SSOHandler) StartSSOPortal() error { func (h *SSOHandler) StartSSOPortal() error {
if h.ssoPortalServer != nil {
return errors.New("SSO portal server already running")
}
h.ssoPortalServer = &http.Server{ h.ssoPortalServer = &http.Server{
Addr: ":" + strconv.Itoa(h.Config.PortalServerPort), Addr: ":" + strconv.Itoa(h.Config.PortalServerPort),
Handler: h.ssoPortalMux, Handler: h.ssoPortalMux,
} }
err := h.ssoPortalServer.ListenAndServe() err := h.ssoPortalServer.ListenAndServe()
if err != nil { if err != nil && err != http.ErrServerClosed {
h.Log("Failed to start SSO portal server", err) h.Log("Failed to start SSO portal server", err)
} }
return err return err
@ -59,14 +65,17 @@ func (h *SSOHandler) StopSSOPortal() error {
h.Log("Failed to stop SSO portal server", err) h.Log("Failed to stop SSO portal server", err)
return err return err
} }
h.ssoPortalServer = nil
return nil return nil
} }
// StartSSOPortal start the SSO portal server // StartSSOPortal start the SSO portal server
func (h *SSOHandler) RestartSSOServer() error { func (h *SSOHandler) RestartSSOServer() error {
err := h.StopSSOPortal() if h.ssoPortalServer != nil {
if err != nil { err := h.StopSSOPortal()
return err if err != nil {
return err
}
} }
go h.StartSSOPortal() go h.StartSSOPortal()
return nil return nil

View File

@ -23,13 +23,27 @@ type SubdomainAccessRule struct {
} }
type UserEntry struct { type UserEntry struct {
UserID string //User ID, in UUIDv4 format UserID string `json:sub` //User ID
Username string //Username Username string `json:"name"` //Username
PasswordHash string //Password hash Email string `json:"email"` //Email
TOTPCode string //2FA TOTP code PasswordHash string `json:"passwordhash"` //Password hash
Enable2FA bool //Enable 2FA for this user TOTPCode string `json:"totpcode"` //TOTP code
Subdomains map[string]*SubdomainAccessRule //Subdomain and access rule Enable2FA bool `json:"enable2fa"` //Enable 2FA
parent *SSOHandler //Parent SSO handler Subdomains map[string]*SubdomainAccessRule `json:"subdomains"` //Subdomain access rules
LastLogin int64 `json:"lastlogin"` //Last login time
LastLoginIP string `json:"lastloginip"` //Last login IP
LastLoginCountry string `json:"lastlogincountry"` //Last login country
parent *SSOHandler //Parent SSO handler
}
type ClientResponse struct {
Sub string `json:"sub"` //User ID
Name string `json:"name"` //Username
Nickname string `json:"nickname"` //Nickname
PreferredUsername string `json:"preferred_username"` //Preferred Username
Email string `json:"email"` //Email
Locale string `json:"locale"` //Locale
Website string `json:"website"` //Website
} }
func (s *SSOHandler) SSOUserExists(userid string) bool { func (s *SSOHandler) SSOUserExists(userid string) bool {
@ -113,3 +127,15 @@ func (u *UserEntry) VerifyTotp(enteredCode string) bool {
totp := gotp.NewDefaultTOTP(u.TOTPCode) totp := gotp.NewDefaultTOTP(u.TOTPCode)
return totp.Verify(enteredCode, time.Now().Unix()) return totp.Verify(enteredCode, time.Now().Unix())
} }
func (u *UserEntry) GetClientResponse() ClientResponse {
return ClientResponse{
Sub: u.UserID,
Name: u.Username,
Nickname: u.Username,
PreferredUsername: u.Username,
Email: u.Email,
Locale: "en",
Website: "",
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

67
src/mod/geodb/locale.go Normal file
View File

@ -0,0 +1,67 @@
package geodb
import "net/http"
// GetRequesterCountryISOCode get the locale of the requester
func (s *Store) GetLocaleFromRequest(r *http.Request) (string, error) {
cc := s.GetRequesterCountryISOCode(r)
return GetLocaleFromCountryCode(cc), nil
}
// GetLocaleFromCountryCode get the locale given the country code
func GetLocaleFromCountryCode(cc string) string {
//If you find your country is not in the list, please add it here
mapCountryToLocale := map[string]string{
"aa": "ar_AA",
"by": "be_BY",
"bg": "bg_BG",
"es": "ca_ES",
"cz": "cs_CZ",
"dk": "da_DK",
"ch": "de_CH",
"de": "de_DE",
"gr": "el_GR",
"au": "en_AU",
"be": "en_BE",
"gb": "en_GB",
"jp": "en_JP",
"us": "en_US",
"za": "en_ZA",
"fi": "fi_FI",
"ca": "fr_CA",
"fr": "fr_FR",
"hr": "hr_HR",
"hu": "hu_HU",
"is": "is_IS",
"it": "it_IT",
"il": "iw_IL",
"kr": "ko_KR",
"lt": "lt_LT",
"lv": "lv_LV",
"mk": "mk_MK",
"nl": "nl_NL",
"no": "no_NO",
"pl": "pl_PL",
"br": "pt_BR",
"pt": "pt_PT",
"ro": "ro_RO",
"ru": "ru_RU",
"sp": "sh_SP",
"sk": "sk_SK",
"sl": "sl_SL",
"al": "sq_AL",
"se": "sv_SE",
"th": "th_TH",
"tr": "tr_TR",
"ua": "uk_UA",
"cn": "zh_CN",
"tw": "zh_TW",
"hk": "zh_HK",
}
locale, ok := mapCountryToLocale[cc]
if !ok {
return "en-US"
}
return locale
}

View File

@ -129,7 +129,6 @@ func startupSequence() {
} }
//Create an SSO handler //Create an SSO handler
sysdb.NewTable("sso_conf")
ssoHandler, err = sso.NewSSOHandler(&sso.SSOConfig{ ssoHandler, err = sso.NewSSOHandler(&sso.SSOConfig{
SystemUUID: nodeUUID, SystemUUID: nodeUUID,
PortalServerPort: 5488, PortalServerPort: 5488,

View File

@ -8,12 +8,12 @@
<i class="circle check icon"></i> <i class="circle check icon"></i>
<div class="content"> <div class="content">
<span class="webserv_status">Running</span> <span class="webserv_status">Running</span>
<div class="sub header">Listen port :<span class="webserv_port">8081</span></div> <div class="sub header">Listen port :<span class="oauthserv_port">8081</span></div>
</div> </div>
</h4> </h4>
</div> </div>
<div class="ui form"> <div class="ui form">
<h4 class="ui dividing header">Oauth2 Server</h4> <h3 class="ui dividing header">Oauth2 Server Settings</h3>
<div class="field"> <div class="field">
<div class="ui toggle checkbox"> <div class="ui toggle checkbox">
<input type="checkbox" name="enableOauth2"> <input type="checkbox" name="enableOauth2">
@ -29,6 +29,35 @@
</div> </div>
<small>Listening port of the Zoraxy internal Oauth2 Server.You can create a subdomain proxy rule to <code>127.0.0.1:<span class="ssoPort">5488</span></code></small> <small>Listening port of the Zoraxy internal Oauth2 Server.You can create a subdomain proxy rule to <code>127.0.0.1:<span class="ssoPort">5488</span></code></small>
</div> </div>
<div class="field">
<label>Auth URL</label>
<div class="ui action input">
<input type="text" name="authURL" placeholder="https://auth.yourdomain.com">
<button id="saveAuthURLBtn" class="ui basic blue button"><i class="ui blue save icon"></i> Save</button>
</div>
<small>The exposed authentication URL of the Oauth2 server, usually <code>https://auth.example.com</code> or <code>https://sso.yourdomain.com</code>. <b>Remember to include the http:// or https:// in your URL.</b></small>
</div>
</div>
<br>
<div class="ui form">
<h3 class="ui dividing header">Zoraxy SSO Settings</h3>
<div class="field">
<label>Default Redirection URL </label>
<div class="ui fluid input">
<input type="text" name="defaultSiteURL" placeholder="https://yourdomain.com">
</div>
<small>The default URL to redirect to after login if redirection target is not set</small>
</div>
<button class="ui basic button"> <i class="ui green check icon"></i> Apply Changes </button>
</div>
<div class="ui basic message">
<div class="header">
<i class="ui yellow exclamation triangle icon"></i> Important Notes about Zoraxy SSO
</div>
<p>Zoraxy SSO, if enabled in HTTP Proxy rule, will automatically intercept the proxy request and provide an SSO interface on upstreams that do not support OAuth natively.
It is basically like basic auth with a login page. <b> The same user credential can be used in OAuth sign-in and Zoraxy SSO sign-in.</b>
</p>
</div> </div>
<div class="ui divider"></div> <div class="ui divider"></div>
<div> <div>
@ -39,6 +68,26 @@
<div class="sub header">A list of users that are registered with the SSO server</div> <div class="sub header">A list of users that are registered with the SSO server</div>
</div> </div>
</h3> </h3>
<table class="ui celled table">
<thead>
<tr>
<th>Username</th>
<th>Registered On</th>
<th>Reset Password</th>
<th>Remove</th>
</tr>
</thead>
<tbody id="registeredSsoUsers">
<tr>
<td>admin</td>
<td>2020-01-01</td>
<td><button class="ui blue basic small icon button"><i class="ui blue key icon"></i></button></td>
<td><button class="ui red basic small icon button"><i class="ui red trash icon"></i></button></td>
</tr>
</tbody>
</table>
<button onclick="handleUserListRefresh();" class="ui basic right floated button"><i class="ui green refresh icon"></i> Refresh</button>
<button onclick="openRegisteredUserManager();" class="ui basic button"><i class="ui blue users icon"></i> Manage Registered Users</button>
</div> </div>
<div class="ui divider"></div> <div class="ui divider"></div>
<div> <div>
@ -49,6 +98,28 @@
<div class="sub header">A list of apps that are registered with the SSO server</div> <div class="sub header">A list of apps that are registered with the SSO server</div>
</div> </div>
</h3> </h3>
<table class="ui celled table">
<thead>
<tr>
<th>App Name</th>
<th>Domain</th>
<th>App ID</th>
<th>Registered On</th>
<th>Remove</th>
</tr>
</thead>
<tbody id="registeredSsoApps">
<tr>
<td>My App</td>
<td><a href="//example.com" target="_blank">example.com</a></td>
<td>123456</td>
<td>2020-01-01</td>
<td><button class="ui red basic small icon button"><i class="ui red trash icon"></i></button></td>
</tr>
</tbody>
</table>
<button onclick="handleRegisterAppListRefresh();" class="ui basic right floated button"><i class="ui green refresh icon"></i> Refresh</button>
<button onclick="openRegisterAppManagementSnippet();" class="ui basic button"><i style="font-size: 1em; margin-top: -0.2em;" class="ui green th large icon"></i> Manage Registered App</button>
<p></p> <p></p>
</div> </div>
</div> </div>
@ -59,7 +130,7 @@
$(".ssoPort").text($(this).val()); $(".ssoPort").text($(this).val());
}); });
function initSSOStatus(){ function updateSSOStatus(){
$.get("/api/sso/status", function(data){ $.get("/api/sso/status", function(data){
if(data.error != undefined){ if(data.error != undefined){
//Show error message //Show error message
@ -70,35 +141,229 @@
$(".ssoRunningState").addClass("enabled"); $(".ssoRunningState").addClass("enabled");
$("#ssoRunningState .webserv_status").html('Running'); $("#ssoRunningState .webserv_status").html('Running');
$(".ssoRunningState i").attr("class", "circle check icon"); $(".ssoRunningState i").attr("class", "circle check icon");
$("input[name=enableOauth2]").parent().checkbox("set checked");
}else{ }else{
$(".ssoRunningState").removeClass("enabled"); $(".ssoRunningState").removeClass("enabled");
$("#ssoRunningState .webserv_status").html('Stopped'); $("#ssoRunningState .webserv_status").html('Stopped');
$(".ssoRunningState i").attr("class", "circle times icon"); $(".ssoRunningState i").attr("class", "circle times icon");
$("input[name=enableOauth2]").parent().checkbox("set unchecked");
} }
$("input[name=enableZoraxySSO]").prop("checked", data.Enabled);
$("input[name=oauth2Port]").val(data.ListeningPort); $("input[name=oauth2Port]").val(data.ListeningPort);
$(".oauthserv_port").text(data.ListeningPort);
$("input[name=authURL]").val(data.AuthURL);
} }
}); });
} }
function initSSOStatus(){
$.get("/api/sso/status", function(data){
//Update the SSO status from the server
updateSSOStatus();
//Bind events to the enable checkbox
$("input[name=enableOauth2]").off("change").on("change", function(){
var checked = $(this).prop("checked");
$.cjax({
url: "/api/sso/enable",
method: "POST",
data: {
enable: checked
},
success: function(data){
if(data.error != undefined){
msgbox("Failed to toggle SSO: " + data.error, false);
//Unbind the event to prevent infinite loop
$("input[name=enableOauth2]").off("change");
}else{
initSSOStatus();
}
}
});
});
});
}
initSSOStatus(); initSSOStatus();
$("#saveOauthServerPortBtn").on("click", function() { /* Save the Oauth server port */
function saveOauthServerPort(){
var port = $("input[name=oauth2Port]").val(); var port = $("input[name=oauth2Port]").val();
//Check if the port is valid
if (port < 1 || port > 65535){
msgbox("Invalid port number", false);
return;
}
//Use cjax to send the port to the server with csrf token //Use cjax to send the port to the server with csrf token
$.cjax({ $.cjax({
url: "/api/sso/oauth2/setPort", url: "/api/sso/setPort",
method: "POST", method: "POST",
data: { data: {
port: port port: port
}, },
success: function(data) { success: function(data) {
if (data.error != undefined) { if (data.error != undefined) {
msgbox("Oauth server port updated", true); msgbox("Failed to update Oauth server port: " + data.error, false);
} else { } else {
msgbox("Failed to update Oauth server port", false); msgbox("Oauth server port updated", true);
}
updateSSOStatus();
}
});
}
//Bind the save button to the saveOauthServerPort function
$("#saveOauthServerPortBtn").on("click", function() {
saveOauthServerPort();
});
$("input[name=oauth2Port]").on("keypress", function(e) {
if (e.which == 13) {
saveOauthServerPort();
}
});
/* Save the Oauth server URL (aka AuthURL) */
function saveAuthURL(){
var url = $("input[name=authURL]").val();
//Make sure the url contains http:// or https://
if (!url.startsWith("http://") && !url.startsWith("https://")){
msgbox("Invalid URL. Make sure to include http:// or https://", false);
$("input[name=authURL]").parent().parent().addClass("error");
return;
}else{
$("input[name=authURL]").parent().parent().removeClass("error");
}
//Use cjax to send the port to the server with csrf token
$.cjax({
url: "/api/sso/setAuthURL",
method: "POST",
data: {
"auth_url": url
},
success: function(data) {
if (data.error != undefined) {
msgbox("Failed to update Oauth server port: " + data.error, false);
} else {
msgbox("Oauth server port updated", true);
}
updateSSOStatus();
}
});
}
//Bind the save button to the saveAuthURL function
$("#saveAuthURLBtn").on("click", function() {
saveAuthURL();
});
$("input[name=authURL]").on("keypress", function(e) {
if (e.which == 13) {
saveAuthURL();
}
});
/* Registered Apps Event Handlers */
//Function to initialize the registered app table
function initRegisteredAppTable(){
$.get("/api/sso/app/list", function(data){
if(data.error != undefined){
msgbox("Failed to get registered apps: " + data.error, false);
}else{
var tbody = $("#registeredSsoApps");
tbody.empty();
for(var i = 0; i < data.length; i++){
var app = data[i];
var tr = $("<tr>");
tr.append($("<td>").text(app.AppName));
tr.append($("<td>").html('<a href="//'+app.Domain+'" target="_blank">'+app.Domain+'</a>'));
tr.append($("<td>").text(app.AppID));
tr.append($("<td>").text(app.RegisteredOn));
var removeBtn = $("<button>").addClass("ui red basic small icon button").html('<i class="ui red trash icon"></i>');
removeBtn.on("click", function(){
removeApp(app.AppID);
});
tr.append($("<td>").append(removeBtn));
tbody.append(tr);
}
if (data.length == 0){
tbody.append($("<tr>").append($("<td>").attr("colspan", 4).html(`<i class="ui green circle check icon"></i> No registered users`)));
} }
} }
}); });
}); }
initRegisteredAppTable();
//Also bind the refresh button to the initRegisteredAppTable function
function handleRegisterAppListRefresh(){
initRegisteredAppTable();
}
function openRegisterAppManagementSnippet(){
//Open the register app management snippet
showSideWrapper("snippet/sso_app.html");
}
//Bind the remove button to the removeApp function
function removeApp(appID){
$.cjax({
url: "/api/sso/removeApp",
method: "POST",
data: {
appID: appID
},
success: function(data){
if(data.error != undefined){
msgbox("Failed to remove app: " + data.error, false);
}else{
msgbox("App removed", true);
updateSSOStatus();
}
}
});
}
/* Registered Users Event Handlers */
function initUserList(){
$.get("/api/sso/user/list", function(data){
if(data.error != undefined){
msgbox("Failed to get registered users: " + data.error, false);
}else{
var tbody = $("#registeredSsoUsers");
tbody.empty();
for(var i = 0; i < data.length; i++){
var user = data[i];
var tr = $("<tr>");
tr.append($("<td>").text(user.Username));
tr.append($("<td>").text(user.RegisteredOn));
var resetBtn = $("<button>").addClass("ui blue basic small icon button").html('<i class="ui blue key icon"></i>');
resetBtn.on("click", function(){
resetPassword(user.Username);
});
tr.append($("<td>").append(resetBtn));
var removeBtn = $("<button>").addClass("ui red basic small icon button").html('<i class="ui red trash icon"></i>');
removeBtn.on("click", function(){
removeUser(user.Username);
});
tr.append($("<td>").append(removeBtn));
tbody.append(tr);
}
if (data.length == 0){
tbody.append($("<tr>").append($("<td>").attr("colspan", 4).html(`<i class="ui green circle check icon"></i> No registered users`)));
}
}
});
}
//Bind the refresh button to the initUserList function
function handleUserListRefresh(){
initUserList();
}
function openRegisteredUserManager(){
//Open the registered user management snippet
showSideWrapper("snippet/sso_user.html");
}
</script> </script>

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
<style>
body{
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<br>
<div class="ui container">
<div class="ui basic segment">
<h2 class="ui header">SSO App Management</h2>
<div class="ui divider"></div>
<h3>Work in progress</h3>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
<link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script>
<script src="../script/utils.js"></script>
<style>
body{
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<br>
<div class="ui container">
<div class="ui basic segment">
<h2 class="ui header">SSO User Management</h2>
<div class="ui divider"></div>
<h3>Work in progress</h3>
</div>
</div>
</body>
</html>