Skip to content

Extend config options #451

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions docs/stackit_auth_activate-service-account.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@ stackit auth activate-service-account [flags]

```
-h, --help Help for "stackit auth activate-service-account"
--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
--private-key-path string RSA private key path. It takes precedence over the private key included in the service account key, if present
--service-account-key-path string Service account key path
--service-account-token string Service account long-lived access token
--token-custom-endpoint string Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated
```

### Options inherited from parent commands
Expand Down
3 changes: 3 additions & 0 deletions docs/stackit_config_set.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ stackit config set [flags]
### Options

```
--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
--argus-custom-endpoint string Argus API base URL, used in calls to this API
--authorization-custom-endpoint string Authorization API base URL, used in calls to this API
--dns-custom-endpoint string DNS API base URL, used in calls to this API
-h, --help Help for "stackit config set"
--iaas-custom-endpoint string IaaS API base URL, used in calls to this API
--identity-provider-custom-client-id string Identity Provider client ID, used for user authentication
--identity-provider-custom-endpoint string Identity Provider base URL, used for user authentication
--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
--load-balancer-custom-endpoint string Load Balancer API base URL, used in calls to this API
--logme-custom-endpoint string LogMe API base URL, used in calls to this API
--mariadb-custom-endpoint string MariaDB API base URL, used in calls to this API
Expand All @@ -54,6 +56,7 @@ stackit config set [flags]
--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)
--ske-custom-endpoint string SKE API base URL, used in calls to this API
--sqlserverflex-custom-endpoint string SQLServer Flex API base URL, used in calls to this API
--token-custom-endpoint string Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated
```

### Options inherited from parent commands
Expand Down
3 changes: 3 additions & 0 deletions docs/stackit_config_unset.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ stackit config unset [flags]
### Options

```
--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
--argus-custom-endpoint Argus API base URL. If unset, uses the default base URL
--async Configuration option to run commands asynchronously
--authorization-custom-endpoint Authorization API base URL. If unset, uses the default base URL
Expand All @@ -34,6 +35,7 @@ stackit config unset [flags]
--iaas-custom-endpoint IaaS API base URL. If unset, uses the default base URL
--identity-provider-custom-client-id Identity Provider client ID, used for user authentication
--identity-provider-custom-endpoint Identity Provider base URL. If unset, uses the default base URL
--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
--load-balancer-custom-endpoint Load Balancer API base URL. If unset, uses the default base URL
--logme-custom-endpoint LogMe API base URL. If unset, uses the default base URL
--mariadb-custom-endpoint MariaDB API base URL. If unset, uses the default base URL
Expand All @@ -54,6 +56,7 @@ stackit config unset [flags]
--session-time-limit Maximum time before authentication is required again. If unset, defaults to 2h
--ske-custom-endpoint SKE API base URL. If unset, uses the default base URL
--sqlserverflex-custom-endpoint SQLServer Flex API base URL. If unset, uses the default base URL
--token-custom-endpoint Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated
--verbosity Verbosity of the CLI
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"errors"
"fmt"

"github.com/spf13/viper"
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"github.com/stackitcloud/stackit-cli/internal/pkg/auth"
"github.com/stackitcloud/stackit-cli/internal/pkg/config"
cliErr "github.com/stackitcloud/stackit-cli/internal/pkg/errors"
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
Expand All @@ -20,16 +22,12 @@ const (
serviceAccountTokenFlag = "service-account-token"
serviceAccountKeyPathFlag = "service-account-key-path"
privateKeyPathFlag = "private-key-path"
tokenCustomEndpointFlag = "token-custom-endpoint"
jwksCustomEndpointFlag = "jwks-custom-endpoint"
)

type inputModel struct {
ServiceAccountToken string
ServiceAccountKeyPath string
PrivateKeyPath string
TokenCustomEndpoint string
JwksCustomEndpoint string
}

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

err := storeFlags(model)
tokenCustomEndpoint, jwksCustomEndpoint, err := storeFlags()
if err != nil {
return err
}
Expand All @@ -65,8 +63,8 @@ func NewCmd(p *print.Printer) *cobra.Command {
Token: model.ServiceAccountToken,
ServiceAccountKeyPath: model.ServiceAccountKeyPath,
PrivateKeyPath: model.PrivateKeyPath,
TokenCustomUrl: model.TokenCustomEndpoint,
JWKSCustomUrl: model.JwksCustomEndpoint,
TokenCustomUrl: tokenCustomEndpoint,
JWKSCustomUrl: jwksCustomEndpoint,
}

// Setup authentication based on the provided credentials and the environment
Expand Down Expand Up @@ -100,17 +98,13 @@ func configureFlags(cmd *cobra.Command) {
cmd.Flags().String(serviceAccountTokenFlag, "", "Service account long-lived access token")
cmd.Flags().String(serviceAccountKeyPathFlag, "", "Service account key path")
cmd.Flags().String(privateKeyPathFlag, "", "RSA private key path. It takes precedence over the private key included in the service account key, if present")
cmd.Flags().String(tokenCustomEndpointFlag, "", "Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated")
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")
}

func parseInput(p *print.Printer, cmd *cobra.Command) *inputModel {
model := inputModel{
ServiceAccountToken: flags.FlagToStringValue(p, cmd, serviceAccountTokenFlag),
ServiceAccountKeyPath: flags.FlagToStringValue(p, cmd, serviceAccountKeyPathFlag),
PrivateKeyPath: flags.FlagToStringValue(p, cmd, privateKeyPathFlag),
TokenCustomEndpoint: flags.FlagToStringValue(p, cmd, tokenCustomEndpointFlag),
JwksCustomEndpoint: flags.FlagToStringValue(p, cmd, jwksCustomEndpointFlag),
}

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

func storeFlags(model *inputModel) error {
err := auth.SetAuthField(auth.TOKEN_CUSTOM_ENDPOINT, model.TokenCustomEndpoint)
func storeFlags() (tokenCustomEndpoint, jwksCustomEndpoint string, err error) {
tokenCustomEndpoint = viper.GetString(config.TokenCustomEndpointKey)
jwksCustomEndpoint = viper.GetString(config.JwksCustomEndpointKey)

err = auth.SetAuthField(auth.TOKEN_CUSTOM_ENDPOINT, tokenCustomEndpoint)
if err != nil {
return fmt.Errorf("set %s: %w", auth.TOKEN_CUSTOM_ENDPOINT, err)
return "", "", fmt.Errorf("set %s: %w", auth.TOKEN_CUSTOM_ENDPOINT, err)
}
err = auth.SetAuthField(auth.JWKS_CUSTOM_ENDPOINT, model.JwksCustomEndpoint)
err = auth.SetAuthField(auth.JWKS_CUSTOM_ENDPOINT, jwksCustomEndpoint)
if err != nil {
return fmt.Errorf("set %s: %w", auth.JWKS_CUSTOM_ENDPOINT, err)
return "", "", fmt.Errorf("set %s: %w", auth.JWKS_CUSTOM_ENDPOINT, err)
}
return nil
return tokenCustomEndpoint, jwksCustomEndpoint, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,24 @@ package activateserviceaccount
import (
"testing"

"github.com/spf13/viper"
"github.com/stackitcloud/stackit-cli/internal/pkg/auth"
"github.com/stackitcloud/stackit-cli/internal/pkg/config"
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
"github.com/zalando/go-keyring"

"github.com/google/go-cmp/cmp"
)

var testTokenCustomEndpoint = "token_url"
var testJwksCustomEndpoint = "jwks_url"

func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string {
flagValues := map[string]string{
serviceAccountTokenFlag: "token",
serviceAccountKeyPathFlag: "sa_key",
privateKeyPathFlag: "private_key",
tokenCustomEndpointFlag: "token_url",
jwksCustomEndpointFlag: "jwks_url",
}
for _, mod := range mods {
mod(flagValues)
Expand All @@ -30,8 +33,6 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
ServiceAccountToken: "token",
ServiceAccountKeyPath: "sa_key",
PrivateKeyPath: "private_key",
TokenCustomEndpoint: "token_url",
JwksCustomEndpoint: "jwks_url",
}
for _, mod := range mods {
mod(model)
Expand All @@ -41,27 +42,31 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {

func TestParseInput(t *testing.T) {
tests := []struct {
description string
flagValues map[string]string
isValid bool
expectedModel *inputModel
description string
flagValues map[string]string
tokenCustomEndpoint string
jwksCustomEndpoint string
isValid bool
expectedModel *inputModel
}{
{
description: "base",
flagValues: fixtureFlagValues(),
isValid: true,
expectedModel: fixtureInputModel(),
description: "base",
flagValues: fixtureFlagValues(),
tokenCustomEndpoint: testTokenCustomEndpoint,
jwksCustomEndpoint: testJwksCustomEndpoint,
isValid: true,
expectedModel: fixtureInputModel(),
},
{
description: "no values",
flagValues: map[string]string{},
isValid: true,
description: "no values",
flagValues: map[string]string{},
tokenCustomEndpoint: "",
jwksCustomEndpoint: "",
isValid: true,
expectedModel: &inputModel{
ServiceAccountToken: "",
ServiceAccountKeyPath: "",
PrivateKeyPath: "",
TokenCustomEndpoint: "",
JwksCustomEndpoint: "",
},
},
{
Expand All @@ -70,16 +75,14 @@ func TestParseInput(t *testing.T) {
serviceAccountTokenFlag: "",
serviceAccountKeyPathFlag: "",
privateKeyPathFlag: "",
tokenCustomEndpointFlag: "",
jwksCustomEndpointFlag: "",
},
isValid: true,
tokenCustomEndpoint: "",
jwksCustomEndpoint: "",
isValid: true,
expectedModel: &inputModel{
ServiceAccountToken: "",
ServiceAccountKeyPath: "",
PrivateKeyPath: "",
TokenCustomEndpoint: "",
JwksCustomEndpoint: "",
},
},
{
Expand Down Expand Up @@ -125,25 +128,29 @@ func TestParseInput(t *testing.T) {

func TestStoreFlags(t *testing.T) {
tests := []struct {
description string
model *inputModel
isValid bool
description string
model *inputModel
tokenCustomEndpoint string
jwksCustomEndpoint string
isValid bool
}{
{
description: "base",
model: fixtureInputModel(),
isValid: true,
description: "base",
model: fixtureInputModel(),
tokenCustomEndpoint: testTokenCustomEndpoint,
jwksCustomEndpoint: testJwksCustomEndpoint,
isValid: true,
},
{
description: "no values",
model: &inputModel{
ServiceAccountToken: "",
ServiceAccountKeyPath: "",
PrivateKeyPath: "",
TokenCustomEndpoint: "",
JwksCustomEndpoint: "",
},
isValid: true,
tokenCustomEndpoint: "",
jwksCustomEndpoint: "",
isValid: true,
},
}

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

err := storeFlags(tt.model)
viper.Reset()
viper.Set(config.TokenCustomEndpointKey, tt.tokenCustomEndpoint)
viper.Set(config.JwksCustomEndpointKey, tt.jwksCustomEndpoint)

tokenCustomEndpoint, jwksCustomEndpoint, err := storeFlags()
if !tt.isValid {
if err == nil {
t.Fatalf("did not fail on invalid input")
Expand All @@ -167,16 +178,16 @@ func TestStoreFlags(t *testing.T) {
if err != nil {
t.Errorf("Failed to get value of auth field: %v", err)
}
if value != tt.model.TokenCustomEndpoint {
t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.TOKEN_CUSTOM_ENDPOINT, tt.model.TokenCustomEndpoint, value)
if value != tokenCustomEndpoint {
t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.TOKEN_CUSTOM_ENDPOINT, tokenCustomEndpoint, value)
}

value, err = auth.GetAuthField(auth.JWKS_CUSTOM_ENDPOINT)
if err != nil {
t.Errorf("Failed to get value of auth field: %v", err)
}
if value != tt.model.JwksCustomEndpoint {
t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.JWKS_CUSTOM_ENDPOINT, tt.model.TokenCustomEndpoint, value)
if value != jwksCustomEndpoint {
t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.JWKS_CUSTOM_ENDPOINT, jwksCustomEndpoint, value)
}
})
}
Expand Down
17 changes: 17 additions & 0 deletions internal/cmd/config/set/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
sessionTimeLimitFlag = "session-time-limit"
identityProviderCustomEndpointFlag = "identity-provider-custom-endpoint"
identityProviderCustomClientIdFlag = "identity-provider-custom-client-id"
allowedUrlDomainFlag = "allowed-url-domain"

argusCustomEndpointFlag = "argus-custom-endpoint"
authorizationCustomEndpointFlag = "authorization-custom-endpoint"
Expand All @@ -42,6 +43,8 @@ const (
skeCustomEndpointFlag = "ske-custom-endpoint"
sqlServerFlexCustomEndpointFlag = "sqlserverflex-custom-endpoint"
iaasCustomEndpointFlag = "iaas-custom-endpoint"
tokenCustomEndpointFlag = "token-custom-endpoint"
jwksCustomEndpointFlag = "jwks-custom-endpoint"
)

type inputModel struct {
Expand Down Expand Up @@ -131,6 +134,7 @@ func configureFlags(cmd *cobra.Command) {
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)")
cmd.Flags().String(identityProviderCustomEndpointFlag, "", "Identity Provider base URL, used for user authentication")
cmd.Flags().String(identityProviderCustomClientIdFlag, "", "Identity Provider client ID, used for user authentication")
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`)
cmd.Flags().String(argusCustomEndpointFlag, "", "Argus API base URL, used in calls to this API")
cmd.Flags().String(authorizationCustomEndpointFlag, "", "Authorization API base URL, used in calls to this API")
cmd.Flags().String(dnsCustomEndpointFlag, "", "DNS API base URL, used in calls to this API")
Expand All @@ -152,13 +156,17 @@ func configureFlags(cmd *cobra.Command) {
cmd.Flags().String(skeCustomEndpointFlag, "", "SKE API base URL, used in calls to this API")
cmd.Flags().String(sqlServerFlexCustomEndpointFlag, "", "SQLServer Flex API base URL, used in calls to this API")
cmd.Flags().String(iaasCustomEndpointFlag, "", "IaaS API base URL, used in calls to this API")
cmd.Flags().String(tokenCustomEndpointFlag, "", "Custom endpoint for the token API, which is used to request access tokens when the service-account authentication is activated")
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")

err := viper.BindPFlag(config.SessionTimeLimitKey, cmd.Flags().Lookup(sessionTimeLimitFlag))
cobra.CheckErr(err)
err = viper.BindPFlag(config.IdentityProviderCustomEndpointKey, cmd.Flags().Lookup(identityProviderCustomEndpointFlag))
cobra.CheckErr(err)
err = viper.BindPFlag(config.IdentityProviderCustomClientIdKey, cmd.Flags().Lookup(identityProviderCustomClientIdFlag))
cobra.CheckErr(err)
err = viper.BindPFlag(config.AllowedUrlDomainKey, cmd.Flags().Lookup(allowedUrlDomainFlag))
cobra.CheckErr(err)

err = viper.BindPFlag(config.ArgusCustomEndpointKey, cmd.Flags().Lookup(argusCustomEndpointFlag))
cobra.CheckErr(err)
Expand Down Expand Up @@ -202,6 +210,10 @@ func configureFlags(cmd *cobra.Command) {
cobra.CheckErr(err)
err = viper.BindPFlag(config.IaaSCustomEndpointKey, cmd.Flags().Lookup(iaasCustomEndpointFlag))
cobra.CheckErr(err)
err = viper.BindPFlag(config.TokenCustomEndpointKey, cmd.Flags().Lookup(tokenCustomEndpointFlag))
cobra.CheckErr(err)
err = viper.BindPFlag(config.JwksCustomEndpointKey, cmd.Flags().Lookup(jwksCustomEndpointFlag))
cobra.CheckErr(err)
}

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

allowedUrlDomainFromFlag := flags.FlagToStringValue(p, cmd, allowedUrlDomainFlag)
if allowedUrlDomainFromFlag == "" {
p.Warn("The allowed URL domain is set to empty. All URLs will be accepted regardless of their domain.\n")
}

model := inputModel{
SessionTimeLimit: sessionTimeLimit,
ProjectIdSet: projectIdSet,
Expand Down
Loading