Browse Source

Linked oauth server dashboard

Toby Chui 5 months ago
parent
commit
e581c51581
7 changed files with 1327 additions and 302 deletions
  1. 1 2
      api.go
  2. 48 17
      mod/auth/sso/handlers.go
  3. 11 5
      mod/auth/sso/server.go
  4. 279 179
      mod/geodb/geoipv4.csv
  5. 883 91
      mod/geodb/geoipv6.csv
  6. 0 1
      start.go
  7. 105 7
      web/components/sso.html

+ 1 - 2
api.go

@@ -97,8 +97,7 @@ func initAPIs(targetMux *http.ServeMux) {
 
 	//SSO and Oauth
 	authRouter.HandleFunc("/api/sso/status", ssoHandler.HandleSSOStatus)
-	authRouter.HandleFunc("/api/sso/start", ssoHandler.HandleStartSSOPortal)
-	authRouter.HandleFunc("/api/sso/stop", ssoHandler.HandleStopSSOPortal)
+	authRouter.HandleFunc("/api/sso/enable", ssoHandler.HandleSSOEnable)
 	authRouter.HandleFunc("/api/sso/setPort", ssoHandler.HandlePortChange)
 	authRouter.HandleFunc("/api/sso/setAuthURL", ssoHandler.HandleSetAuthURL)
 	//authRouter.HandleFunc("/api/sso/registerApp", ssoHandler.HandleRegisterApp)

+ 48 - 17
mod/auth/sso/handlers.go

@@ -37,16 +37,46 @@ func (s *SSOHandler) HandleSSOStatus(w http.ResponseWriter, r *http.Request) {
 	utils.SendJSONResponse(w, string(js))
 }
 
+// Wrapper for starting and stopping the SSO portal server
+// require POST request with key "enable" and value "true" or "false"
+func (s *SSOHandler) HandleSSOEnable(w http.ResponseWriter, r *http.Request) {
+	enable, err := utils.PostBool(r, "enable")
+	if err != nil {
+		utils.SendErrorResponse(w, "invalid enable value")
+		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) {
-	err := s.StartSSOPortal()
-	if err != nil {
-		s.Log("Failed to start SSO portal server", err)
-		utils.SendErrorResponse(w, "failed to start SSO portal server")
+	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
-	err = s.Config.Database.Write("sso_conf", "enabled", true)
+	err := s.Config.Database.Write("sso_conf", "enabled", true)
 	if err != nil {
 		utils.SendErrorResponse(w, "failed to update SSO state")
 		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
 func (s *SSOHandler) HandleStopSSOPortal(w http.ResponseWriter, r *http.Request) {
+	if s.ssoPortalServer == nil {
+		//Already disabled
+		utils.SendOK(w)
+		return
+	}
+
 	err := s.ssoPortalServer.Close()
 	if err != nil {
 		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")
 		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)
 }
 
@@ -104,11 +133,13 @@ func (s *SSOHandler) HandlePortChange(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	//Clear the cookie store and restart the server
-	err = s.RestartSSOServer()
-	if err != nil {
-		utils.SendErrorResponse(w, "failed to restart SSO server")
-		return
+	if s.IsRunning() {
+		//Restart the server if it is running
+		err = s.RestartSSOServer()
+		if err != nil {
+			utils.SendErrorResponse(w, "failed to restart SSO server")
+			return
+		}
 	}
 	utils.SendOK(w)
 }

+ 11 - 5
mod/auth/sso/server.go

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

File diff suppressed because it is too large
+ 279 - 179
mod/geodb/geoipv4.csv


File diff suppressed because it is too large
+ 883 - 91
mod/geodb/geoipv6.csv


+ 0 - 1
start.go

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

+ 105 - 7
web/components/sso.html

@@ -8,7 +8,7 @@
                 <i class="circle check icon"></i>
                 <div class="content">
                     <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>
             </h4>
         </div>
@@ -29,6 +29,14 @@
                 </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>
             </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>
         <div class="ui divider"></div>
         <div>
@@ -59,7 +67,7 @@
         $(".ssoPort").text($(this).val());
     });
 
-    function initSSOStatus(){
+    function updateSSOStatus(){
         $.get("/api/sso/status", function(data){
             if(data.error != undefined){
                 //Show error message
@@ -70,35 +78,125 @@
                     $(".ssoRunningState").addClass("enabled");
                     $("#ssoRunningState .webserv_status").html('Running');
                     $(".ssoRunningState i").attr("class", "circle check icon");
+                    $("input[name=enableOauth2]").parent().checkbox("set checked");
                 }else{
                     $(".ssoRunningState").removeClass("enabled");
                     $("#ssoRunningState .webserv_status").html('Stopped');
                     $(".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);
-
+                $(".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();
 
-    $("#saveOauthServerPortBtn").on("click", function() {
+    /* Save the Oauth server port */
+    function saveOauthServerPort(){
         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
         $.cjax({
-            url: "/api/sso/oauth2/setPort",
+            url: "/api/sso/setPort",
             method: "POST",
             data: {
                 port: port
             },
             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 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("Failed to update Oauth server port", false);
+                    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();
+        }
+    });
+    
+
 </script>

Some files were not shown because too many files changed in this diff