Skip to content

Commit b799e96

Browse files
authored
Add support for custom IDP endpoint and client ID (#400)
* Add support for custom IDP endpoint and client ID * Add debug log for client ID * Add warning when using custom IDP endpoint * Handle error in PromptForEnter * Remove IDO custom flags from command, will live only in config commands * Improve flag documentation * Improve flag documentation * Validate custom IDP endpoint belongs to STACKIT * Remove client ID custom endpoint * Update docs * Simplify code * Remove unneeded debug log * Simplify test
1 parent 0761885 commit b799e96

File tree

14 files changed

+282
-110
lines changed

14 files changed

+282
-110
lines changed

docs/stackit_config_set.md

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,27 @@ stackit config set [flags]
2929
### Options
3030

3131
```
32-
--argus-custom-endpoint string Argus API base URL, used in calls to this API
33-
--authorization-custom-endpoint string Authorization API base URL, used in calls to this API
34-
--dns-custom-endpoint string DNS API base URL, used in calls to this API
35-
-h, --help Help for "stackit config set"
36-
--load-balancer-custom-endpoint string Load Balancer API base URL, used in calls to this API
37-
--logme-custom-endpoint string LogMe API base URL, used in calls to this API
38-
--mariadb-custom-endpoint string MariaDB API base URL, used in calls to this API
39-
--mongodbflex-custom-endpoint string MongoDB Flex API base URL, used in calls to this API
40-
--object-storage-custom-endpoint string Object Storage API base URL, used in calls to this API
41-
--opensearch-custom-endpoint string OpenSearch API base URL, used in calls to this API
42-
--postgresflex-custom-endpoint string PostgreSQL Flex API base URL, used in calls to this API
43-
--rabbitmq-custom-endpoint string RabbitMQ API base URL, used in calls to this API
44-
--redis-custom-endpoint string Redis API base URL, used in calls to this API
45-
--resource-manager-custom-endpoint string Resource Manager API base URL, used in calls to this API
46-
--secrets-manager-custom-endpoint string Secrets Manager API base URL, used in calls to this API
47-
--serverbackup-custom-endpoint string Server Backup API base URL, used in calls to this API
48-
--service-account-custom-endpoint string Service Account API base URL, used in calls to this API
49-
--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)
50-
--ske-custom-endpoint string SKE API base URL, used in calls to this API
51-
--sqlserverflex-custom-endpoint string SQLServer Flex API base URL, used in calls to this API
32+
--argus-custom-endpoint string Argus API base URL, used in calls to this API
33+
--authorization-custom-endpoint string Authorization API base URL, used in calls to this API
34+
--dns-custom-endpoint string DNS API base URL, used in calls to this API
35+
-h, --help Help for "stackit config set"
36+
--identity-provider-custom-endpoint string Identity Provider base URL, used for user authentication
37+
--load-balancer-custom-endpoint string Load Balancer API base URL, used in calls to this API
38+
--logme-custom-endpoint string LogMe API base URL, used in calls to this API
39+
--mariadb-custom-endpoint string MariaDB API base URL, used in calls to this API
40+
--mongodbflex-custom-endpoint string MongoDB Flex API base URL, used in calls to this API
41+
--object-storage-custom-endpoint string Object Storage API base URL, used in calls to this API
42+
--opensearch-custom-endpoint string OpenSearch API base URL, used in calls to this API
43+
--postgresflex-custom-endpoint string PostgreSQL Flex API base URL, used in calls to this API
44+
--rabbitmq-custom-endpoint string RabbitMQ API base URL, used in calls to this API
45+
--redis-custom-endpoint string Redis API base URL, used in calls to this API
46+
--resource-manager-custom-endpoint string Resource Manager API base URL, used in calls to this API
47+
--secrets-manager-custom-endpoint string Secrets Manager API base URL, used in calls to this API
48+
--serverbackup-custom-endpoint string Server Backup API base URL, used in calls to this API
49+
--service-account-custom-endpoint string Service Account API base URL, used in calls to this API
50+
--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)
51+
--ske-custom-endpoint string SKE API base URL, used in calls to this API
52+
--sqlserverflex-custom-endpoint string SQLServer Flex API base URL, used in calls to this API
5253
```
5354

5455
### Options inherited from parent commands

docs/stackit_config_unset.md

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,30 +26,31 @@ stackit config unset [flags]
2626
### Options
2727

2828
```
29-
--argus-custom-endpoint Argus API base URL. If unset, uses the default base URL
30-
--async Configuration option to run commands asynchronously
31-
--authorization-custom-endpoint Authorization API base URL. If unset, uses the default base URL
32-
--dns-custom-endpoint DNS API base URL. If unset, uses the default base URL
33-
-h, --help Help for "stackit config unset"
34-
--load-balancer-custom-endpoint Load Balancer API base URL. If unset, uses the default base URL
35-
--logme-custom-endpoint LogMe API base URL. If unset, uses the default base URL
36-
--mariadb-custom-endpoint MariaDB API base URL. If unset, uses the default base URL
37-
--mongodbflex-custom-endpoint MongoDB Flex API base URL. If unset, uses the default base URL
38-
--object-storage-custom-endpoint Object Storage API base URL. If unset, uses the default base URL
39-
--opensearch-custom-endpoint OpenSearch API base URL. If unset, uses the default base URL
40-
--output-format Output format
41-
--postgresflex-custom-endpoint PostgreSQL Flex API base URL. If unset, uses the default base URL
42-
--project-id Project ID
43-
--rabbitmq-custom-endpoint RabbitMQ API base URL. If unset, uses the default base URL
44-
--redis-custom-endpoint Redis API base URL. If unset, uses the default base URL
45-
--resource-manager-custom-endpoint Resource Manager API base URL. If unset, uses the default base URL
46-
--secrets-manager-custom-endpoint Secrets Manager API base URL. If unset, uses the default base URL
47-
--serverbackup-custom-endpoint Server Backup base URL. If unset, uses the default base URL
48-
--service-account-custom-endpoint SKE API base URL. If unset, uses the default base URL
49-
--session-time-limit Maximum time before authentication is required again. If unset, defaults to 2h
50-
--ske-custom-endpoint SKE API base URL. If unset, uses the default base URL
51-
--sqlserverflex-custom-endpoint SQLServer Flex API base URL. If unset, uses the default base URL
52-
--verbosity Verbosity of the CLI
29+
--argus-custom-endpoint Argus API base URL. If unset, uses the default base URL
30+
--async Configuration option to run commands asynchronously
31+
--authorization-custom-endpoint Authorization API base URL. If unset, uses the default base URL
32+
--dns-custom-endpoint DNS API base URL. If unset, uses the default base URL
33+
-h, --help Help for "stackit config unset"
34+
--identity-provider-custom-endpoint Identity Provider base URL. If unset, uses the default base URL
35+
--load-balancer-custom-endpoint Load Balancer API base URL. If unset, uses the default base URL
36+
--logme-custom-endpoint LogMe API base URL. If unset, uses the default base URL
37+
--mariadb-custom-endpoint MariaDB API base URL. If unset, uses the default base URL
38+
--mongodbflex-custom-endpoint MongoDB Flex API base URL. If unset, uses the default base URL
39+
--object-storage-custom-endpoint Object Storage API base URL. If unset, uses the default base URL
40+
--opensearch-custom-endpoint OpenSearch API base URL. If unset, uses the default base URL
41+
--output-format Output format
42+
--postgresflex-custom-endpoint PostgreSQL Flex API base URL. If unset, uses the default base URL
43+
--project-id Project ID
44+
--rabbitmq-custom-endpoint RabbitMQ API base URL. If unset, uses the default base URL
45+
--redis-custom-endpoint Redis API base URL. If unset, uses the default base URL
46+
--resource-manager-custom-endpoint Resource Manager API base URL. If unset, uses the default base URL
47+
--secrets-manager-custom-endpoint Secrets Manager API base URL. If unset, uses the default base URL
48+
--serverbackup-custom-endpoint Server Backup base URL. If unset, uses the default base URL
49+
--service-account-custom-endpoint SKE API base URL. If unset, uses the default base URL
50+
--session-time-limit Maximum time before authentication is required again. If unset, defaults to 2h
51+
--ske-custom-endpoint SKE API base URL. If unset, uses the default base URL
52+
--sqlserverflex-custom-endpoint SQLServer Flex API base URL. If unset, uses the default base URL
53+
--verbosity Verbosity of the CLI
5354
```
5455

5556
### Options inherited from parent commands

internal/cmd/config/set/set.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import (
1717
)
1818

1919
const (
20-
sessionTimeLimitFlag = "session-time-limit"
20+
sessionTimeLimitFlag = "session-time-limit"
21+
identityProviderCustomEndpointFlag = "identity-provider-custom-endpoint"
2122

2223
argusCustomEndpointFlag = "argus-custom-endpoint"
2324
authorizationCustomEndpointFlag = "authorization-custom-endpoint"
@@ -124,7 +125,7 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.{{e
124125

125126
func configureFlags(cmd *cobra.Command) {
126127
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)")
127-
128+
cmd.Flags().String(identityProviderCustomEndpointFlag, "", "Identity Provider base URL, used for user authentication")
128129
cmd.Flags().String(argusCustomEndpointFlag, "", "Argus API base URL, used in calls to this API")
129130
cmd.Flags().String(authorizationCustomEndpointFlag, "", "Authorization API base URL, used in calls to this API")
130131
cmd.Flags().String(dnsCustomEndpointFlag, "", "DNS API base URL, used in calls to this API")
@@ -144,7 +145,12 @@ func configureFlags(cmd *cobra.Command) {
144145
cmd.Flags().String(skeCustomEndpointFlag, "", "SKE API base URL, used in calls to this API")
145146
cmd.Flags().String(sqlServerFlexCustomEndpointFlag, "", "SQLServer Flex API base URL, used in calls to this API")
146147

147-
err := viper.BindPFlag(config.ArgusCustomEndpointKey, cmd.Flags().Lookup(argusCustomEndpointFlag))
148+
err := viper.BindPFlag(config.SessionTimeLimitKey, cmd.Flags().Lookup(sessionTimeLimitFlag))
149+
cobra.CheckErr(err)
150+
err = viper.BindPFlag(config.IdentityProviderCustomEndpointKey, cmd.Flags().Lookup(identityProviderCustomEndpointFlag))
151+
cobra.CheckErr(err)
152+
153+
err = viper.BindPFlag(config.ArgusCustomEndpointKey, cmd.Flags().Lookup(argusCustomEndpointFlag))
148154
cobra.CheckErr(err)
149155
err = viper.BindPFlag(config.AuthorizationCustomEndpointKey, cmd.Flags().Lookup(authorizationCustomEndpointFlag))
150156
cobra.CheckErr(err)

internal/cmd/config/unset/unset.go

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ const (
2020
projectIdFlag = globalflags.ProjectIdFlag
2121
verbosityFlag = globalflags.VerbosityFlag
2222

23-
sessionTimeLimitFlag = "session-time-limit"
23+
sessionTimeLimitFlag = "session-time-limit"
24+
identityProviderCustomEndpointFlag = "identity-provider-custom-endpoint"
2425

2526
argusCustomEndpointFlag = "argus-custom-endpoint"
2627
authorizationCustomEndpointFlag = "authorization-custom-endpoint"
@@ -43,11 +44,13 @@ const (
4344
)
4445

4546
type inputModel struct {
46-
Async bool
47-
OutputFormat bool
48-
ProjectId bool
49-
SessionTimeLimit bool
50-
Verbosity bool
47+
Async bool
48+
OutputFormat bool
49+
ProjectId bool
50+
Verbosity bool
51+
52+
SessionTimeLimit bool
53+
IdentityProviderCustomEndpoint bool
5154

5255
ArgusCustomEndpoint bool
5356
AuthorizationCustomEndpoint bool
@@ -98,11 +101,15 @@ func NewCmd(p *print.Printer) *cobra.Command {
98101
if model.ProjectId {
99102
viper.Set(config.ProjectIdKey, "")
100103
}
104+
if model.Verbosity {
105+
viper.Set(config.VerbosityKey, globalflags.VerbosityDefault)
106+
}
107+
101108
if model.SessionTimeLimit {
102109
viper.Set(config.SessionTimeLimitKey, config.SessionTimeLimitDefault)
103110
}
104-
if model.Verbosity {
105-
viper.Set(config.VerbosityKey, globalflags.VerbosityDefault)
111+
if model.IdentityProviderCustomEndpoint {
112+
viper.Set(config.IdentityProviderCustomEndpointKey, "")
106113
}
107114

108115
if model.ArgusCustomEndpoint {
@@ -175,9 +182,11 @@ func configureFlags(cmd *cobra.Command) {
175182
cmd.Flags().Bool(asyncFlag, false, "Configuration option to run commands asynchronously")
176183
cmd.Flags().Bool(projectIdFlag, false, "Project ID")
177184
cmd.Flags().Bool(outputFormatFlag, false, "Output format")
178-
cmd.Flags().Bool(sessionTimeLimitFlag, false, fmt.Sprintf("Maximum time before authentication is required again. If unset, defaults to %s", config.SessionTimeLimitDefault))
179185
cmd.Flags().Bool(verbosityFlag, false, "Verbosity of the CLI")
180186

187+
cmd.Flags().Bool(sessionTimeLimitFlag, false, fmt.Sprintf("Maximum time before authentication is required again. If unset, defaults to %s", config.SessionTimeLimitDefault))
188+
cmd.Flags().Bool(identityProviderCustomEndpointFlag, false, "Identity Provider base URL. If unset, uses the default base URL")
189+
181190
cmd.Flags().Bool(argusCustomEndpointFlag, false, "Argus API base URL. If unset, uses the default base URL")
182191
cmd.Flags().Bool(authorizationCustomEndpointFlag, false, "Authorization API base URL. If unset, uses the default base URL")
183192
cmd.Flags().Bool(dnsCustomEndpointFlag, false, "DNS API base URL. If unset, uses the default base URL")
@@ -200,11 +209,13 @@ func configureFlags(cmd *cobra.Command) {
200209

201210
func parseInput(p *print.Printer, cmd *cobra.Command) *inputModel {
202211
model := inputModel{
203-
Async: flags.FlagToBoolValue(p, cmd, asyncFlag),
204-
OutputFormat: flags.FlagToBoolValue(p, cmd, outputFormatFlag),
205-
ProjectId: flags.FlagToBoolValue(p, cmd, projectIdFlag),
206-
SessionTimeLimit: flags.FlagToBoolValue(p, cmd, sessionTimeLimitFlag),
207-
Verbosity: flags.FlagToBoolValue(p, cmd, verbosityFlag),
212+
Async: flags.FlagToBoolValue(p, cmd, asyncFlag),
213+
OutputFormat: flags.FlagToBoolValue(p, cmd, outputFormatFlag),
214+
ProjectId: flags.FlagToBoolValue(p, cmd, projectIdFlag),
215+
Verbosity: flags.FlagToBoolValue(p, cmd, verbosityFlag),
216+
217+
SessionTimeLimit: flags.FlagToBoolValue(p, cmd, sessionTimeLimitFlag),
218+
IdentityProviderCustomEndpoint: flags.FlagToBoolValue(p, cmd, identityProviderCustomEndpointFlag),
208219

209220
ArgusCustomEndpoint: flags.FlagToBoolValue(p, cmd, argusCustomEndpointFlag),
210221
AuthorizationCustomEndpoint: flags.FlagToBoolValue(p, cmd, authorizationCustomEndpointFlag),

internal/cmd/config/unset/unset_test.go

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ import (
1111

1212
func fixtureFlagValues(mods ...func(flagValues map[string]bool)) map[string]bool {
1313
flagValues := map[string]bool{
14-
asyncFlag: true,
15-
outputFormatFlag: true,
16-
projectIdFlag: true,
17-
sessionTimeLimitFlag: true,
18-
verbosityFlag: true,
14+
asyncFlag: true,
15+
outputFormatFlag: true,
16+
projectIdFlag: true,
17+
verbosityFlag: true,
18+
19+
sessionTimeLimitFlag: true,
20+
identityProviderCustomEndpointFlag: true,
1921

2022
argusCustomEndpointFlag: true,
2123
authorizationCustomEndpointFlag: true,
@@ -42,11 +44,13 @@ func fixtureFlagValues(mods ...func(flagValues map[string]bool)) map[string]bool
4244

4345
func fixtureInputModel(mods ...func(model *inputModel)) *inputModel {
4446
model := &inputModel{
45-
Async: true,
46-
OutputFormat: true,
47-
ProjectId: true,
48-
SessionTimeLimit: true,
49-
Verbosity: true,
47+
Async: true,
48+
OutputFormat: true,
49+
ProjectId: true,
50+
Verbosity: true,
51+
52+
SessionTimeLimit: true,
53+
IdentityProviderCustomEndpoint: true,
5054

5155
ArgusCustomEndpoint: true,
5256
AuthorizationCustomEndpoint: true,
@@ -92,9 +96,11 @@ func TestParseInput(t *testing.T) {
9296
model.Async = false
9397
model.OutputFormat = false
9498
model.ProjectId = false
95-
model.SessionTimeLimit = false
9699
model.Verbosity = false
97100

101+
model.SessionTimeLimit = false
102+
model.IdentityProviderCustomEndpoint = false
103+
98104
model.ArgusCustomEndpoint = false
99105
model.AuthorizationCustomEndpoint = false
100106
model.DNSCustomEndpoint = false
@@ -133,6 +139,16 @@ func TestParseInput(t *testing.T) {
133139
model.OutputFormat = false
134140
}),
135141
},
142+
{
143+
description: "identity provider custom endpoint empty",
144+
flagValues: fixtureFlagValues(func(flagValues map[string]bool) {
145+
flagValues[identityProviderCustomEndpointFlag] = false
146+
}),
147+
isValid: true,
148+
expectedModel: fixtureInputModel(func(model *inputModel) {
149+
model.IdentityProviderCustomEndpoint = false
150+
}),
151+
},
136152
{
137153
description: "argus custom endpoint empty",
138154
flagValues: fixtureFlagValues(func(flagValues map[string]bool) {

internal/cmd/curl/curl.go

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"io"
77
"net/http"
88
"net/http/httputil"
9-
"net/url"
109
"os"
1110
"strings"
1211
"time"
@@ -17,6 +16,7 @@ import (
1716
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
1817
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
1918
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
19+
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
2020

2121
"github.com/spf13/cobra"
2222
)
@@ -67,7 +67,7 @@ func NewCmd(p *print.Printer) *cobra.Command {
6767
`$ stackit curl https://dns.api.stackit.cloud/v1/projects/xxx/zones -X POST -H "Authorization: Bearer yyy" --fail`,
6868
),
6969
),
70-
Args: args.SingleArg(urlArg, validateURL),
70+
Args: args.SingleArg(urlArg, utils.ValidateSTACKITURL),
7171
RunE: func(cmd *cobra.Command, args []string) (err error) {
7272
model, err := parseInput(p, cmd, args)
7373
if err != nil {
@@ -113,21 +113,6 @@ func NewCmd(p *print.Printer) *cobra.Command {
113113
return cmd
114114
}
115115

116-
func validateURL(value string) error {
117-
urlStruct, err := url.Parse(value)
118-
if err != nil {
119-
return fmt.Errorf("parse URL: %w", err)
120-
}
121-
urlHost := urlStruct.Hostname()
122-
if urlHost == "" {
123-
return fmt.Errorf("bad url")
124-
}
125-
if !strings.HasSuffix(urlHost, "stackit.cloud") {
126-
return fmt.Errorf("only urls belonging to STACKIT are permitted, hostname must end in stackit.cloud")
127-
}
128-
return nil
129-
}
130-
131116
func configureFlags(cmd *cobra.Command) {
132117
requestMethodOptions := []string{
133118
http.MethodGet,

0 commit comments

Comments
 (0)