mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-08-07 05:38:30 +02:00
Fixed #316
Fixed early renew day not passed into auto renewer config bug
This commit is contained in:
@@ -37,16 +37,46 @@ func (s *SSOHandler) HandleSSOStatus(w http.ResponseWriter, r *http.Request) {
|
||||
utils.SendJSONResponse(w, string(js))
|
||||
}
|
||||
|
||||
// HandleStartSSOPortal handle the request to start the SSO portal server
|
||||
func (s *SSOHandler) HandleStartSSOPortal(w http.ResponseWriter, r *http.Request) {
|
||||
err := s.StartSSOPortal()
|
||||
// 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 {
|
||||
s.Log("Failed to start SSO portal server", err)
|
||||
utils.SendErrorResponse(w, "failed to start SSO portal server")
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
|
58
src/mod/auth/sso/openid.go
Normal file
58
src/mod/auth/sso/openid.go
Normal 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)
|
||||
}
|
@@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/go-oauth2/oauth2/v4/errors"
|
||||
"imuslab.com/zoraxy/mod/utils"
|
||||
)
|
||||
|
||||
@@ -30,21 +31,26 @@ func (h *SSOHandler) InitSSOPortal(portalServerPort int) {
|
||||
//Register API endpoint for the SSO portal
|
||||
pmux.HandleFunc("/sso/login", h.HandleLogin)
|
||||
|
||||
//Register API endpoint for autodiscovery
|
||||
pmux.HandleFunc("/.well-known/openid-configuration", h.HandleDiscoveryRequest)
|
||||
|
||||
//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 +65,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
|
||||
|
@@ -23,13 +23,27 @@ type SubdomainAccessRule struct {
|
||||
}
|
||||
|
||||
type UserEntry struct {
|
||||
UserID string //User ID, in UUIDv4 format
|
||||
Username string //Username
|
||||
PasswordHash string //Password hash
|
||||
TOTPCode string //2FA TOTP code
|
||||
Enable2FA bool //Enable 2FA for this user
|
||||
Subdomains map[string]*SubdomainAccessRule //Subdomain and access rule
|
||||
parent *SSOHandler //Parent SSO handler
|
||||
UserID string `json:sub` //User ID
|
||||
Username string `json:"name"` //Username
|
||||
Email string `json:"email"` //Email
|
||||
PasswordHash string `json:"passwordhash"` //Password hash
|
||||
TOTPCode string `json:"totpcode"` //TOTP code
|
||||
Enable2FA bool `json:"enable2fa"` //Enable 2FA
|
||||
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 {
|
||||
@@ -113,3 +127,15 @@ func (u *UserEntry) VerifyTotp(enteredCode string) bool {
|
||||
totp := gotp.NewDefaultTOTP(u.TOTPCode)
|
||||
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: "",
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user