mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-05-31 04:37:20 +02:00
feat: forward auth
This adds basic support for forwarded authentication similar to caddy and traefik. This replaces Authelia SSO as it effectively covers exactly the same use cases.
This commit is contained in:
parent
0e5550487e
commit
8f046a0b47
@ -80,10 +80,9 @@ func RegisterTLSAPIs(authRouter *auth.RouterDef) {
|
||||
authRouter.HandleFunc("/api/cert/delete", handleCertRemove)
|
||||
}
|
||||
|
||||
// Register the APIs for Authentication handlers like Authelia and OAUTH2
|
||||
// Register the APIs for Authentication handlers like Forward Auth and OAUTH2
|
||||
func RegisterAuthenticationHandlerAPIs(authRouter *auth.RouterDef) {
|
||||
authRouter.HandleFunc("/api/sso/Authelia", autheliaRouter.HandleSetAutheliaURLAndHTTPS)
|
||||
authRouter.HandleFunc("/api/sso/Authentik", authentikRouter.HandleSetAuthentikURLAndHTTPS)
|
||||
authRouter.HandleFunc("/api/sso/forward-auth", forwardAuthRouter.HandleAPIOptions)
|
||||
}
|
||||
|
||||
// Register the APIs for redirection rules management functions
|
||||
|
12
src/def.go
12
src/def.go
@ -13,12 +13,10 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"imuslab.com/zoraxy/mod/auth/sso/authentik"
|
||||
|
||||
"imuslab.com/zoraxy/mod/access"
|
||||
"imuslab.com/zoraxy/mod/acme"
|
||||
"imuslab.com/zoraxy/mod/auth"
|
||||
"imuslab.com/zoraxy/mod/auth/sso/authelia"
|
||||
"imuslab.com/zoraxy/mod/auth/sso/forward"
|
||||
"imuslab.com/zoraxy/mod/database"
|
||||
"imuslab.com/zoraxy/mod/dockerux"
|
||||
"imuslab.com/zoraxy/mod/dynamicproxy/loadbalance"
|
||||
@ -43,8 +41,9 @@ import (
|
||||
|
||||
const (
|
||||
/* Build Constants */
|
||||
SYSTEM_NAME = "Zoraxy"
|
||||
SYSTEM_VERSION = "3.2.1"
|
||||
SYSTEM_NAME = "Zoraxy"
|
||||
SYSTEM_VERSION = "3.2.2"
|
||||
DEVELOPMENT_BUILD = false
|
||||
|
||||
/* System Constants */
|
||||
TMP_FOLDER = "./tmp"
|
||||
@ -144,8 +143,7 @@ var (
|
||||
pluginManager *plugins.Manager //Plugin manager for managing plugins
|
||||
|
||||
//Authentication Provider
|
||||
autheliaRouter *authelia.AutheliaRouter //Authelia router for Authelia authentication
|
||||
authentikRouter *authentik.AuthentikRouter //Authentik router for Authentik authentication
|
||||
forwardAuthRouter *forward.AuthRouter // Forward Auth router for Authelia/Authentik/etc authentication
|
||||
|
||||
//Helper modules
|
||||
EmailSender *email.Sender //Email sender that handle email sending
|
||||
|
@ -1,164 +0,0 @@
|
||||
package authelia
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"imuslab.com/zoraxy/mod/database"
|
||||
"imuslab.com/zoraxy/mod/info/logger"
|
||||
"imuslab.com/zoraxy/mod/utils"
|
||||
)
|
||||
|
||||
type AutheliaRouterOptions struct {
|
||||
UseHTTPS bool //If the Authelia server is using HTTPS
|
||||
AutheliaURL string //The URL of the Authelia server
|
||||
Logger *logger.Logger
|
||||
Database *database.Database
|
||||
}
|
||||
|
||||
type AutheliaRouter struct {
|
||||
options *AutheliaRouterOptions
|
||||
}
|
||||
|
||||
// NewAutheliaRouter creates a new AutheliaRouter object
|
||||
func NewAutheliaRouter(options *AutheliaRouterOptions) *AutheliaRouter {
|
||||
options.Database.NewTable("authelia")
|
||||
|
||||
//Read settings from database, if exists
|
||||
options.Database.Read("authelia", "autheliaURL", &options.AutheliaURL)
|
||||
options.Database.Read("authelia", "useHTTPS", &options.UseHTTPS)
|
||||
|
||||
return &AutheliaRouter{
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// HandleSetAutheliaURLAndHTTPS is the internal handler for setting the Authelia URL and HTTPS
|
||||
func (ar *AutheliaRouter) HandleSetAutheliaURLAndHTTPS(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodGet {
|
||||
//Return the current settings
|
||||
js, _ := json.Marshal(map[string]interface{}{
|
||||
"useHTTPS": ar.options.UseHTTPS,
|
||||
"autheliaURL": ar.options.AutheliaURL,
|
||||
})
|
||||
|
||||
utils.SendJSONResponse(w, string(js))
|
||||
return
|
||||
} else if r.Method == http.MethodPost {
|
||||
//Update the settings
|
||||
autheliaURL, err := utils.PostPara(r, "autheliaURL")
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, "autheliaURL not found")
|
||||
return
|
||||
}
|
||||
|
||||
useHTTPS, err := utils.PostBool(r, "useHTTPS")
|
||||
if err != nil {
|
||||
useHTTPS = false
|
||||
}
|
||||
|
||||
//Write changes to runtime
|
||||
ar.options.AutheliaURL = autheliaURL
|
||||
ar.options.UseHTTPS = useHTTPS
|
||||
|
||||
//Write changes to database
|
||||
ar.options.Database.Write("authelia", "autheliaURL", autheliaURL)
|
||||
ar.options.Database.Write("authelia", "useHTTPS", useHTTPS)
|
||||
|
||||
utils.SendOK(w)
|
||||
} else {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// handleAutheliaAuth is the internal handler for Authelia authentication
|
||||
// Set useHTTPS to true if your authelia server is using HTTPS
|
||||
// Set autheliaURL to the URL of the Authelia server, e.g. authelia.example.com
|
||||
func (ar *AutheliaRouter) HandleAutheliaAuth(w http.ResponseWriter, r *http.Request) error {
|
||||
client := &http.Client{}
|
||||
|
||||
if ar.options.AutheliaURL == "" {
|
||||
ar.options.Logger.PrintAndLog("Authelia", "Authelia URL not set", nil)
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte("500 - Internal Server Error"))
|
||||
return errors.New("authelia URL not set")
|
||||
}
|
||||
protocol := "http"
|
||||
if ar.options.UseHTTPS {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
autheliaURL := &url.URL{
|
||||
Scheme: protocol,
|
||||
Host: ar.options.AutheliaURL,
|
||||
}
|
||||
|
||||
//Make a request to Authelia to verify the request
|
||||
req, err := http.NewRequest("POST", autheliaURL.JoinPath("api", "verify").String(), nil)
|
||||
if err != nil {
|
||||
ar.options.Logger.PrintAndLog("Authelia", "Unable to create request", err)
|
||||
w.WriteHeader(401)
|
||||
return errors.New("unauthorized")
|
||||
}
|
||||
|
||||
originalURL := rOriginalHeaders(r, req)
|
||||
|
||||
// Copy cookies from the incoming request
|
||||
for _, cookie := range r.Cookies() {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
|
||||
// Making the verification request
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
ar.options.Logger.PrintAndLog("Authelia", "Unable to verify", err)
|
||||
w.WriteHeader(401)
|
||||
return errors.New("unauthorized")
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
redirectURL := autheliaURL.JoinPath()
|
||||
|
||||
query := redirectURL.Query()
|
||||
|
||||
query.Set("rd", originalURL.String())
|
||||
query.Set("rm", r.Method)
|
||||
|
||||
http.Redirect(w, r, redirectURL.String(), http.StatusSeeOther)
|
||||
return errors.New("unauthorized")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func rOriginalHeaders(r, req *http.Request) *url.URL {
|
||||
if r.RemoteAddr != "" {
|
||||
before, _, _ := strings.Cut(r.RemoteAddr, ":")
|
||||
|
||||
if ip := net.ParseIP(before); ip != nil {
|
||||
req.Header.Set("X-Forwarded-For", ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
originalURL := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: r.Host,
|
||||
Path: r.URL.Path,
|
||||
RawPath: r.URL.RawPath,
|
||||
}
|
||||
|
||||
if r.TLS != nil {
|
||||
originalURL.Scheme = "https"
|
||||
}
|
||||
|
||||
req.Header.Add("X-Forwarded-Method", r.Method)
|
||||
req.Header.Add("X-Original-URL", originalURL.String())
|
||||
|
||||
return originalURL
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
package authentik
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"imuslab.com/zoraxy/mod/database"
|
||||
"imuslab.com/zoraxy/mod/info/logger"
|
||||
"imuslab.com/zoraxy/mod/utils"
|
||||
)
|
||||
|
||||
type AuthentikRouterOptions struct {
|
||||
UseHTTPS bool //If the Authentik server is using HTTPS
|
||||
AuthentikURL string //The URL of the Authentik server
|
||||
Logger *logger.Logger
|
||||
Database *database.Database
|
||||
}
|
||||
|
||||
type AuthentikRouter struct {
|
||||
options *AuthentikRouterOptions
|
||||
}
|
||||
|
||||
// NewAuthentikRouter creates a new AuthentikRouter object
|
||||
func NewAuthentikRouter(options *AuthentikRouterOptions) *AuthentikRouter {
|
||||
options.Database.NewTable("authentik")
|
||||
|
||||
//Read settings from database, if exists
|
||||
options.Database.Read("authentik", "authentikURL", &options.AuthentikURL)
|
||||
options.Database.Read("authentik", "useHTTPS", &options.UseHTTPS)
|
||||
|
||||
return &AuthentikRouter{
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// HandleSetAuthentikURLAndHTTPS is the internal handler for setting the Authentik URL and HTTPS
|
||||
func (ar *AuthentikRouter) HandleSetAuthentikURLAndHTTPS(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodGet {
|
||||
//Return the current settings
|
||||
js, _ := json.Marshal(map[string]interface{}{
|
||||
"useHTTPS": ar.options.UseHTTPS,
|
||||
"authentikURL": ar.options.AuthentikURL,
|
||||
})
|
||||
|
||||
utils.SendJSONResponse(w, string(js))
|
||||
return
|
||||
} else if r.Method == http.MethodPost {
|
||||
//Update the settings
|
||||
AuthentikURL, err := utils.PostPara(r, "authentikURL")
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, "authentikURL not found")
|
||||
return
|
||||
}
|
||||
|
||||
useHTTPS, err := utils.PostBool(r, "useHTTPS")
|
||||
if err != nil {
|
||||
useHTTPS = false
|
||||
}
|
||||
|
||||
//Write changes to runtime
|
||||
ar.options.AuthentikURL = AuthentikURL
|
||||
ar.options.UseHTTPS = useHTTPS
|
||||
|
||||
//Write changes to database
|
||||
ar.options.Database.Write("authentik", "authentikURL", AuthentikURL)
|
||||
ar.options.Database.Write("authentik", "useHTTPS", useHTTPS)
|
||||
|
||||
utils.SendOK(w)
|
||||
} else {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// HandleAuthentikAuth is the internal handler for Authentik authentication
|
||||
// Set useHTTPS to true if your Authentik server is using HTTPS
|
||||
// Set AuthentikURL to the URL of the Authentik server, e.g. Authentik.example.com
|
||||
func (ar *AuthentikRouter) HandleAuthentikAuth(w http.ResponseWriter, r *http.Request) error {
|
||||
const outpostPrefix = "outpost.goauthentik.io"
|
||||
client := &http.Client{}
|
||||
|
||||
if ar.options.AuthentikURL == "" {
|
||||
ar.options.Logger.PrintAndLog("Authentik", "Authentik URL not set", nil)
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte("500 - Internal Server Error"))
|
||||
return errors.New("authentik URL not set")
|
||||
}
|
||||
protocol := "http"
|
||||
if ar.options.UseHTTPS {
|
||||
protocol = "https"
|
||||
}
|
||||
|
||||
authentikBaseURL := protocol + "://" + ar.options.AuthentikURL
|
||||
//Remove tailing slash if any
|
||||
authentikBaseURL = strings.TrimSuffix(authentikBaseURL, "/")
|
||||
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
reqUrl := scheme + "://" + r.Host + r.RequestURI
|
||||
// Pass request to outpost if path matches outpost prefix
|
||||
if reqPath := strings.TrimPrefix(r.URL.Path, "/"); strings.HasPrefix(reqPath, outpostPrefix) {
|
||||
req, err := http.NewRequest(r.Method, authentikBaseURL+r.RequestURI, r.Body)
|
||||
if err != nil {
|
||||
ar.options.Logger.PrintAndLog("Authentik", "Unable to create request", err)
|
||||
w.WriteHeader(401)
|
||||
return errors.New("unauthorized")
|
||||
}
|
||||
req.Header.Set("X-Original-URL", reqUrl)
|
||||
req.Header.Set("Host", r.Host)
|
||||
for _, cookie := range r.Cookies() {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
if resp, err := client.Do(req); err != nil {
|
||||
ar.options.Logger.PrintAndLog("Authentik", "Unable to pass request to Authentik outpost", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return errors.New("internal server error")
|
||||
} else {
|
||||
defer resp.Body.Close()
|
||||
for k := range resp.Header {
|
||||
w.Header().Set(k, resp.Header.Get(k))
|
||||
}
|
||||
w.WriteHeader(resp.StatusCode)
|
||||
if _, err = io.Copy(w, resp.Body); err != nil {
|
||||
ar.options.Logger.PrintAndLog("Authentik", "Unable to pass Authentik outpost response to client", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return errors.New("internal server error")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//Make a request to Authentik to verify the request
|
||||
req, err := http.NewRequest(http.MethodGet, authentikBaseURL+"/"+outpostPrefix+"/auth/nginx", nil)
|
||||
if err != nil {
|
||||
ar.options.Logger.PrintAndLog("Authentik", "Unable to create request", err)
|
||||
w.WriteHeader(401)
|
||||
return errors.New("unauthorized")
|
||||
}
|
||||
|
||||
req.Header.Set("X-Original-URL", reqUrl)
|
||||
|
||||
// Copy cookies from the incoming request
|
||||
for _, cookie := range r.Cookies() {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
|
||||
// Making the verification request
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
ar.options.Logger.PrintAndLog("Authentik", "Unable to verify", err)
|
||||
w.WriteHeader(401)
|
||||
return errors.New("unauthorized")
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
redirectURL := authentikBaseURL + "/" + outpostPrefix + "/start?rd=" + url.QueryEscape(scheme+"://"+r.Host+r.URL.String())
|
||||
http.Redirect(w, r, redirectURL, http.StatusSeeOther)
|
||||
return errors.New("unauthorized")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
44
src/mod/auth/sso/forward/const.go
Normal file
44
src/mod/auth/sso/forward/const.go
Normal file
@ -0,0 +1,44 @@
|
||||
package forward
|
||||
|
||||
import "errors"
|
||||
|
||||
const (
|
||||
LogTitle = "Forward Auth"
|
||||
|
||||
DatabaseTable = "auth_sso_forward"
|
||||
|
||||
DatabaseKeyAddress = "address"
|
||||
DatabaseKeyResponseHeaders = "responseHeaders"
|
||||
DatabaseKeyRequestExcludedCookies = "requestExcludedCookies"
|
||||
|
||||
HeaderXForwardedProto = "X-Forwarded-Proto"
|
||||
HeaderXForwardedHost = "X-Forwarded-Host"
|
||||
HeaderXForwardedFor = "X-Forwarded-For"
|
||||
HeaderXForwardedURI = "X-Forwarded-URI"
|
||||
HeaderXForwardedMethod = "X-Forwarded-Method"
|
||||
|
||||
HeaderCookie = "Cookie"
|
||||
|
||||
HeaderUpgrade = "Upgrade"
|
||||
HeaderConnection = "Connection"
|
||||
HeaderTransferEncoding = "Transfer-Encoding"
|
||||
HeaderTE = "TE"
|
||||
HeaderTrailers = "Trailers"
|
||||
HeaderKeepAlive = "Keep-Alive"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInternalServerError = errors.New("internal server error")
|
||||
ErrUnauthorized = errors.New("unauthorized")
|
||||
)
|
||||
|
||||
var (
|
||||
doNotCopyHeaders = []string{
|
||||
HeaderUpgrade,
|
||||
HeaderConnection,
|
||||
HeaderTransferEncoding,
|
||||
HeaderTE,
|
||||
HeaderTrailers,
|
||||
HeaderKeepAlive,
|
||||
}
|
||||
)
|
294
src/mod/auth/sso/forward/forward.go
Normal file
294
src/mod/auth/sso/forward/forward.go
Normal file
@ -0,0 +1,294 @@
|
||||
package forward
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"imuslab.com/zoraxy/mod/database"
|
||||
"imuslab.com/zoraxy/mod/info/logger"
|
||||
"imuslab.com/zoraxy/mod/utils"
|
||||
)
|
||||
|
||||
type AuthRouterOptions struct {
|
||||
// Address of the forward auth endpoint.
|
||||
Address string
|
||||
|
||||
// ResponseHeaders is a list of headers to be copied from the response if provided by the forward auth endpoint to
|
||||
// the request.
|
||||
ResponseHeaders []string
|
||||
|
||||
// RequestExcludedCookies is a list of cookie keys that should be removed from every request sent to the upstream.
|
||||
RequestExcludedCookies []string
|
||||
|
||||
Logger *logger.Logger
|
||||
Database *database.Database
|
||||
}
|
||||
|
||||
type AuthRouter struct {
|
||||
client *http.Client
|
||||
options *AuthRouterOptions
|
||||
}
|
||||
|
||||
// NewAuthRouter creates a new AuthRouter object
|
||||
func NewAuthRouter(options *AuthRouterOptions) *AuthRouter {
|
||||
options.Database.NewTable(DatabaseTable)
|
||||
|
||||
//Read settings from database if available.
|
||||
options.Database.Read(DatabaseTable, DatabaseKeyAddress, &options.Address)
|
||||
|
||||
responseHeaders, requestExcludedCookies := "", ""
|
||||
|
||||
options.Database.Read(DatabaseTable, DatabaseKeyResponseHeaders, responseHeaders)
|
||||
options.Database.Read(DatabaseTable, DatabaseKeyRequestExcludedCookies, requestExcludedCookies)
|
||||
|
||||
options.ResponseHeaders = strings.Split(responseHeaders, ",")
|
||||
options.RequestExcludedCookies = strings.Split(requestExcludedCookies, ",")
|
||||
|
||||
return &AuthRouter{
|
||||
client: &http.Client{
|
||||
CheckRedirect: func(r *http.Request, via []*http.Request) (err error) {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
},
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAPIOptions is the internal handler for setting the options.
|
||||
func (ar *AuthRouter) HandleAPIOptions(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
ar.handleOptionsGET(w, r)
|
||||
case http.MethodPost:
|
||||
ar.handleOptionsPOST(w, r)
|
||||
default:
|
||||
ar.handleOptionsMethodNotAllowed(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (ar *AuthRouter) handleOptionsGET(w http.ResponseWriter, r *http.Request) {
|
||||
js, _ := json.Marshal(map[string]interface{}{
|
||||
DatabaseKeyAddress: ar.options.Address,
|
||||
DatabaseKeyResponseHeaders: ar.options.ResponseHeaders,
|
||||
DatabaseKeyRequestExcludedCookies: ar.options.RequestExcludedCookies,
|
||||
})
|
||||
|
||||
utils.SendJSONResponse(w, string(js))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ar *AuthRouter) handleOptionsPOST(w http.ResponseWriter, r *http.Request) {
|
||||
// Update the settings
|
||||
address, err := utils.PostPara(r, DatabaseKeyAddress)
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, "address not found")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// These are optional fields.
|
||||
responseHeaders, _ := utils.PostPara(r, DatabaseKeyResponseHeaders)
|
||||
requestExcludedCookies, _ := utils.PostPara(r, DatabaseKeyRequestExcludedCookies)
|
||||
|
||||
// Write changes to runtime
|
||||
ar.options.Address = address
|
||||
ar.options.ResponseHeaders = strings.Split(responseHeaders, ",")
|
||||
ar.options.RequestExcludedCookies = strings.Split(requestExcludedCookies, ",")
|
||||
|
||||
// Write changes to database
|
||||
ar.options.Database.Write(DatabaseTable, DatabaseKeyAddress, address)
|
||||
ar.options.Database.Write(DatabaseTable, DatabaseKeyResponseHeaders, responseHeaders)
|
||||
ar.options.Database.Write(DatabaseTable, DatabaseKeyRequestExcludedCookies, requestExcludedCookies)
|
||||
|
||||
utils.SendOK(w)
|
||||
}
|
||||
|
||||
func (ar *AuthRouter) handleOptionsMethodNotAllowed(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// HandleAuthProviderRouting is the internal handler for Forward Auth authentication.
|
||||
func (ar *AuthRouter) HandleAuthProviderRouting(w http.ResponseWriter, r *http.Request) error {
|
||||
if ar.options.Address == "" {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
|
||||
ar.options.Logger.PrintAndLog(LogTitle, "Address not set", nil)
|
||||
|
||||
return ErrInternalServerError
|
||||
}
|
||||
|
||||
// Make a request to Authz Server to verify the request
|
||||
req, err := http.NewRequest(http.MethodGet, ar.options.Address, nil)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
|
||||
ar.options.Logger.PrintAndLog(LogTitle, "Unable to create request", err)
|
||||
|
||||
return ErrInternalServerError
|
||||
}
|
||||
|
||||
// TODO: Add opt-in support for copying the request body to the forward auth request.
|
||||
// TODO: Add support for customizing which headers are copied from the request to the forward auth request.
|
||||
headerCopyExcluded(r.Header, req.Header, nil)
|
||||
|
||||
// TODO: Add support for upstream headers.
|
||||
rSetForwardedHeaders(r, req)
|
||||
|
||||
// Make the Authz Request.
|
||||
respForwarded, err := ar.client.Do(req)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
|
||||
ar.options.Logger.PrintAndLog(LogTitle, "Unable to perform forwarded auth due to a request error", err)
|
||||
|
||||
return ErrInternalServerError
|
||||
}
|
||||
|
||||
defer respForwarded.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(respForwarded.Body)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
|
||||
ar.options.Logger.PrintAndLog(LogTitle, "Unable to read response to forward auth request", err)
|
||||
|
||||
return ErrInternalServerError
|
||||
}
|
||||
|
||||
// Responses within the 200-299 range are considered successful and allow the proxy to handle the request.
|
||||
if respForwarded.StatusCode >= http.StatusOK && respForwarded.StatusCode < http.StatusMultipleChoices {
|
||||
// TODO: Add support for copying response headers to the response (in the user agent), not just the request.
|
||||
|
||||
if len(ar.options.ResponseHeaders) != 0 {
|
||||
// If the user has specified a list of cookies to be removed from the request, deterministically remove them.
|
||||
headerCookieRedact(r, ar.options.RequestExcludedCookies)
|
||||
}
|
||||
|
||||
// Copy specific user-specified headers from the response of the forward auth request to the request sent to the
|
||||
// upstream server/next hop.
|
||||
headerCopyIncluded(respForwarded.Header, w.Header(), ar.options.ResponseHeaders)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Copy the response.
|
||||
headerCopyExcluded(respForwarded.Header, w.Header(), nil)
|
||||
|
||||
w.WriteHeader(respForwarded.StatusCode)
|
||||
if _, err = w.Write(body); err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
|
||||
ar.options.Logger.PrintAndLog(LogTitle, "Unable to write response", err)
|
||||
|
||||
return ErrInternalServerError
|
||||
}
|
||||
|
||||
return ErrUnauthorized
|
||||
}
|
||||
|
||||
func scheme(r *http.Request) string {
|
||||
if r.TLS != nil {
|
||||
return "https"
|
||||
}
|
||||
|
||||
return "http"
|
||||
}
|
||||
|
||||
func headerCookieRedact(r *http.Request, excluded []string) {
|
||||
original := r.Cookies()
|
||||
|
||||
if len(original) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var cookies []string
|
||||
|
||||
for _, cookie := range original {
|
||||
if stringInSlice(cookie.Name, excluded) {
|
||||
continue
|
||||
}
|
||||
|
||||
cookies = append(cookies, cookie.String())
|
||||
}
|
||||
|
||||
r.Header.Set(HeaderCookie, strings.Join(cookies, "; "))
|
||||
}
|
||||
|
||||
func headerCopyExcluded(original, destination http.Header, excludedHeaders []string) {
|
||||
for key, values := range original {
|
||||
// We should never copy the headers in the below list.
|
||||
if stringInSliceFold(key, doNotCopyHeaders) {
|
||||
continue
|
||||
}
|
||||
|
||||
if stringInSliceFold(key, excludedHeaders) {
|
||||
continue
|
||||
}
|
||||
|
||||
destination[key] = append(destination[key], values...)
|
||||
}
|
||||
}
|
||||
|
||||
func headerCopyIncluded(original, destination http.Header, includedHeaders []string) {
|
||||
for key, values := range original {
|
||||
// We should never copy the headers in the below list, even if they're in the list provided by a user.
|
||||
if stringInSliceFold(key, doNotCopyHeaders) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !stringInSliceFold(key, includedHeaders) {
|
||||
continue
|
||||
}
|
||||
|
||||
destination[key] = append(destination[key], values...)
|
||||
}
|
||||
}
|
||||
|
||||
func stringInSlice(needle string, haystack []string) bool {
|
||||
if len(haystack) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, v := range haystack {
|
||||
if needle == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func stringInSliceFold(needle string, haystack []string) bool {
|
||||
if len(haystack) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, v := range haystack {
|
||||
if strings.EqualFold(needle, v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func rSetForwardedHeaders(r, req *http.Request) {
|
||||
if r.RemoteAddr != "" {
|
||||
before, _, _ := strings.Cut(r.RemoteAddr, ":")
|
||||
|
||||
if ip := net.ParseIP(before); ip != nil {
|
||||
req.Header.Set(HeaderXForwardedFor, ip.String())
|
||||
}
|
||||
}
|
||||
|
||||
req.Header.Set(HeaderXForwardedMethod, r.Method)
|
||||
req.Header.Set(HeaderXForwardedProto, scheme(r))
|
||||
req.Header.Set(HeaderXForwardedHost, r.Host)
|
||||
req.Header.Set(HeaderXForwardedURI, r.URL.Path)
|
||||
}
|
@ -32,20 +32,16 @@ and return a boolean indicate if the request is written to http.ResponseWriter
|
||||
*/
|
||||
func handleAuthProviderRouting(sep *ProxyEndpoint, w http.ResponseWriter, r *http.Request, h *ProxyHandler) bool {
|
||||
requestHostname := r.Host
|
||||
if sep.AuthenticationProvider.AuthMethod == AuthMethodBasic {
|
||||
|
||||
switch sep.AuthenticationProvider.AuthMethod {
|
||||
case AuthMethodBasic:
|
||||
err := h.handleBasicAuthRouting(w, r, sep)
|
||||
if err != nil {
|
||||
h.Parent.Option.Logger.LogHTTPRequest(r, "host-http", 401, requestHostname, "")
|
||||
return true
|
||||
}
|
||||
} else if sep.AuthenticationProvider.AuthMethod == AuthMethodAuthelia {
|
||||
err := h.handleAutheliaAuth(w, r)
|
||||
if err != nil {
|
||||
h.Parent.Option.Logger.LogHTTPRequest(r, "host-http", 401, requestHostname, "")
|
||||
return true
|
||||
}
|
||||
} else if sep.AuthenticationProvider.AuthMethod == AuthMethodAuthentik {
|
||||
err := h.handleAuthentikAuth(w, r)
|
||||
case AuthMethodForward:
|
||||
err := h.handleForwardAuth(w, r)
|
||||
if err != nil {
|
||||
h.Parent.Option.Logger.LogHTTPRequest(r, "host-http", 401, requestHostname, "")
|
||||
return true
|
||||
@ -106,13 +102,9 @@ func handleBasicAuth(w http.ResponseWriter, r *http.Request, pe *ProxyEndpoint)
|
||||
return nil
|
||||
}
|
||||
|
||||
/* Authelia */
|
||||
/* Forward Auth */
|
||||
|
||||
// Handle authelia auth routing
|
||||
func (h *ProxyHandler) handleAutheliaAuth(w http.ResponseWriter, r *http.Request) error {
|
||||
return h.Parent.Option.AutheliaRouter.HandleAutheliaAuth(w, r)
|
||||
}
|
||||
|
||||
func (h *ProxyHandler) handleAuthentikAuth(w http.ResponseWriter, r *http.Request) error {
|
||||
return h.Parent.Option.AuthentikRouter.HandleAuthentikAuth(w, r)
|
||||
// Handle forward auth routing
|
||||
func (h *ProxyHandler) handleForwardAuth(w http.ResponseWriter, r *http.Request) error {
|
||||
return h.Parent.Option.ForwardAuthRouter.HandleAuthProviderRouting(w, r)
|
||||
}
|
||||
|
@ -17,12 +17,13 @@ import (
|
||||
// GetDefaultAuthenticationProvider return a default authentication provider
|
||||
func GetDefaultAuthenticationProvider() *AuthenticationProvider {
|
||||
return &AuthenticationProvider{
|
||||
AuthMethod: AuthMethodNone,
|
||||
BasicAuthCredentials: []*BasicAuthCredentials{},
|
||||
BasicAuthExceptionRules: []*BasicAuthExceptionRule{},
|
||||
BasicAuthGroupIDs: []string{},
|
||||
AutheliaURL: "",
|
||||
UseHTTPS: false,
|
||||
AuthMethod: AuthMethodNone,
|
||||
BasicAuthCredentials: []*BasicAuthCredentials{},
|
||||
BasicAuthExceptionRules: []*BasicAuthExceptionRule{},
|
||||
BasicAuthGroupIDs: []string{},
|
||||
ForwardAuthURL: "",
|
||||
ForwardAuthResponseHeaders: []string{},
|
||||
ForwardAuthRequestExcludedCookies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,13 +9,12 @@ package dynamicproxy
|
||||
*/
|
||||
import (
|
||||
_ "embed"
|
||||
"imuslab.com/zoraxy/mod/auth/sso/authentik"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"imuslab.com/zoraxy/mod/access"
|
||||
"imuslab.com/zoraxy/mod/auth/sso/authelia"
|
||||
"imuslab.com/zoraxy/mod/auth/sso/forward"
|
||||
"imuslab.com/zoraxy/mod/dynamicproxy/dpcore"
|
||||
"imuslab.com/zoraxy/mod/dynamicproxy/loadbalance"
|
||||
"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy"
|
||||
@ -64,8 +63,7 @@ type RouterOption struct {
|
||||
PluginManager *plugins.Manager //Plugin manager for handling plugin routing
|
||||
|
||||
/* Authentication Providers */
|
||||
AutheliaRouter *authelia.AutheliaRouter //Authelia router for Authelia authentication
|
||||
AuthentikRouter *authentik.AuthentikRouter //Authentik router for Authentik authentication
|
||||
ForwardAuthRouter *forward.AuthRouter
|
||||
|
||||
/* Utilities */
|
||||
Logger *logger.Logger //Logger for reverse proxy requets
|
||||
@ -141,11 +139,10 @@ type HeaderRewriteRules struct {
|
||||
type AuthMethod int
|
||||
|
||||
const (
|
||||
AuthMethodNone AuthMethod = iota //No authentication required
|
||||
AuthMethodBasic //Basic Auth
|
||||
AuthMethodAuthelia //Authelia
|
||||
AuthMethodOauth2 //Oauth2
|
||||
AuthMethodAuthentik
|
||||
AuthMethodNone AuthMethod = iota //No authentication required
|
||||
AuthMethodBasic //Basic Auth
|
||||
AuthMethodForward //Forward
|
||||
AuthMethodOauth2 //Oauth2
|
||||
)
|
||||
|
||||
type AuthenticationProvider struct {
|
||||
@ -155,9 +152,10 @@ type AuthenticationProvider struct {
|
||||
BasicAuthExceptionRules []*BasicAuthExceptionRule //Path to exclude in a basic auth enabled proxy target
|
||||
BasicAuthGroupIDs []string //Group IDs that are allowed to access this endpoint
|
||||
|
||||
/* Authelia Settings */
|
||||
AutheliaURL string //URL of the Authelia server, leave empty to use global settings e.g. authelia.example.com
|
||||
UseHTTPS bool //Whether to use HTTPS for the Authelia server
|
||||
/* Forward Auth Settings */
|
||||
ForwardAuthURL string // Full URL of the Forward Auth endpoint. Example: https://auth.example.com/api/authz/forward-auth
|
||||
ForwardAuthResponseHeaders []string // List of headers to copy from the forward auth server response to the request.
|
||||
ForwardAuthRequestExcludedCookies []string // List of cookies to exclude from the request after sending it to the forward auth server.
|
||||
}
|
||||
|
||||
// A proxy endpoint record, a general interface for handling inbound routing
|
||||
|
@ -59,7 +59,7 @@ type AuthProvider int
|
||||
const (
|
||||
AuthProviderNone AuthProvider = iota
|
||||
AuthProviderBasicAuth
|
||||
AuthProviderAuthelia
|
||||
AuthProviderForward
|
||||
AuthProviderOauth2
|
||||
)
|
||||
|
||||
|
@ -115,8 +115,7 @@ func ReverseProxtInit() {
|
||||
StatisticCollector: statisticCollector,
|
||||
WebDirectory: *path_webserver,
|
||||
AccessController: accessController,
|
||||
AutheliaRouter: autheliaRouter,
|
||||
AuthentikRouter: authentikRouter,
|
||||
ForwardAuthRouter: forwardAuthRouter,
|
||||
LoadBalancer: loadBalancer,
|
||||
PluginManager: pluginManager,
|
||||
/* Utilities */
|
||||
@ -585,11 +584,9 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
if authProviderType == 1 {
|
||||
newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodBasic
|
||||
} else if authProviderType == 2 {
|
||||
newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodAuthelia
|
||||
newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodForward
|
||||
} else if authProviderType == 3 {
|
||||
newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodOauth2
|
||||
} else if authProviderType == 4 {
|
||||
newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodAuthentik
|
||||
} else {
|
||||
newProxyEndpoint.AuthenticationProvider.AuthMethod = dynamicproxy.AuthMethodNone
|
||||
}
|
||||
|
18
src/start.go
18
src/start.go
@ -15,7 +15,7 @@ import (
|
||||
"imuslab.com/zoraxy/mod/access"
|
||||
"imuslab.com/zoraxy/mod/acme"
|
||||
"imuslab.com/zoraxy/mod/auth"
|
||||
"imuslab.com/zoraxy/mod/auth/sso/authelia"
|
||||
"imuslab.com/zoraxy/mod/auth/sso/forward"
|
||||
"imuslab.com/zoraxy/mod/database"
|
||||
"imuslab.com/zoraxy/mod/database/dbinc"
|
||||
"imuslab.com/zoraxy/mod/dockerux"
|
||||
@ -143,18 +143,10 @@ func startupSequence() {
|
||||
}
|
||||
|
||||
//Create authentication providers
|
||||
autheliaRouter = authelia.NewAutheliaRouter(&authelia.AutheliaRouterOptions{
|
||||
UseHTTPS: false, // Automatic populate in router initiation
|
||||
AutheliaURL: "", // Automatic populate in router initiation
|
||||
Logger: SystemWideLogger,
|
||||
Database: sysdb,
|
||||
})
|
||||
|
||||
authentikRouter = authentik.NewAuthentikRouter(&authentik.AuthentikRouterOptions{
|
||||
UseHTTPS: false, // Automatic populate in router initiation
|
||||
AuthentikURL: "", // Automatic populate in router initiation
|
||||
Logger: SystemWideLogger,
|
||||
Database: sysdb,
|
||||
forwardAuthRouter = forward.NewAuthRouter(&forward.AuthRouterOptions{
|
||||
Address: "",
|
||||
Logger: SystemWideLogger,
|
||||
Database: sysdb,
|
||||
})
|
||||
|
||||
//Create a statistic collector
|
||||
|
@ -185,9 +185,8 @@
|
||||
</td>
|
||||
<td data-label="" editable="true" datatype="advanced" style="width: 350px;">
|
||||
${subd.AuthenticationProvider.AuthMethod == 0x1?`<i class="ui grey key icon"></i> Basic Auth`:``}
|
||||
${subd.AuthenticationProvider.AuthMethod == 0x2?`<i class="ui blue key icon"></i> Authelia`:``}
|
||||
${subd.AuthenticationProvider.AuthMethod == 0x3?`<i class="ui yellow key icon"></i> Oauth2`:``}
|
||||
${subd.AuthenticationProvider.AuthMethod == 0x4?`<i class="ui blue key icon"></i> Authentik`:``}
|
||||
${subd.AuthenticationProvider.AuthMethod == 0x2?`<i class="ui blue key icon"></i> Forward Auth`:``}
|
||||
${subd.AuthenticationProvider.AuthMethod == 0x3?`<i class="ui yellow key icon"></i> OAuth2`:``}
|
||||
${subd.AuthenticationProvider.AuthMethod != 0x0 && subd.RequireRateLimit?"<br>":""}
|
||||
${subd.RequireRateLimit?`<i class="ui green check icon"></i> Rate Limit @ ${subd.RateLimit} req/s`:``}
|
||||
${subd.AuthenticationProvider.AuthMethod == 0x0 && !subd.RequireRateLimit?`<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Special Settings</small>`:""}
|
||||
@ -393,13 +392,7 @@
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" value="2" name="authProviderType" ${authProvider==0x2?"checked":""}>
|
||||
<label>Authelia</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui radio checkbox">
|
||||
<input type="radio" value="4" name="authProviderType" ${authProvider==0x4?"checked":""}>
|
||||
<label>Authentik</label>
|
||||
<label>Forward Auth</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,44 +14,43 @@
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui basic segment">
|
||||
<h3>Authelia</h3>
|
||||
<p>Configuration settings for Authelia authentication provider.</p>
|
||||
|
||||
<h3>Forward Auth</h3>
|
||||
<p>Configuration settings for the Forward Auth provider.</p>
|
||||
<p>The Forward Auth provider makes a subrequest to an authorization server that supports Forward Auth, then either:</p>
|
||||
<ul>
|
||||
<li>Allows the request to flow through to the backend when the authorization server responds with a 200-299 status code.</li>
|
||||
<li>Responds with the response from the authorization server.</li>
|
||||
</ul>
|
||||
<p>Example authorization servers that support this:</p>
|
||||
<ul>
|
||||
<li><a href="https://www.authelia.com" rel=”noopener noreferrer” target="_blank">Authelia</a></li>
|
||||
<li><a href="https://goauthentik.io/" rel=”noopener noreferrer” target="_blank">Authentik</a></li>
|
||||
</ul>
|
||||
<form class="ui form">
|
||||
<div class="field">
|
||||
<label for="autheliaServerUrl">Authelia Server URL</label>
|
||||
<input type="text" id="autheliaServerUrl" name="autheliaServerUrl" placeholder="Enter Authelia Server URL">
|
||||
<small>Example: auth.example.com</small>
|
||||
<label for="forwardAuthAddress">Address</label>
|
||||
<input type="text" id="forwardAuthAddress" name="forwardAuthAddress" placeholder="Enter Forward Auth Address">
|
||||
<small>The full remote address or URL of the authorization servers forward auth endpoint. <strong>Example:</strong> https://auth.example.com/authz/forward-auth</small>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" id="useHttps" name="useHttps">
|
||||
<label for="useHttps">Use HTTPS</label>
|
||||
<small>Check this if your authelia server uses HTTPS</small>
|
||||
<div class="ui advancedSSOForwardAuthOptions accordion" style="margin-top:0.6em;">
|
||||
<div class="title">
|
||||
<i class="dropdown icon"></i>
|
||||
Advanced Options
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui basic button" onclick="event.preventDefault(); updateAutheliaSettings();"><i class="green check icon"></i> Apply Change</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui basic segment">
|
||||
<h3>Authentik</h3>
|
||||
<p>Configuration settings for Authentik authentication provider.</p>
|
||||
|
||||
<form class="ui form">
|
||||
<div class="field">
|
||||
<label for="authentikServerUrl">Authentik Server URL</label>
|
||||
<input type="text" id="authentikServerUrl" name="authentikServerUrl" placeholder="Enter Authentik Server URL">
|
||||
<small>Example: auth.example.com</small>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" id="authentikUseHttps" name="useHttps">
|
||||
<label for="authentikUseHttps">Use HTTPS</label>
|
||||
<small>Check this if your Authentik server uses HTTPS</small>
|
||||
<div class="content">
|
||||
<div class="field">
|
||||
<label for="forwardAuthResponseHeaders">Response Headers</label>
|
||||
<input type="text" id="forwardAuthResponseHeaders" name="forwardAuthResponseHeaders" placeholder="Enter Forward Auth Response Headers">
|
||||
<small>Comma separated list of case-insensitive headers to copy from the authorization servers response, to the request to the backend. <strong>Example:</strong> <code>Remote-User,Remote-Groups,Remote-Email,Remote-Name</code></small>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="forwardAuthRequestExcludedCookies">Request Excluded Cookies</label>
|
||||
<input type="text" id="forwardAuthRequestExcludedCookies" name="forwardAuthRequestExcludedCookies" placeholder="Enter Forward Auth Request Excluded Cookies">
|
||||
<small>Comma separated list of case-sensitive cookie names to exclude from the request to the backend. <strong>Example:</strong> <code>authelia_session,another_session</code></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui basic button" onclick="event.preventDefault(); updateAuthentikSettings();"><i class="green check icon"></i> Apply Change</button>
|
||||
</div><br />
|
||||
<button class="ui basic button" onclick="event.preventDefault(); updateForwardAuthSettings();"><i class="green check icon"></i> Apply Change</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
@ -60,24 +59,13 @@
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$.cjax({
|
||||
url: '/api/sso/Authelia',
|
||||
url: '/api/sso/forward-auth',
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$('#autheliaServerUrl').val(data.autheliaURL);
|
||||
$('#useHttps').prop('checked', data.useHTTPS);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
console.error('Error fetching SSO settings:', textStatus, errorThrown);
|
||||
}
|
||||
});
|
||||
$.cjax({
|
||||
url: '/api/sso/Authentik',
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$('#authentikServerUrl').val(data.authentikURL);
|
||||
$('#authentikUseHttps').prop('checked', data.useHTTPS);
|
||||
$('#forwardAuthAddress').val(data.address);
|
||||
$('#forwardAuthResponseHeaders').val(data.responseHeaders.join(","));
|
||||
$('#forwardAuthRequestExcludedCookies').val(data.requestExcludedCookies.join(","));
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
console.error('Error fetching SSO settings:', textStatus, errorThrown);
|
||||
@ -85,51 +73,31 @@
|
||||
});
|
||||
});
|
||||
|
||||
function updateAutheliaSettings(){
|
||||
var autheliaServerUrl = $('#autheliaServerUrl').val();
|
||||
var useHttps = $('#useHttps').prop('checked');
|
||||
function updateForwardAuthSettings() {
|
||||
const address = $('#forwardAuthAddress').val();
|
||||
const responseHeaders = $('#forwardAuthResponseHeaders').val();
|
||||
const requestExcludedCookies = $('#forwardAuthRequestExcludedCookies').val();
|
||||
|
||||
console.log(`Updating Forward Auth settings. Address: ${address}. Response Headers: ${responseHeaders}. Request Excluded Cookies: ${requestExcludedCookies}.`);
|
||||
|
||||
$.cjax({
|
||||
url: '/api/sso/Authelia',
|
||||
url: '/api/sso/forward-auth',
|
||||
method: 'POST',
|
||||
data: {
|
||||
autheliaURL: autheliaServerUrl,
|
||||
useHTTPS: useHttps
|
||||
address: address,
|
||||
responseHeaders: responseHeaders,
|
||||
requestExcludedCookies: requestExcludedCookies
|
||||
},
|
||||
success: function(data) {
|
||||
if (data.error != undefined) {
|
||||
$.msgbox(data.error, false);
|
||||
if (data.error !== undefined) {
|
||||
msgbox(data.error, false);
|
||||
return;
|
||||
}
|
||||
msgbox('Authelia settings updated', true);
|
||||
console.log('Authelia settings updated:', data);
|
||||
msgbox('Forward Auth settings updated', true);
|
||||
console.log('Forward Auth settings updated:', data);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
console.error('Error updating Authelia settings:', textStatus, errorThrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
function updateAuthentikSettings(){
|
||||
var authentikServerUrl = $('#authentikServerUrl').val();
|
||||
var useHttps = $('#authentikUseHttps').prop('checked');
|
||||
|
||||
$.cjax({
|
||||
url: '/api/sso/Authentik',
|
||||
method: 'POST',
|
||||
data: {
|
||||
authentikURL: authentikServerUrl,
|
||||
useHTTPS: useHttps
|
||||
},
|
||||
success: function(data) {
|
||||
if (data.error != undefined) {
|
||||
$.msgbox(data.error, false);
|
||||
return;
|
||||
}
|
||||
msgbox('Authentik settings updated', true);
|
||||
console.log('Authentik settings updated:', data);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
console.error('Error updating Authentik settings:', textStatus, errorThrown);
|
||||
console.error('Error updating Forward Auth settings:', textStatus, errorThrown);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user