Skip to content

Commit 0edba20

Browse files
GokceGKjoaopaletvicentepinto98
authored
Extend config options (#451)
* implement allowed-url-domain config option * implement jwks and token endpoints in cfg command * Update internal/cmd/config/set/set.go Co-authored-by: João Palet <[email protected]> * extend unset command for token and jwks * Change method name * Change endpoint handling * change default value handling for the allowed url domain * accept empty url domains and add warning * fix unit tests * Update internal/cmd/config/set/set.go Co-authored-by: Vicente Pinto <[email protected]> --------- Co-authored-by: João Palet <[email protected]> Co-authored-by: Vicente Pinto <[email protected]>
1 parent 303a201 commit 0edba20

File tree

15 files changed

+241
-74
lines changed

15 files changed

+241
-74
lines changed

docs/stackit_auth_activate-service-account.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,9 @@ stackit auth activate-service-account [flags]
2929

3030
```
3131
-h, --help Help for "stackit auth activate-service-account"
32-
--jwks-custom-endpoint string Custom endpoint for the jwks API, which is used to get the json web key sets (jwks) to validate tokens when the service-account authentication is activated
3332
--private-key-path string RSA private key path. It takes precedence over the private key included in the service account key, if present
3433
--service-account-key-path string Service account key path
3534
--service-account-token string Service account long-lived access token
36-
--token-custom-endpoint string Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated
3735
```
3836

3937
### Options inherited from parent commands

docs/stackit_config_set.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ stackit config set [flags]
2929
### Options
3030

3131
```
32+
--allowed-url-domain string Domain name, used for the verification of the URLs that are given in the custom identidy provider endpoint and "STACKIT curl" command
3233
--argus-custom-endpoint string Argus API base URL, used in calls to this API
3334
--authorization-custom-endpoint string Authorization API base URL, used in calls to this API
3435
--dns-custom-endpoint string DNS API base URL, used in calls to this API
3536
-h, --help Help for "stackit config set"
3637
--iaas-custom-endpoint string IaaS API base URL, used in calls to this API
3738
--identity-provider-custom-client-id string Identity Provider client ID, used for user authentication
3839
--identity-provider-custom-endpoint string Identity Provider base URL, used for user authentication
40+
--jwks-custom-endpoint string Custom endpoint for the jwks API, which is used to get the json web key sets (jwks) to validate tokens when the service-account authentication is activated
3941
--load-balancer-custom-endpoint string Load Balancer API base URL, used in calls to this API
4042
--logme-custom-endpoint string LogMe API base URL, used in calls to this API
4143
--mariadb-custom-endpoint string MariaDB API base URL, used in calls to this API
@@ -54,6 +56,7 @@ stackit config set [flags]
5456
--session-time-limit string Maximum time before authentication is required again. After this time, you will be prompted to login again to execute commands that require authentication. Can't be larger than 24h. Requires authentication after being set to take effect. Examples: 3h, 5h30m40s (BETA: currently values greater than 2h have no effect)
5557
--ske-custom-endpoint string SKE API base URL, used in calls to this API
5658
--sqlserverflex-custom-endpoint string SQLServer Flex API base URL, used in calls to this API
59+
--token-custom-endpoint string Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated
5760
```
5861

5962
### Options inherited from parent commands

docs/stackit_config_unset.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ stackit config unset [flags]
2626
### Options
2727

2828
```
29+
--allowed-url-domain Domain name, used for the verification of the URLs that are given in the IDP endpoint and curl commands. If unset, defaults to stackit.cloud
2930
--argus-custom-endpoint Argus API base URL. If unset, uses the default base URL
3031
--async Configuration option to run commands asynchronously
3132
--authorization-custom-endpoint Authorization API base URL. If unset, uses the default base URL
@@ -34,6 +35,7 @@ stackit config unset [flags]
3435
--iaas-custom-endpoint IaaS API base URL. If unset, uses the default base URL
3536
--identity-provider-custom-client-id Identity Provider client ID, used for user authentication
3637
--identity-provider-custom-endpoint Identity Provider base URL. If unset, uses the default base URL
38+
--jwks-custom-endpoint Custom endpoint for the jwks API, which is used to get the json web key sets (jwks) to validate tokens when the service-account authentication is activated
3739
--load-balancer-custom-endpoint Load Balancer API base URL. If unset, uses the default base URL
3840
--logme-custom-endpoint LogMe API base URL. If unset, uses the default base URL
3941
--mariadb-custom-endpoint MariaDB API base URL. If unset, uses the default base URL
@@ -54,6 +56,7 @@ stackit config unset [flags]
5456
--session-time-limit Maximum time before authentication is required again. If unset, defaults to 2h
5557
--ske-custom-endpoint SKE API base URL. If unset, uses the default base URL
5658
--sqlserverflex-custom-endpoint SQLServer Flex API base URL. If unset, uses the default base URL
59+
--token-custom-endpoint Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated
5760
--verbosity Verbosity of the CLI
5861
```
5962

internal/cmd/auth/activate-service-account/activate_service_account.go

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import (
44
"errors"
55
"fmt"
66

7+
"github.com/spf13/viper"
78
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
89
"github.com/stackitcloud/stackit-cli/internal/pkg/auth"
10+
"github.com/stackitcloud/stackit-cli/internal/pkg/config"
911
cliErr "github.com/stackitcloud/stackit-cli/internal/pkg/errors"
1012
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
1113
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
@@ -20,16 +22,12 @@ const (
2022
serviceAccountTokenFlag = "service-account-token"
2123
serviceAccountKeyPathFlag = "service-account-key-path"
2224
privateKeyPathFlag = "private-key-path"
23-
tokenCustomEndpointFlag = "token-custom-endpoint"
24-
jwksCustomEndpointFlag = "jwks-custom-endpoint"
2525
)
2626

2727
type inputModel struct {
2828
ServiceAccountToken string
2929
ServiceAccountKeyPath string
3030
PrivateKeyPath string
31-
TokenCustomEndpoint string
32-
JwksCustomEndpoint string
3331
}
3432

3533
func NewCmd(p *print.Printer) *cobra.Command {
@@ -56,7 +54,7 @@ func NewCmd(p *print.Printer) *cobra.Command {
5654
RunE: func(cmd *cobra.Command, args []string) error {
5755
model := parseInput(p, cmd)
5856

59-
err := storeFlags(model)
57+
tokenCustomEndpoint, jwksCustomEndpoint, err := storeFlags()
6058
if err != nil {
6159
return err
6260
}
@@ -65,8 +63,8 @@ func NewCmd(p *print.Printer) *cobra.Command {
6563
Token: model.ServiceAccountToken,
6664
ServiceAccountKeyPath: model.ServiceAccountKeyPath,
6765
PrivateKeyPath: model.PrivateKeyPath,
68-
TokenCustomUrl: model.TokenCustomEndpoint,
69-
JWKSCustomUrl: model.JwksCustomEndpoint,
66+
TokenCustomUrl: tokenCustomEndpoint,
67+
JWKSCustomUrl: jwksCustomEndpoint,
7068
}
7169

7270
// Setup authentication based on the provided credentials and the environment
@@ -100,17 +98,13 @@ func configureFlags(cmd *cobra.Command) {
10098
cmd.Flags().String(serviceAccountTokenFlag, "", "Service account long-lived access token")
10199
cmd.Flags().String(serviceAccountKeyPathFlag, "", "Service account key path")
102100
cmd.Flags().String(privateKeyPathFlag, "", "RSA private key path. It takes precedence over the private key included in the service account key, if present")
103-
cmd.Flags().String(tokenCustomEndpointFlag, "", "Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated")
104-
cmd.Flags().String(jwksCustomEndpointFlag, "", "Custom endpoint for the jwks API, which is used to get the json web key sets (jwks) to validate tokens when the service-account authentication is activated")
105101
}
106102

107103
func parseInput(p *print.Printer, cmd *cobra.Command) *inputModel {
108104
model := inputModel{
109105
ServiceAccountToken: flags.FlagToStringValue(p, cmd, serviceAccountTokenFlag),
110106
ServiceAccountKeyPath: flags.FlagToStringValue(p, cmd, serviceAccountKeyPathFlag),
111107
PrivateKeyPath: flags.FlagToStringValue(p, cmd, privateKeyPathFlag),
112-
TokenCustomEndpoint: flags.FlagToStringValue(p, cmd, tokenCustomEndpointFlag),
113-
JwksCustomEndpoint: flags.FlagToStringValue(p, cmd, jwksCustomEndpointFlag),
114108
}
115109

116110
if p.IsVerbosityDebug() {
@@ -125,14 +119,17 @@ func parseInput(p *print.Printer, cmd *cobra.Command) *inputModel {
125119
return &model
126120
}
127121

128-
func storeFlags(model *inputModel) error {
129-
err := auth.SetAuthField(auth.TOKEN_CUSTOM_ENDPOINT, model.TokenCustomEndpoint)
122+
func storeFlags() (tokenCustomEndpoint, jwksCustomEndpoint string, err error) {
123+
tokenCustomEndpoint = viper.GetString(config.TokenCustomEndpointKey)
124+
jwksCustomEndpoint = viper.GetString(config.JwksCustomEndpointKey)
125+
126+
err = auth.SetAuthField(auth.TOKEN_CUSTOM_ENDPOINT, tokenCustomEndpoint)
130127
if err != nil {
131-
return fmt.Errorf("set %s: %w", auth.TOKEN_CUSTOM_ENDPOINT, err)
128+
return "", "", fmt.Errorf("set %s: %w", auth.TOKEN_CUSTOM_ENDPOINT, err)
132129
}
133-
err = auth.SetAuthField(auth.JWKS_CUSTOM_ENDPOINT, model.JwksCustomEndpoint)
130+
err = auth.SetAuthField(auth.JWKS_CUSTOM_ENDPOINT, jwksCustomEndpoint)
134131
if err != nil {
135-
return fmt.Errorf("set %s: %w", auth.JWKS_CUSTOM_ENDPOINT, err)
132+
return "", "", fmt.Errorf("set %s: %w", auth.JWKS_CUSTOM_ENDPOINT, err)
136133
}
137-
return nil
134+
return tokenCustomEndpoint, jwksCustomEndpoint, nil
138135
}

internal/cmd/auth/activate-service-account/activate_service_account_test.go

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,24 @@ package activateserviceaccount
33
import (
44
"testing"
55

6+
"github.com/spf13/viper"
67
"github.com/stackitcloud/stackit-cli/internal/pkg/auth"
8+
"github.com/stackitcloud/stackit-cli/internal/pkg/config"
79
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
810
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
911
"github.com/zalando/go-keyring"
1012

1113
"github.com/google/go-cmp/cmp"
1214
)
1315

16+
var testTokenCustomEndpoint = "token_url"
17+
var testJwksCustomEndpoint = "jwks_url"
18+
1419
func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string {
1520
flagValues := map[string]string{
1621
serviceAccountTokenFlag: "token",
1722
serviceAccountKeyPathFlag: "sa_key",
1823
privateKeyPathFlag: "private_key",
19-
tokenCustomEndpointFlag: "token_url",
20-
jwksCustomEndpointFlag: "jwks_url",
2124
}
2225
for _, mod := range mods {
2326
mod(flagValues)
@@ -30,8 +33,6 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
3033
ServiceAccountToken: "token",
3134
ServiceAccountKeyPath: "sa_key",
3235
PrivateKeyPath: "private_key",
33-
TokenCustomEndpoint: "token_url",
34-
JwksCustomEndpoint: "jwks_url",
3536
}
3637
for _, mod := range mods {
3738
mod(model)
@@ -41,27 +42,31 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
4142

4243
func TestParseInput(t *testing.T) {
4344
tests := []struct {
44-
description string
45-
flagValues map[string]string
46-
isValid bool
47-
expectedModel *inputModel
45+
description string
46+
flagValues map[string]string
47+
tokenCustomEndpoint string
48+
jwksCustomEndpoint string
49+
isValid bool
50+
expectedModel *inputModel
4851
}{
4952
{
50-
description: "base",
51-
flagValues: fixtureFlagValues(),
52-
isValid: true,
53-
expectedModel: fixtureInputModel(),
53+
description: "base",
54+
flagValues: fixtureFlagValues(),
55+
tokenCustomEndpoint: testTokenCustomEndpoint,
56+
jwksCustomEndpoint: testJwksCustomEndpoint,
57+
isValid: true,
58+
expectedModel: fixtureInputModel(),
5459
},
5560
{
56-
description: "no values",
57-
flagValues: map[string]string{},
58-
isValid: true,
61+
description: "no values",
62+
flagValues: map[string]string{},
63+
tokenCustomEndpoint: "",
64+
jwksCustomEndpoint: "",
65+
isValid: true,
5966
expectedModel: &inputModel{
6067
ServiceAccountToken: "",
6168
ServiceAccountKeyPath: "",
6269
PrivateKeyPath: "",
63-
TokenCustomEndpoint: "",
64-
JwksCustomEndpoint: "",
6570
},
6671
},
6772
{
@@ -70,16 +75,14 @@ func TestParseInput(t *testing.T) {
7075
serviceAccountTokenFlag: "",
7176
serviceAccountKeyPathFlag: "",
7277
privateKeyPathFlag: "",
73-
tokenCustomEndpointFlag: "",
74-
jwksCustomEndpointFlag: "",
7578
},
76-
isValid: true,
79+
tokenCustomEndpoint: "",
80+
jwksCustomEndpoint: "",
81+
isValid: true,
7782
expectedModel: &inputModel{
7883
ServiceAccountToken: "",
7984
ServiceAccountKeyPath: "",
8085
PrivateKeyPath: "",
81-
TokenCustomEndpoint: "",
82-
JwksCustomEndpoint: "",
8386
},
8487
},
8588
{
@@ -125,25 +128,29 @@ func TestParseInput(t *testing.T) {
125128

126129
func TestStoreFlags(t *testing.T) {
127130
tests := []struct {
128-
description string
129-
model *inputModel
130-
isValid bool
131+
description string
132+
model *inputModel
133+
tokenCustomEndpoint string
134+
jwksCustomEndpoint string
135+
isValid bool
131136
}{
132137
{
133-
description: "base",
134-
model: fixtureInputModel(),
135-
isValid: true,
138+
description: "base",
139+
model: fixtureInputModel(),
140+
tokenCustomEndpoint: testTokenCustomEndpoint,
141+
jwksCustomEndpoint: testJwksCustomEndpoint,
142+
isValid: true,
136143
},
137144
{
138145
description: "no values",
139146
model: &inputModel{
140147
ServiceAccountToken: "",
141148
ServiceAccountKeyPath: "",
142149
PrivateKeyPath: "",
143-
TokenCustomEndpoint: "",
144-
JwksCustomEndpoint: "",
145150
},
146-
isValid: true,
151+
tokenCustomEndpoint: "",
152+
jwksCustomEndpoint: "",
153+
isValid: true,
147154
},
148155
}
149156

@@ -152,7 +159,11 @@ func TestStoreFlags(t *testing.T) {
152159
// Initialize an empty keyring
153160
keyring.MockInit()
154161

155-
err := storeFlags(tt.model)
162+
viper.Reset()
163+
viper.Set(config.TokenCustomEndpointKey, tt.tokenCustomEndpoint)
164+
viper.Set(config.JwksCustomEndpointKey, tt.jwksCustomEndpoint)
165+
166+
tokenCustomEndpoint, jwksCustomEndpoint, err := storeFlags()
156167
if !tt.isValid {
157168
if err == nil {
158169
t.Fatalf("did not fail on invalid input")
@@ -167,16 +178,16 @@ func TestStoreFlags(t *testing.T) {
167178
if err != nil {
168179
t.Errorf("Failed to get value of auth field: %v", err)
169180
}
170-
if value != tt.model.TokenCustomEndpoint {
171-
t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.TOKEN_CUSTOM_ENDPOINT, tt.model.TokenCustomEndpoint, value)
181+
if value != tokenCustomEndpoint {
182+
t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.TOKEN_CUSTOM_ENDPOINT, tokenCustomEndpoint, value)
172183
}
173184

174185
value, err = auth.GetAuthField(auth.JWKS_CUSTOM_ENDPOINT)
175186
if err != nil {
176187
t.Errorf("Failed to get value of auth field: %v", err)
177188
}
178-
if value != tt.model.JwksCustomEndpoint {
179-
t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.JWKS_CUSTOM_ENDPOINT, tt.model.TokenCustomEndpoint, value)
189+
if value != jwksCustomEndpoint {
190+
t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.JWKS_CUSTOM_ENDPOINT, jwksCustomEndpoint, value)
180191
}
181192
})
182193
}

internal/cmd/config/set/set.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const (
2020
sessionTimeLimitFlag = "session-time-limit"
2121
identityProviderCustomEndpointFlag = "identity-provider-custom-endpoint"
2222
identityProviderCustomClientIdFlag = "identity-provider-custom-client-id"
23+
allowedUrlDomainFlag = "allowed-url-domain"
2324

2425
argusCustomEndpointFlag = "argus-custom-endpoint"
2526
authorizationCustomEndpointFlag = "authorization-custom-endpoint"
@@ -42,6 +43,8 @@ const (
4243
skeCustomEndpointFlag = "ske-custom-endpoint"
4344
sqlServerFlexCustomEndpointFlag = "sqlserverflex-custom-endpoint"
4445
iaasCustomEndpointFlag = "iaas-custom-endpoint"
46+
tokenCustomEndpointFlag = "token-custom-endpoint"
47+
jwksCustomEndpointFlag = "jwks-custom-endpoint"
4548
)
4649

4750
type inputModel struct {
@@ -131,6 +134,7 @@ func configureFlags(cmd *cobra.Command) {
131134
cmd.Flags().String(sessionTimeLimitFlag, "", "Maximum time before authentication is required again. After this time, you will be prompted to login again to execute commands that require authentication. Can't be larger than 24h. Requires authentication after being set to take effect. Examples: 3h, 5h30m40s (BETA: currently values greater than 2h have no effect)")
132135
cmd.Flags().String(identityProviderCustomEndpointFlag, "", "Identity Provider base URL, used for user authentication")
133136
cmd.Flags().String(identityProviderCustomClientIdFlag, "", "Identity Provider client ID, used for user authentication")
137+
cmd.Flags().String(allowedUrlDomainFlag, "", `Domain name, used for the verification of the URLs that are given in the custom identity provider endpoint and "STACKIT curl" command`)
134138
cmd.Flags().String(argusCustomEndpointFlag, "", "Argus API base URL, used in calls to this API")
135139
cmd.Flags().String(authorizationCustomEndpointFlag, "", "Authorization API base URL, used in calls to this API")
136140
cmd.Flags().String(dnsCustomEndpointFlag, "", "DNS API base URL, used in calls to this API")
@@ -152,13 +156,17 @@ func configureFlags(cmd *cobra.Command) {
152156
cmd.Flags().String(skeCustomEndpointFlag, "", "SKE API base URL, used in calls to this API")
153157
cmd.Flags().String(sqlServerFlexCustomEndpointFlag, "", "SQLServer Flex API base URL, used in calls to this API")
154158
cmd.Flags().String(iaasCustomEndpointFlag, "", "IaaS API base URL, used in calls to this API")
159+
cmd.Flags().String(tokenCustomEndpointFlag, "", "Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated")
160+
cmd.Flags().String(jwksCustomEndpointFlag, "", "Custom endpoint for the jwks API, which is used to get the json web key sets (jwks) to validate tokens when the service-account authentication is activated")
155161

156162
err := viper.BindPFlag(config.SessionTimeLimitKey, cmd.Flags().Lookup(sessionTimeLimitFlag))
157163
cobra.CheckErr(err)
158164
err = viper.BindPFlag(config.IdentityProviderCustomEndpointKey, cmd.Flags().Lookup(identityProviderCustomEndpointFlag))
159165
cobra.CheckErr(err)
160166
err = viper.BindPFlag(config.IdentityProviderCustomClientIdKey, cmd.Flags().Lookup(identityProviderCustomClientIdFlag))
161167
cobra.CheckErr(err)
168+
err = viper.BindPFlag(config.AllowedUrlDomainKey, cmd.Flags().Lookup(allowedUrlDomainFlag))
169+
cobra.CheckErr(err)
162170

163171
err = viper.BindPFlag(config.ArgusCustomEndpointKey, cmd.Flags().Lookup(argusCustomEndpointFlag))
164172
cobra.CheckErr(err)
@@ -202,6 +210,10 @@ func configureFlags(cmd *cobra.Command) {
202210
cobra.CheckErr(err)
203211
err = viper.BindPFlag(config.IaaSCustomEndpointKey, cmd.Flags().Lookup(iaasCustomEndpointFlag))
204212
cobra.CheckErr(err)
213+
err = viper.BindPFlag(config.TokenCustomEndpointKey, cmd.Flags().Lookup(tokenCustomEndpointFlag))
214+
cobra.CheckErr(err)
215+
err = viper.BindPFlag(config.JwksCustomEndpointKey, cmd.Flags().Lookup(jwksCustomEndpointFlag))
216+
cobra.CheckErr(err)
205217
}
206218

207219
func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
@@ -222,6 +234,11 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) {
222234
projectIdSet = true
223235
}
224236

237+
allowedUrlDomainFromFlag := flags.FlagToStringValue(p, cmd, allowedUrlDomainFlag)
238+
if allowedUrlDomainFromFlag == "" {
239+
p.Warn("The allowed URL domain is set to empty. All URLs will be accepted regardless of their domain.\n")
240+
}
241+
225242
model := inputModel{
226243
SessionTimeLimit: sessionTimeLimit,
227244
ProjectIdSet: projectIdSet,

0 commit comments

Comments
 (0)