From 182850ee4401a79f283ddf04f2907cac8d36c672 Mon Sep 17 00:00:00 2001 From: Marcel Jacek Date: Fri, 21 Mar 2025 15:25:44 +0100 Subject: [PATCH 1/4] add new STACKIT logo --- .../pkg/auth/templates/login-successful.html | 2 +- .../auth/templates/stackit_nav_logo_light.svg | 11 +++++++++++ internal/pkg/auth/user_login.go | 17 ++++++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 internal/pkg/auth/templates/stackit_nav_logo_light.svg diff --git a/internal/pkg/auth/templates/login-successful.html b/internal/pkg/auth/templates/login-successful.html index 45cf2721c..1e312e5cb 100644 --- a/internal/pkg/auth/templates/login-successful.html +++ b/internal/pkg/auth/templates/login-successful.html @@ -271,7 +271,7 @@ diff --git a/internal/pkg/auth/templates/stackit_nav_logo_light.svg b/internal/pkg/auth/templates/stackit_nav_logo_light.svg new file mode 100644 index 000000000..5da793e0b --- /dev/null +++ b/internal/pkg/auth/templates/stackit_nav_logo_light.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/internal/pkg/auth/user_login.go b/internal/pkg/auth/user_login.go index b8a706a51..2c4dbaf61 100644 --- a/internal/pkg/auth/user_login.go +++ b/internal/pkg/auth/user_login.go @@ -30,6 +30,8 @@ const ( stackitLandingPage = "https://www.stackit.de" htmlTemplatesPath = "templates" loginSuccessfulHTMLFile = "login-successful.html" + logoPath = "/stackit_nav_logo_light.svg" + logoSVGFilePath = "stackit_nav_logo_light.svg" // The IDP doesn't support wildcards for the port, // so we configure a range of ports from 8000 to 8020 @@ -208,7 +210,6 @@ func AuthorizeUser(p *print.Printer, isReauthentication bool) error { }) mux.HandleFunc(loginSuccessPath, func(w http.ResponseWriter, _ *http.Request) { - defer cleanup(server) email, err := GetAuthField(USER_EMAIL) if err != nil { @@ -232,6 +233,20 @@ func AuthorizeUser(p *print.Printer, isReauthentication bool) error { } }) + mux.HandleFunc(logoPath, func(w http.ResponseWriter, _ *http.Request) { + defer cleanup(server) + + img, err := htmlContent.ReadFile(path.Join(htmlTemplatesPath, logoSVGFilePath)) + if err != nil { + errServer = fmt.Errorf("read logo file: %w", err) + } + w.Header().Set("Content-Type", "image/svg+xml") + _, err = w.Write(img) + if err != nil { + return + } + }) + p.Debug(print.DebugLevel, "opening browser for authentication: %s", authorizationURL) p.Debug(print.DebugLevel, "using authentication server on %s", idpWellKnownConfig.Issuer) p.Debug(print.DebugLevel, "using client ID %s for authentication ", idpClientID) From 97ce2f76ded987b8b866c07782cd21e15c627bec Mon Sep 17 00:00:00 2001 From: Marcel Jacek Date: Fri, 21 Mar 2025 15:37:07 +0100 Subject: [PATCH 2/4] fix linter --- internal/pkg/auth/user_login.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/pkg/auth/user_login.go b/internal/pkg/auth/user_login.go index 2c4dbaf61..a3d7deab2 100644 --- a/internal/pkg/auth/user_login.go +++ b/internal/pkg/auth/user_login.go @@ -210,7 +210,6 @@ func AuthorizeUser(p *print.Printer, isReauthentication bool) error { }) mux.HandleFunc(loginSuccessPath, func(w http.ResponseWriter, _ *http.Request) { - email, err := GetAuthField(USER_EMAIL) if err != nil { errServer = fmt.Errorf("read user email: %w", err) From 05e75936ce0c0175d52eda523a55483693c88ea9 Mon Sep 17 00:00:00 2001 From: Marcel Jacek Date: Fri, 21 Mar 2025 17:08:38 +0100 Subject: [PATCH 3/4] add logo as base64 to the login-successful.html instead of adding an extra handleFunc - add go:embed - removed unused variables --- .../pkg/auth/templates/login-successful.html | 2 +- internal/pkg/auth/user_login.go | 51 +++++++++---------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/internal/pkg/auth/templates/login-successful.html b/internal/pkg/auth/templates/login-successful.html index 1e312e5cb..d8519cad0 100644 --- a/internal/pkg/auth/templates/login-successful.html +++ b/internal/pkg/auth/templates/login-successful.html @@ -271,7 +271,7 @@ diff --git a/internal/pkg/auth/user_login.go b/internal/pkg/auth/user_login.go index a3d7deab2..6c09d69da 100644 --- a/internal/pkg/auth/user_login.go +++ b/internal/pkg/auth/user_login.go @@ -1,7 +1,8 @@ package auth import ( - "embed" + _ "embed" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -11,7 +12,6 @@ import ( "net/http" "os" "os/exec" - "path" "runtime" "strconv" "strings" @@ -26,12 +26,7 @@ const ( defaultWellKnownConfig = "https://accounts.stackit.cloud/.well-known/openid-configuration" defaultCLIClientID = "stackit-cli-0000-0000-000000000001" - loginSuccessPath = "/login-successful" - stackitLandingPage = "https://www.stackit.de" - htmlTemplatesPath = "templates" - loginSuccessfulHTMLFile = "login-successful.html" - logoPath = "/stackit_nav_logo_light.svg" - logoSVGFilePath = "stackit_nav_logo_light.svg" + loginSuccessPath = "/login-successful" // The IDP doesn't support wildcards for the port, // so we configure a range of ports from 8000 to 8020 @@ -39,11 +34,15 @@ const ( configuredPortRange = 20 ) -//go:embed templates/* -var htmlContent embed.FS +//go:embed templates/login-successful.html +var htmlTemplateContent string -type User struct { +//go:embed templates/stackit_nav_logo_light.svg +var logoSvgContent []byte + +type InputValues struct { Email string + Logo string } type apiClient interface { @@ -210,42 +209,31 @@ func AuthorizeUser(p *print.Printer, isReauthentication bool) error { }) mux.HandleFunc(loginSuccessPath, func(w http.ResponseWriter, _ *http.Request) { + defer cleanup(server) + email, err := GetAuthField(USER_EMAIL) if err != nil { errServer = fmt.Errorf("read user email: %w", err) } - user := User{ + input := InputValues{ Email: email, + Logo: base64Encode(logoSvgContent), } // ParseFS expects paths using forward slashes, even on Windows // See: https://github.com/golang/go/issues/44305#issuecomment-780111748 - htmlTemplate, err := template.ParseFS(htmlContent, path.Join(htmlTemplatesPath, loginSuccessfulHTMLFile)) + htmlTemplate, err := template.New("loginSuccess").Parse(htmlTemplateContent) if err != nil { errServer = fmt.Errorf("parse html file: %w", err) } - err = htmlTemplate.Execute(w, user) + err = htmlTemplate.Execute(w, input) if err != nil { errServer = fmt.Errorf("render page: %w", err) } }) - mux.HandleFunc(logoPath, func(w http.ResponseWriter, _ *http.Request) { - defer cleanup(server) - - img, err := htmlContent.ReadFile(path.Join(htmlTemplatesPath, logoSVGFilePath)) - if err != nil { - errServer = fmt.Errorf("read logo file: %w", err) - } - w.Header().Set("Content-Type", "image/svg+xml") - _, err = w.Write(img) - if err != nil { - return - } - }) - p.Debug(print.DebugLevel, "opening browser for authentication: %s", authorizationURL) p.Debug(print.DebugLevel, "using authentication server on %s", idpWellKnownConfig.Issuer) p.Debug(print.DebugLevel, "using client ID %s for authentication ", idpClientID) @@ -272,6 +260,13 @@ func AuthorizeUser(p *print.Printer, isReauthentication bool) error { return nil } +// base64Encode encodes a []byte to a base64 representation as string +func base64Encode(message []byte) string { + b := make([]byte, base64.StdEncoding.EncodedLen(len(message))) + base64.StdEncoding.Encode(b, message) + return string(b) +} + // getUserAccessAndRefreshTokens trades the authorization code retrieved from the first OAuth2 leg for an access token and a refresh token func getUserAccessAndRefreshTokens(idpWellKnownConfig *wellKnownConfig, clientID, codeVerifier, authorizationCode, callbackURL string) (accessToken, refreshToken string, err error) { // Set form-encoded data for the POST to the access token endpoint From de33ef8be6f7e9a856b316d291e81337c70c9d0e Mon Sep 17 00:00:00 2001 From: Marcel Jacek Date: Fri, 21 Mar 2025 17:16:27 +0100 Subject: [PATCH 4/4] move base64Encode function to utils --- internal/pkg/auth/user_login.go | 11 ++--------- internal/pkg/utils/utils.go | 8 ++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/internal/pkg/auth/user_login.go b/internal/pkg/auth/user_login.go index 6c09d69da..8ac94743e 100644 --- a/internal/pkg/auth/user_login.go +++ b/internal/pkg/auth/user_login.go @@ -2,7 +2,6 @@ package auth import ( _ "embed" - "encoding/base64" "encoding/json" "errors" "fmt" @@ -17,6 +16,7 @@ import ( "strings" "time" + "github.com/stackitcloud/stackit-cli/internal/pkg/utils" "golang.org/x/oauth2" "github.com/stackitcloud/stackit-cli/internal/pkg/print" @@ -218,7 +218,7 @@ func AuthorizeUser(p *print.Printer, isReauthentication bool) error { input := InputValues{ Email: email, - Logo: base64Encode(logoSvgContent), + Logo: utils.Base64Encode(logoSvgContent), } // ParseFS expects paths using forward slashes, even on Windows @@ -260,13 +260,6 @@ func AuthorizeUser(p *print.Printer, isReauthentication bool) error { return nil } -// base64Encode encodes a []byte to a base64 representation as string -func base64Encode(message []byte) string { - b := make([]byte, base64.StdEncoding.EncodedLen(len(message))) - base64.StdEncoding.Encode(b, message) - return string(b) -} - // getUserAccessAndRefreshTokens trades the authorization code retrieved from the first OAuth2 leg for an access token and a refresh token func getUserAccessAndRefreshTokens(idpWellKnownConfig *wellKnownConfig, clientID, codeVerifier, authorizationCode, callbackURL string) (accessToken, refreshToken string, err error) { // Set form-encoded data for the POST to the access token endpoint diff --git a/internal/pkg/utils/utils.go b/internal/pkg/utils/utils.go index a8b2a31b3..5649155cd 100644 --- a/internal/pkg/utils/utils.go +++ b/internal/pkg/utils/utils.go @@ -1,6 +1,7 @@ package utils import ( + "encoding/base64" "fmt" "net/url" "strings" @@ -116,3 +117,10 @@ func PtrByteSizeDefault(size *int64, defaultValue string) string { } return bytesize.New(float64(*size)).String() } + +// Base64Encode encodes a []byte to a base64 representation as string +func Base64Encode(message []byte) string { + b := make([]byte, base64.StdEncoding.EncodedLen(len(message))) + base64.StdEncoding.Encode(b, message) + return string(b) +}