From 7c3b36c9ae526edd9784e7971eb68c0d169a8b51 Mon Sep 17 00:00:00 2001 From: MrMelon54 Date: Wed, 4 Oct 2023 21:53:20 +0100 Subject: [PATCH] Finish up working flow and setup test client --- cmd/lavender/conf.go | 1 + cmd/lavender/serve.go | 2 +- issuer/sso.go | 1 + server/flow-callback.go.html | 17 ++++---- server/flow-popup.go.html | 8 ++-- server/flow.go | 21 ++++++++-- server/server.go | 29 +++++++------- test-client/index.html | 75 ++++++++++++++++++++++++++++++++++++ test-client/run.sh | 2 + 9 files changed, 124 insertions(+), 32 deletions(-) create mode 100644 test-client/index.html create mode 100755 test-client/run.sh diff --git a/cmd/lavender/conf.go b/cmd/lavender/conf.go index 9637149..c9b465f 100644 --- a/cmd/lavender/conf.go +++ b/cmd/lavender/conf.go @@ -8,6 +8,7 @@ import ( type startUpConfig struct { Listen string `json:"listen"` BaseUrl string `json:"base_url"` + ServiceName string `json:"service_name"` Issuer string `json:"issuer"` SsoServices []loginServiceManager.SsoConfig `json:"sso_services"` AllowedClients []utils.JsonUrl `json:"allowed_clients"` diff --git a/cmd/lavender/serve.go b/cmd/lavender/serve.go index 30ca916..4f94ca7 100644 --- a/cmd/lavender/serve.go +++ b/cmd/lavender/serve.go @@ -77,7 +77,7 @@ func normalLoad(startUp startUpConfig, wd string) { log.Fatal("[Lavender] Failed to create SSO service manager: ", err) } - srv := server.NewHttpServer(startUp.Listen, startUp.BaseUrl, startUp.AllowedClients, manager, mSign) + srv := server.NewHttpServer(startUp.Listen, startUp.BaseUrl, startUp.ServiceName, startUp.AllowedClients, manager, mSign) log.Printf("[Lavender] Starting HTTP server on '%s'\n", srv.Addr) go utils.RunBackgroundHttp("HTTP", srv) diff --git a/issuer/sso.go b/issuer/sso.go index 2533784..f208e4f 100644 --- a/issuer/sso.go +++ b/issuer/sso.go @@ -46,6 +46,7 @@ func (s SsoConfig) FetchConfig() (*WellKnownOIDC, error) { if err != nil { return nil, err } + c.Config = s c.OAuth2Config = oauth2.Config{ ClientID: c.Config.Client.ID, ClientSecret: c.Config.Client.Secret, diff --git a/server/flow-callback.go.html b/server/flow-callback.go.html index 7c72a9d..267f6c3 100644 --- a/server/flow-callback.go.html +++ b/server/flow-callback.go.html @@ -2,20 +2,17 @@ {{.ServiceName}} + -

{{.ServiceName}}

-
Loading...
+
Loading...
diff --git a/server/flow-popup.go.html b/server/flow-popup.go.html index f809094..86c67ca 100644 --- a/server/flow-popup.go.html +++ b/server/flow-popup.go.html @@ -8,11 +8,11 @@

{{.ServiceName}}

-
- + +
- - + +
diff --git a/server/flow.go b/server/flow.go index ca7302e..c40f6b1 100644 --- a/server/flow.go +++ b/server/flow.go @@ -1,10 +1,13 @@ package server import ( + "context" _ "embed" "encoding/json" + "fmt" "github.com/google/uuid" "github.com/julienschmidt/httprouter" + "golang.org/x/oauth2" "html/template" "log" "net/http" @@ -28,6 +31,7 @@ func init() { log.Fatal("flow.go: Failed to parse flow popup HTML:", err) } flowPopupTemplate = pageParse + pageParse, err = template.New("pages").Parse(flowCallbackHtml) if err != nil { log.Fatal("flow.go: Failed to parse flow callback HTML:", err) @@ -37,7 +41,7 @@ func init() { func (h *HttpServer) flowPopup(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) { err := flowPopupTemplate.Execute(rw, map[string]any{ - "ServiceName": flowPopupTemplate, + "ServiceName": h.serviceName, "Origin": req.URL.Query().Get("origin"), }) if err != nil { @@ -46,7 +50,8 @@ func (h *HttpServer) flowPopup(rw http.ResponseWriter, req *http.Request, _ http } func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) { - login := h.manager.FindServiceFromLogin(req.PostFormValue("username")) + loginName := req.PostFormValue("loginname") + login := h.manager.FindServiceFromLogin(loginName) if login == nil { http.Error(rw, "No login service defined for this username", http.StatusBadRequest) return @@ -68,7 +73,7 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _ // generate oauth2 config and redirect to authorize URL oa2conf := login.OAuth2Config oa2conf.RedirectURL = h.baseUrl + "/callback" - nextUrl := oa2conf.AuthCodeURL(state) + nextUrl := oa2conf.AuthCodeURL(state, oauth2.SetAuthURLParam("login_name", loginName)) http.Redirect(rw, req, nextUrl, http.StatusFound) } @@ -92,14 +97,18 @@ func (h *HttpServer) flowCallback(rw http.ResponseWriter, req *http.Request, _ h return } - exchange, err := v.sso.OAuth2Config.Exchange(req.Context(), q.Get("code")) + oa2conf := v.sso.OAuth2Config + oa2conf.RedirectURL = h.baseUrl + "/callback" + exchange, err := oa2conf.Exchange(context.Background(), q.Get("code")) if err != nil { + fmt.Println("Failed exchange:", err) http.Error(rw, "Failed to exchange code", http.StatusInternalServerError) return } client := v.sso.OAuth2Config.Client(req.Context(), exchange) v2, err := client.Get(v.sso.UserInfoEndpoint) if err != nil { + fmt.Println("Failed to get userinfo:", err) http.Error(rw, "Failed to get userinfo", http.StatusInternalServerError) return } @@ -110,11 +119,15 @@ func (h *HttpServer) flowCallback(rw http.ResponseWriter, req *http.Request, _ h } var v3 any if json.NewDecoder(v2.Body).Decode(&v3) != nil { + fmt.Println("Failed to decode userinfo:", err) http.Error(rw, "Failed to decode userinfo JSON", http.StatusInternalServerError) return } + // TODO: generate signed mjwt object + _ = flowCallbackTemplate.Execute(rw, map[string]any{ + "ServiceName": h.serviceName, "TargetOrigin": v.targetOrigin, "TargetMessage": v3, }) diff --git a/server/server.go b/server/server.go index fc6b16b..f0447ad 100644 --- a/server/server.go +++ b/server/server.go @@ -12,12 +12,13 @@ import ( ) type HttpServer struct { - r *httprouter.Router - baseUrl string - manager *issuer.Manager - signer mjwt.Signer - flowState *cache.Cache[string, flowStateData] - services map[string]struct{} + r *httprouter.Router + baseUrl string + serviceName string + manager *issuer.Manager + signer mjwt.Signer + flowState *cache.Cache[string, flowStateData] + services map[string]struct{} } type flowStateData struct { @@ -25,7 +26,7 @@ type flowStateData struct { targetOrigin string } -func NewHttpServer(listen, baseUrl string, clients []utils.JsonUrl, manager *issuer.Manager, signer mjwt.Signer) *http.Server { +func NewHttpServer(listen, baseUrl, serviceName string, clients []utils.JsonUrl, manager *issuer.Manager, signer mjwt.Signer) *http.Server { r := httprouter.New() // remove last slash from baseUrl @@ -38,15 +39,17 @@ func NewHttpServer(listen, baseUrl string, clients []utils.JsonUrl, manager *iss services := make(map[string]struct{}) for _, i := range clients { - services[i.Host] = struct{}{} + services[i.String()] = struct{}{} } hs := &HttpServer{ - r: r, - baseUrl: baseUrl, - manager: manager, - signer: signer, - services: services, + r: r, + baseUrl: baseUrl, + serviceName: serviceName, + manager: manager, + signer: signer, + flowState: cache.New[string, flowStateData](), + services: services, } r.GET("/", func(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) { diff --git a/test-client/index.html b/test-client/index.html new file mode 100644 index 0000000..a6ec13a --- /dev/null +++ b/test-client/index.html @@ -0,0 +1,75 @@ + + + + Test Client + + + + +
+

Test Client

+
+
+
+ +
+
+ +
+
+ + diff --git a/test-client/run.sh b/test-client/run.sh new file mode 100755 index 0000000..60aacf8 --- /dev/null +++ b/test-client/run.sh @@ -0,0 +1,2 @@ +#!/bin/bash +python3 -m http.server 2020