Skip to content

Commit 00f524f

Browse files
authored
feat(auth): check for valid urls (#1373)
relates to STACKITCLI-340
1 parent cffbc17 commit 00f524f

5 files changed

Lines changed: 46 additions & 9 deletions

File tree

internal/pkg/auth/user_login.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,12 @@ func cleanup(server *http.Server) {
340340
}()
341341
}
342342

343-
func openBrowser(pageUrl string) error {
344-
var err error
343+
func openBrowser(pageUrl string) (err error) {
344+
err = utils.ValidateURLDomain(pageUrl)
345+
if err != nil {
346+
return err
347+
}
348+
345349
switch runtime.GOOS {
346350
case "freebsd", "linux":
347351
// We need to use the windows way on WSL, otherwise we do not pass query

internal/pkg/auth/utils.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,21 @@ func parseWellKnownConfiguration(httpClient apiClient, wellKnownConfigURL string
9898
if wellKnownConfig.Issuer == "" {
9999
return nil, fmt.Errorf("found no issuer")
100100
}
101+
if utils.ValidateURLDomain(wellKnownConfig.Issuer) != nil {
102+
return nil, fmt.Errorf("issuer is invalid")
103+
}
101104
if wellKnownConfig.AuthorizationEndpoint == "" {
102105
return nil, fmt.Errorf("found no authorization endpoint")
103106
}
107+
if utils.ValidateURLDomain(wellKnownConfig.AuthorizationEndpoint) != nil {
108+
return nil, fmt.Errorf("authorization endpoint is invalid")
109+
}
104110
if wellKnownConfig.TokenEndpoint == "" {
105111
return nil, fmt.Errorf("found no token endpoint")
106112
}
113+
if utils.ValidateURLDomain(wellKnownConfig.TokenEndpoint) != nil {
114+
return nil, fmt.Errorf("token endpoint is invalid")
115+
}
107116

108117
err = SetAuthField(IDP_TOKEN_ENDPOINT, wellKnownConfig.TokenEndpoint)
109118
if err != nil {

internal/pkg/auth/utils_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ func TestParseWellKnownConfig(t *testing.T) {
133133
{
134134
name: "success",
135135
getFails: false,
136-
getResponse: `{"issuer":"issuer","authorization_endpoint":"auth","token_endpoint":"token"}`,
136+
getResponse: `{"issuer":"https://issuer.stackit.cloud/endpoint","authorization_endpoint":"https://auth.stackit.cloud/enpoint","token_endpoint":"https://token.stackit.cloud/endpoint"}`,
137137
isValid: true,
138138
expected: &wellKnownConfig{
139-
Issuer: "issuer",
140-
AuthorizationEndpoint: "auth",
141-
TokenEndpoint: "token",
139+
Issuer: "https://issuer.stackit.cloud/endpoint",
140+
AuthorizationEndpoint: "https://auth.stackit.cloud/enpoint",
141+
TokenEndpoint: "https://token.stackit.cloud/endpoint",
142142
},
143143
},
144144
{
@@ -158,21 +158,21 @@ func TestParseWellKnownConfig(t *testing.T) {
158158
{
159159
name: "missing_issuer",
160160
getFails: true,
161-
getResponse: `{"authorization_endpoint":"auth","token_endpoint":"token"}`,
161+
getResponse: `{"authorization_endpoint":"https://auth.stackit.cloud/enpoint","token_endpoint":"https://token.stackit.cloud/endpoint"}`,
162162
isValid: false,
163163
expected: nil,
164164
},
165165
{
166166
name: "missing_authorization",
167167
getFails: true,
168-
getResponse: `{"issuer":"issuer","token_endpoint":"token"}`,
168+
getResponse: `{"issuer":"https://issuer.stackit.cloud/endpoint","token_endpoint":"https://token.stackit.cloud/endpoint"}`,
169169
isValid: false,
170170
expected: nil,
171171
},
172172
{
173173
name: "missing_token",
174174
getFails: true,
175-
getResponse: `{"issuer":"issuer","authorization_endpoint":"auth"}`,
175+
getResponse: `{"issuer":"https://issuer.stackit.cloud/endpoint","authorization_endpoint":"https://auth.stackit.cloud/enpoint"}`,
176176
isValid: false,
177177
expected: nil,
178178
},

internal/pkg/utils/utils.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/base64"
55
"fmt"
66
"net/url"
7+
"slices"
78
"strings"
89
"time"
910

@@ -82,11 +83,19 @@ func ValidateURLDomain(value string) error {
8283
if err != nil {
8384
return fmt.Errorf("parse url: %w", err)
8485
}
86+
8587
urlHost := urlStruct.Hostname()
8688
if urlHost == "" {
8789
return fmt.Errorf("bad url")
8890
}
8991

92+
allowedSchemes := []string{
93+
"https",
94+
}
95+
if !slices.Contains(allowedSchemes, urlStruct.Scheme) {
96+
return fmt.Errorf("unsupported protocol: %s", urlStruct.Scheme)
97+
}
98+
9099
allowedUrlDomain := viper.GetString(config.AllowedUrlDomainKey)
91100

92101
if !strings.HasSuffix(urlHost, allowedUrlDomain) {

internal/pkg/utils/utils_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,21 @@ func TestValidateURLDomain(t *testing.T) {
9797
input: "",
9898
isValid: false,
9999
},
100+
{
101+
name: "invalid protocol",
102+
input: "http://example.stackit.cloud",
103+
isValid: false,
104+
},
105+
{
106+
name: "no protocol",
107+
input: "example.stackit.cloud",
108+
isValid: false,
109+
},
110+
{
111+
name: "valid endpoint",
112+
input: "https://service-account.api.stackit.cloud/token",
113+
isValid: true,
114+
},
100115
}
101116

102117
for _, tt := range tests {

0 commit comments

Comments
 (0)