You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

mygithub.libinneed.workers.dev/stackitcloud/stackit-cli

Package Overview
Dependencies
Versions
175
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mygithub.libinneed.workers.dev/stackitcloud/stackit-cli - go Package Compare versions

Comparing version
v0.14.0
to
v0.15.0
+110
internal/pkg/auth/user_login_test.go
package auth
import (
"fmt"
"io"
"net/http"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/zalando/go-keyring"
)
type apiClientMocked struct {
getFails bool
getResponse string
}
func (a *apiClientMocked) Do(_ *http.Request) (*http.Response, error) {
if a.getFails {
return &http.Response{
StatusCode: http.StatusNotFound,
}, fmt.Errorf("not found")
}
return &http.Response{
Status: "200 OK",
StatusCode: http.StatusAccepted,
Body: io.NopCloser(strings.NewReader(a.getResponse)),
}, nil
}
func TestParseWellKnownConfig(t *testing.T) {
tests := []struct {
name string
getFails bool
getResponse string
isValid bool
expected *wellKnownConfig
}{
{
name: "success",
getFails: false,
getResponse: `{"issuer":"issuer","authorization_endpoint":"auth","token_endpoint":"token"}`,
isValid: true,
expected: &wellKnownConfig{
Issuer: "issuer",
AuthorizationEndpoint: "auth",
TokenEndpoint: "token",
},
},
{
name: "get_fails",
getFails: true,
getResponse: "",
isValid: false,
expected: nil,
},
{
name: "empty_response",
getFails: true,
getResponse: "",
isValid: false,
expected: nil,
},
{
name: "missing_issuer",
getFails: true,
getResponse: `{"authorization_endpoint":"auth","token_endpoint":"token"}`,
isValid: false,
expected: nil,
},
{
name: "missing_authorization",
getFails: true,
getResponse: `{"issuer":"issuer","token_endpoint":"token"}`,
isValid: false,
expected: nil,
},
{
name: "missing_token",
getFails: true,
getResponse: `{"issuer":"issuer","authorization_endpoint":"auth"}`,
isValid: false,
expected: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
keyring.MockInit()
testClient := apiClientMocked{
tt.getFails,
tt.getResponse,
}
got, err := parseWellKnownConfiguration(&testClient, "")
if tt.isValid && err != nil {
t.Fatalf("expected no error, got %v", err)
}
if !tt.isValid && err == nil {
t.Fatalf("expected error, got none")
}
if tt.isValid && !cmp.Equal(*got, *tt.expected) {
t.Fatalf("expected %v, got %v", tt.expected, got)
}
})
}
}
+27
-27

@@ -32,29 +32,29 @@ ## stackit config set

```
--allowed-url-domain string Domain name, used for the verification of the URLs that are given in the custom identity provider endpoint and "STACKIT curl" command
--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
--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
--mongodbflex-custom-endpoint string MongoDB Flex API base URL, used in calls to this API
--object-storage-custom-endpoint string Object Storage API base URL, used in calls to this API
--observability-custom-endpoint string Observability API base URL, used in calls to this API
--opensearch-custom-endpoint string OpenSearch API base URL, used in calls to this API
--postgresflex-custom-endpoint string PostgreSQL Flex API base URL, used in calls to this API
--rabbitmq-custom-endpoint string RabbitMQ API base URL, used in calls to this API
--redis-custom-endpoint string Redis API base URL, used in calls to this API
--resource-manager-custom-endpoint string Resource Manager API base URL, used in calls to this API
--runcommand-custom-endpoint string Run Command API base URL, used in calls to this API
--secrets-manager-custom-endpoint string Secrets Manager API base URL, used in calls to this API
--serverbackup-custom-endpoint string Server Backup API base URL, used in calls to this API
--service-account-custom-endpoint string Service Account API base URL, used in calls to this API
--service-enablement-custom-endpoint string Service Enablement API base URL, used in calls to this API
--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
--allowed-url-domain string Domain name, used for the verification of the URLs that are given in the custom identity provider endpoint and "STACKIT curl" command
--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-well-known-configuration string Identity Provider well-known OpenID configuration URL, used for user authentication
--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
--mongodbflex-custom-endpoint string MongoDB Flex API base URL, used in calls to this API
--object-storage-custom-endpoint string Object Storage API base URL, used in calls to this API
--observability-custom-endpoint string Observability API base URL, used in calls to this API
--opensearch-custom-endpoint string OpenSearch API base URL, used in calls to this API
--postgresflex-custom-endpoint string PostgreSQL Flex API base URL, used in calls to this API
--rabbitmq-custom-endpoint string RabbitMQ API base URL, used in calls to this API
--redis-custom-endpoint string Redis API base URL, used in calls to this API
--resource-manager-custom-endpoint string Resource Manager API base URL, used in calls to this API
--runcommand-custom-endpoint string Run Command API base URL, used in calls to this API
--secrets-manager-custom-endpoint string Secrets Manager API base URL, used in calls to this API
--serverbackup-custom-endpoint string Server Backup API base URL, used in calls to this API
--service-account-custom-endpoint string Service Account API base URL, used in calls to this API
--service-enablement-custom-endpoint string Service Enablement API base URL, used in calls to this API
--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
```

@@ -61,0 +61,0 @@

@@ -29,33 +29,33 @@ ## stackit config unset

```
--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
--async Configuration option to run commands asynchronously
--authorization-custom-endpoint Authorization API base URL. If unset, uses the default base URL
--dns-custom-endpoint DNS API base URL. If unset, uses the default base URL
-h, --help Help for "stackit config unset"
--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
--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
--mongodbflex-custom-endpoint MongoDB Flex API base URL. If unset, uses the default base URL
--object-storage-custom-endpoint Object Storage API base URL. If unset, uses the default base URL
--observability-custom-endpoint Observability API base URL. If unset, uses the default base URL
--opensearch-custom-endpoint OpenSearch API base URL. If unset, uses the default base URL
--output-format Output format
--postgresflex-custom-endpoint PostgreSQL Flex API base URL. If unset, uses the default base URL
--project-id Project ID
--rabbitmq-custom-endpoint RabbitMQ API base URL. If unset, uses the default base URL
--redis-custom-endpoint Redis API base URL. If unset, uses the default base URL
--resource-manager-custom-endpoint Resource Manager API base URL. If unset, uses the default base URL
--runcommand-custom-endpoint Server Command base URL. If unset, uses the default base URL
--secrets-manager-custom-endpoint Secrets Manager API base URL. If unset, uses the default base URL
--serverbackup-custom-endpoint Server Backup base URL. If unset, uses the default base URL
--service-account-custom-endpoint Service Account API base URL. If unset, uses the default base URL
--service-enablement-custom-endpoint Service Enablement API base URL. If unset, uses the default base URL
--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
--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
--async Configuration option to run commands asynchronously
--authorization-custom-endpoint Authorization API base URL. If unset, uses the default base URL
--dns-custom-endpoint DNS API base URL. If unset, uses the default base URL
-h, --help Help for "stackit config unset"
--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-well-known-configuration Identity Provider well-known OpenID configuration URL. If unset, uses the default identity provider
--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
--mongodbflex-custom-endpoint MongoDB Flex API base URL. If unset, uses the default base URL
--object-storage-custom-endpoint Object Storage API base URL. If unset, uses the default base URL
--observability-custom-endpoint Observability API base URL. If unset, uses the default base URL
--opensearch-custom-endpoint OpenSearch API base URL. If unset, uses the default base URL
--output-format Output format
--postgresflex-custom-endpoint PostgreSQL Flex API base URL. If unset, uses the default base URL
--project-id Project ID
--rabbitmq-custom-endpoint RabbitMQ API base URL. If unset, uses the default base URL
--redis-custom-endpoint Redis API base URL. If unset, uses the default base URL
--resource-manager-custom-endpoint Resource Manager API base URL. If unset, uses the default base URL
--runcommand-custom-endpoint Server Command base URL. If unset, uses the default base URL
--secrets-manager-custom-endpoint Secrets Manager API base URL. If unset, uses the default base URL
--serverbackup-custom-endpoint Server Backup base URL. If unset, uses the default base URL
--service-account-custom-endpoint Service Account API base URL. If unset, uses the default base URL
--service-enablement-custom-endpoint Service Enablement API base URL. If unset, uses the default base URL
--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
```

@@ -62,0 +62,0 @@

+7
-7

@@ -18,8 +18,8 @@ module github.com/stackitcloud/stackit-cli

github.com/spf13/viper v1.19.0
github.com/stackitcloud/stackit-sdk-go/core v0.12.0
github.com/stackitcloud/stackit-sdk-go/core v0.13.0
github.com/stackitcloud/stackit-sdk-go/services/authorization v0.3.0
github.com/stackitcloud/stackit-sdk-go/services/dns v0.10.0
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.8.0
github.com/stackitcloud/stackit-sdk-go/services/mongodbflex v0.14.0
github.com/stackitcloud/stackit-sdk-go/services/opensearch v0.16.0
github.com/stackitcloud/stackit-sdk-go/services/mongodbflex v0.15.0
github.com/stackitcloud/stackit-sdk-go/services/opensearch v0.18.0
github.com/stackitcloud/stackit-sdk-go/services/postgresflex v0.15.0

@@ -82,8 +82,8 @@ github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.9.0

github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v0.14.0
github.com/stackitcloud/stackit-sdk-go/services/logme v0.17.0
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.17.0
github.com/stackitcloud/stackit-sdk-go/services/logme v0.19.0
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.19.0
github.com/stackitcloud/stackit-sdk-go/services/objectstorage v0.10.0
github.com/stackitcloud/stackit-sdk-go/services/observability v0.1.0
github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v0.17.0
github.com/stackitcloud/stackit-sdk-go/services/redis v0.17.0
github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v0.19.0
github.com/stackitcloud/stackit-sdk-go/services/redis v0.19.0
github.com/subosito/gotenv v1.6.0 // indirect

@@ -90,0 +90,0 @@ go.uber.org/multierr v1.11.0 // indirect

+14
-14

@@ -126,4 +126,4 @@ github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4uEoM0=

github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stackitcloud/stackit-sdk-go/core v0.12.0 h1:auIzUUNRuydKOScvpICP4MifGgvOajiDQd+ncGmBL0U=
github.com/stackitcloud/stackit-sdk-go/core v0.12.0/go.mod h1:mDX1mSTsB3mP+tNBGcFNx6gH1mGBN4T+dVt+lcw7nlw=
github.com/stackitcloud/stackit-sdk-go/core v0.13.0 h1:BtJT2WXqZdexPPQi/HPUIr8g4JUPOCheh6J9dxiCQ4Q=
github.com/stackitcloud/stackit-sdk-go/core v0.13.0/go.mod h1:mDX1mSTsB3mP+tNBGcFNx6gH1mGBN4T+dVt+lcw7nlw=
github.com/stackitcloud/stackit-sdk-go/services/authorization v0.3.0 h1:AyzBgcbd0rCm+2+xaWqtfibjWmkKlO+U+7qxqvtKpJ8=

@@ -137,8 +137,8 @@ github.com/stackitcloud/stackit-sdk-go/services/authorization v0.3.0/go.mod h1:1sLuXa7Qvp9f+wKWdRjyNe8B2F8JX7nSTd8fBKadri4=

github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v0.14.0/go.mod h1:wsO3+vXe1XiKLeCIctWAptaHQZ07Un7kmLTQ+drbj7w=
github.com/stackitcloud/stackit-sdk-go/services/logme v0.17.0 h1:S8UZYBu2lHmKCPTR17jZetIal8X7cHO1gVRv101UdPw=
github.com/stackitcloud/stackit-sdk-go/services/logme v0.17.0/go.mod h1:bj9cn1treNSxKTRCEmESwqfENN8vCYn60HUnEA0P83c=
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.17.0 h1:+amOO/LW/PfUVU2ptxoB8PuNacawjjX2gGh7bHd45RE=
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.17.0/go.mod h1:kPetkX9hNm9HkRyiKQL/tlgdi8frZdMP8afg0mEvQ9s=
github.com/stackitcloud/stackit-sdk-go/services/mongodbflex v0.14.0 h1:FaJYVfha+atvPfFIf3h3+BFjOjeux9OBHukG1J98kq0=
github.com/stackitcloud/stackit-sdk-go/services/mongodbflex v0.14.0/go.mod h1:iFerEzGmkg6R13ldFUyHUWHm0ac9cS4ftTDLhP0k/dU=
github.com/stackitcloud/stackit-sdk-go/services/logme v0.19.0 h1:KcsF549yXOrm8zlqFCNV+lf2L4zvQuh4L2i3kgdWbOE=
github.com/stackitcloud/stackit-sdk-go/services/logme v0.19.0/go.mod h1:bj9cn1treNSxKTRCEmESwqfENN8vCYn60HUnEA0P83c=
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.19.0 h1:tlU/Z1Z8IXqWdkdIQYSHkO/btqYX80rg3oddKBzn430=
github.com/stackitcloud/stackit-sdk-go/services/mariadb v0.19.0/go.mod h1:kPetkX9hNm9HkRyiKQL/tlgdi8frZdMP8afg0mEvQ9s=
github.com/stackitcloud/stackit-sdk-go/services/mongodbflex v0.15.0 h1:WjjG2GJ+7fBH7Akil2srDBZhCbqxNpAR8LhYwIoeylo=
github.com/stackitcloud/stackit-sdk-go/services/mongodbflex v0.15.0/go.mod h1:iFerEzGmkg6R13ldFUyHUWHm0ac9cS4ftTDLhP0k/dU=
github.com/stackitcloud/stackit-sdk-go/services/objectstorage v0.10.0 h1:tn1MD1nu+gYEbT3lslRI6BrapKwuvHv5Wi2Zw9uVPPc=

@@ -148,10 +148,10 @@ github.com/stackitcloud/stackit-sdk-go/services/objectstorage v0.10.0/go.mod h1:dkVMJI88eJ3Xs0ZV15r4tUpgitUGJXcvrX3RL4Zq2bQ=

github.com/stackitcloud/stackit-sdk-go/services/observability v0.1.0/go.mod h1:cSnBZGdtx4jnn9HEefkQHDrm8+PuS0NCWvukVfuwP/8=
github.com/stackitcloud/stackit-sdk-go/services/opensearch v0.16.0 h1:EEjhfIFiC4TsaFKB4mkxz6NFz4InfVs5STmWc+oEjgQ=
github.com/stackitcloud/stackit-sdk-go/services/opensearch v0.16.0/go.mod h1:ZecMIf9oYj2DGZqWh93l97WdVaRdLl+tW5Fq3YKGwBM=
github.com/stackitcloud/stackit-sdk-go/services/opensearch v0.18.0 h1:pzHA3sxaAsZzKjsCffMcToAk3ooZsj1PxwZODGRTpoI=
github.com/stackitcloud/stackit-sdk-go/services/opensearch v0.18.0/go.mod h1:ZecMIf9oYj2DGZqWh93l97WdVaRdLl+tW5Fq3YKGwBM=
github.com/stackitcloud/stackit-sdk-go/services/postgresflex v0.15.0 h1:05wQYhO37Z4y8xAD+4OTYz6rYu6eJEmwMfCG4tjETEc=
github.com/stackitcloud/stackit-sdk-go/services/postgresflex v0.15.0/go.mod h1:SdrqGLCkilL6wl1+jcxmLtks2IocgIg+bsyeyYUIzR4=
github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v0.17.0 h1:k8GIrOQj+COIgkkHNNXw5ciUzvWU/RjL5XD7t5DTrOM=
github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v0.17.0/go.mod h1:eSgnPBknTJh7t+jVKN+xzeAh+Cg1USOlH3QCyfvG20g=
github.com/stackitcloud/stackit-sdk-go/services/redis v0.17.0 h1:jnApmhchW5FYNWss1d2hJzH7O3slBOYa2wEseg5pl3o=
github.com/stackitcloud/stackit-sdk-go/services/redis v0.17.0/go.mod h1:3LhiTR/DMbKR2HuleTzlFHltR1MT1KD0DeW46X6K2GE=
github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v0.19.0 h1:qZ62GSQKw73JrS7a9WeGILMki26KNyqrMOmD8r41u/A=
github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v0.19.0/go.mod h1:eSgnPBknTJh7t+jVKN+xzeAh+Cg1USOlH3QCyfvG20g=
github.com/stackitcloud/stackit-sdk-go/services/redis v0.19.0 h1:/s9GUIpwZTN6I7J4nKmBBmxc6lPJYpCHHxYsC+gDsZs=
github.com/stackitcloud/stackit-sdk-go/services/redis v0.19.0/go.mod h1:3LhiTR/DMbKR2HuleTzlFHltR1MT1KD0DeW46X6K2GE=
github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.9.0 h1:qCbvGqdG9saRB++UlhXt5ieCCDCITROqL5K2nm38efU=

@@ -158,0 +158,0 @@ github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.9.0/go.mod h1:p16qz/pAW8b1gEhqMpIgJfutRPeDPqQLlbVGyCo3f8o=

@@ -69,3 +69,3 @@ # Installation

If you can't get latest updates due to an expired key, please go back to Step 1 and execute the commands again to fetch and use the latest key.
> If you can't install the `stackit` package due to an expired key, please go back to step `1` to import the latest public key.

@@ -72,0 +72,0 @@ #### Any distribution

@@ -68,2 +68,13 @@ package create

func fixtureRequiredRequest(mods ...func(request *iaas.ApiCreateNetworkRequest)) iaas.ApiCreateNetworkRequest {
request := testClient.CreateNetwork(testCtx, testProjectId)
request = request.CreateNetworkPayload(iaas.CreateNetworkPayload{
Name: utils.Ptr("example-network-name"),
})
for _, mod := range mods {
mod(&request)
}
return request
}
func fixturePayload(mods ...func(payload *iaas.CreateNetworkPayload)) iaas.CreateNetworkPayload {

@@ -230,2 +241,13 @@ payload := iaas.CreateNetworkPayload{

},
{
description: "only name in payload",
model: &inputModel{
GlobalFlagModel: &globalflags.GlobalFlagModel{
ProjectId: testProjectId,
Verbosity: globalflags.VerbosityDefault,
},
Name: utils.Ptr("example-network-name"),
},
expectedRequest: fixtureRequiredRequest(),
},
}

@@ -232,0 +254,0 @@

@@ -156,3 +156,3 @@ package create

if model.IPv6DnsNameServers != nil {
if model.IPv6DnsNameServers != nil || model.IPv6PrefixLength != nil {
addressFamily.Ipv6 = &iaas.CreateNetworkIPv6Body{

@@ -164,3 +164,3 @@ Nameservers: model.IPv6DnsNameServers,

if model.IPv4DnsNameServers != nil {
if model.IPv4DnsNameServers != nil || model.IPv4PrefixLength != nil {
addressFamily.Ipv4 = &iaas.CreateNetworkIPv4Body{

@@ -173,6 +173,9 @@ Nameservers: model.IPv4DnsNameServers,

payload := iaas.CreateNetworkPayload{
Name: model.Name,
AddressFamily: addressFamily,
Name: model.Name,
}
if addressFamily.Ipv4 != nil || addressFamily.Ipv6 != nil {
payload.AddressFamily = addressFamily
}
return req.CreateNetworkPayload(payload)

@@ -179,0 +182,0 @@ }

@@ -37,3 +37,2 @@ package update

IPv6DnsNameServers *[]string
IPv6PrefixLength *int64
}

@@ -170,7 +169,10 @@

payload := iaas.PartialUpdateNetworkPayload{
Name: model.Name,
AddressFamily: addressFamily,
Name: model.Name,
}
if addressFamily.Ipv4 != nil || addressFamily.Ipv6 != nil {
payload.AddressFamily = addressFamily
}
return req.PartialUpdateNetworkPayload(payload)
}

@@ -20,6 +20,6 @@ package set

const (
sessionTimeLimitFlag = "session-time-limit"
identityProviderCustomEndpointFlag = "identity-provider-custom-endpoint"
identityProviderCustomClientIdFlag = "identity-provider-custom-client-id"
allowedUrlDomainFlag = "allowed-url-domain"
sessionTimeLimitFlag = "session-time-limit"
identityProviderCustomWellKnownConfigurationFlag = "identity-provider-custom-well-known-configuration"
identityProviderCustomClientIdFlag = "identity-provider-custom-client-id"
allowedUrlDomainFlag = "allowed-url-domain"

@@ -135,3 +135,3 @@ authorizationCustomEndpointFlag = "authorization-custom-endpoint"

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(identityProviderCustomWellKnownConfigurationFlag, "", "Identity Provider well-known OpenID configuration URL, used for user authentication")
cmd.Flags().String(identityProviderCustomClientIdFlag, "", "Identity Provider client ID, used for user authentication")

@@ -164,3 +164,3 @@ 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`)

cobra.CheckErr(err)
err = viper.BindPFlag(config.IdentityProviderCustomEndpointKey, cmd.Flags().Lookup(identityProviderCustomEndpointFlag))
err = viper.BindPFlag(config.IdentityProviderCustomWellKnownConfigurationKey, cmd.Flags().Lookup(identityProviderCustomWellKnownConfigurationFlag))
cobra.CheckErr(err)

@@ -196,3 +196,3 @@ err = viper.BindPFlag(config.IdentityProviderCustomClientIdKey, cmd.Flags().Lookup(identityProviderCustomClientIdFlag))

cobra.CheckErr(err)
err = viper.BindPFlag(config.ResourceManagerEndpointKey, cmd.Flags().Lookup(skeCustomEndpointFlag))
err = viper.BindPFlag(config.ResourceManagerEndpointKey, cmd.Flags().Lookup(resourceManagerCustomEndpointFlag))
cobra.CheckErr(err)

@@ -199,0 +199,0 @@ err = viper.BindPFlag(config.SecretsManagerCustomEndpointKey, cmd.Flags().Lookup(secretsManagerCustomEndpointFlag))

@@ -19,6 +19,6 @@ package unset

sessionTimeLimitFlag: true,
identityProviderCustomEndpointFlag: true,
identityProviderCustomClientIdFlag: true,
allowedUrlDomainFlag: true,
sessionTimeLimitFlag: true,
identityProviderCustomWellKnownConfigurationFlag: true,
identityProviderCustomClientIdFlag: true,
allowedUrlDomainFlag: true,

@@ -161,3 +161,3 @@ authorizationCustomEndpointFlag: true,

flagValues: fixtureFlagValues(func(flagValues map[string]bool) {
flagValues[identityProviderCustomEndpointFlag] = false
flagValues[identityProviderCustomWellKnownConfigurationFlag] = false
}),

@@ -164,0 +164,0 @@ isValid: true,

@@ -23,6 +23,6 @@ package unset

sessionTimeLimitFlag = "session-time-limit"
identityProviderCustomEndpointFlag = "identity-provider-custom-endpoint"
identityProviderCustomClientIdFlag = "identity-provider-custom-client-id"
allowedUrlDomainFlag = "allowed-url-domain"
sessionTimeLimitFlag = "session-time-limit"
identityProviderCustomWellKnownConfigurationFlag = "identity-provider-custom-well-known-configuration"
identityProviderCustomClientIdFlag = "identity-provider-custom-client-id"
allowedUrlDomainFlag = "allowed-url-domain"

@@ -125,3 +125,3 @@ authorizationCustomEndpointFlag = "authorization-custom-endpoint"

if model.IdentityProviderCustomEndpoint {
viper.Set(config.IdentityProviderCustomEndpointKey, "")
viper.Set(config.IdentityProviderCustomWellKnownConfigurationKey, "")
}

@@ -220,3 +220,3 @@ if model.IdentityProviderCustomClientID {

cmd.Flags().Bool(sessionTimeLimitFlag, false, fmt.Sprintf("Maximum time before authentication is required again. If unset, defaults to %s", config.SessionTimeLimitDefault))
cmd.Flags().Bool(identityProviderCustomEndpointFlag, false, "Identity Provider base URL. If unset, uses the default base URL")
cmd.Flags().Bool(identityProviderCustomWellKnownConfigurationFlag, false, "Identity Provider well-known OpenID configuration URL. If unset, uses the default identity provider")
cmd.Flags().Bool(identityProviderCustomClientIdFlag, false, "Identity Provider client ID, used for user authentication")

@@ -257,3 +257,3 @@ cmd.Flags().Bool(allowedUrlDomainFlag, false, fmt.Sprintf("Domain name, used for the verification of the URLs that are given in the IDP endpoint and curl commands. If unset, defaults to %s", config.AllowedUrlDomainDefault))

SessionTimeLimit: flags.FlagToBoolValue(p, cmd, sessionTimeLimitFlag),
IdentityProviderCustomEndpoint: flags.FlagToBoolValue(p, cmd, identityProviderCustomEndpointFlag),
IdentityProviderCustomEndpoint: flags.FlagToBoolValue(p, cmd, identityProviderCustomWellKnownConfigurationFlag),
IdentityProviderCustomClientID: flags.FlagToBoolValue(p, cmd, identityProviderCustomClientIdFlag),

@@ -260,0 +260,0 @@ AllowedUrlDomain: flags.FlagToBoolValue(p, cmd, allowedUrlDomainFlag),

@@ -40,2 +40,3 @@ package auth

TOKEN_CUSTOM_ENDPOINT authFieldKey = "token_custom_endpoint"
IDP_TOKEN_ENDPOINT authFieldKey = "idp_token_endpoint" //nolint:gosec // linter false positive
)

@@ -61,2 +62,3 @@

TOKEN_CUSTOM_ENDPOINT,
IDP_TOKEN_ENDPOINT,
authFlowType,

@@ -63,0 +65,0 @@ }

@@ -26,4 +26,4 @@ package auth

const (
defaultIDPEndpoint = "https://accounts.stackit.cloud/oauth/v2"
defaultCLIClientID = "stackit-cli-0000-0000-000000000001"
defaultWellKnownConfig = "https://accounts.stackit.cloud/.well-known/openid-configuration"
defaultCLIClientID = "stackit-cli-0000-0000-000000000001"

@@ -48,10 +48,14 @@ loginSuccessPath = "/login-successful"

type apiClient interface {
Do(req *http.Request) (*http.Response, error)
}
// AuthorizeUser implements the PKCE OAuth2 flow.
func AuthorizeUser(p *print.Printer, isReauthentication bool) error {
idpEndpoint, err := getIDPEndpoint()
idpWellKnownConfigURL, err := getIDPWellKnownConfigURL()
if err != nil {
return err
return fmt.Errorf("get IDP well-known configuration: %w", err)
}
if idpEndpoint != defaultIDPEndpoint {
p.Warn("You are using a custom identity provider (%s) for authentication.\n", idpEndpoint)
if idpWellKnownConfigURL != defaultWellKnownConfig {
p.Warn("You are using a custom identity provider well-known configuration (%s) for authentication.\n", idpWellKnownConfigURL)
err := p.PromptForEnter("Press Enter to proceed with the login...")

@@ -63,2 +67,9 @@ if err != nil {

p.Debug(print.DebugLevel, "get IDP well-known configuration from %s", idpWellKnownConfigURL)
httpClient := &http.Client{}
idpWellKnownConfig, err := parseWellKnownConfiguration(httpClient, idpWellKnownConfigURL)
if err != nil {
return fmt.Errorf("parse IDP well-known configuration: %w", err)
}
idpClientID, err := getIDPClientID()

@@ -106,3 +117,3 @@ if err != nil {

Endpoint: oauth2.Endpoint{
AuthURL: fmt.Sprintf("%s/authorize", idpEndpoint),
AuthURL: idpWellKnownConfig.AuthorizationEndpoint,
},

@@ -154,3 +165,3 @@ Scopes: []string{"openid offline_access email"},

// Trade the authorization code and the code verifier for access and refresh tokens
accessToken, refreshToken, err := getUserAccessAndRefreshTokens(idpEndpoint, idpClientID, codeVerifier, code, redirectURL)
accessToken, refreshToken, err := getUserAccessAndRefreshTokens(idpWellKnownConfig, idpClientID, codeVerifier, code, redirectURL)
if err != nil {

@@ -230,3 +241,3 @@ errServer = fmt.Errorf("retrieve tokens: %w", err)

p.Debug(print.DebugLevel, "opening browser for authentication")
p.Debug(print.DebugLevel, "using authentication server on %s", idpEndpoint)
p.Debug(print.DebugLevel, "using authentication server on %s", idpWellKnownConfig.Issuer)
p.Debug(print.DebugLevel, "using client ID %s for authentication ", idpClientID)

@@ -257,5 +268,4 @@

// getUserAccessAndRefreshTokens trades the authorization code retrieved from the first OAuth2 leg for an access token and a refresh token
func getUserAccessAndRefreshTokens(authDomain, clientID, codeVerifier, authorizationCode, callbackURL string) (accessToken, refreshToken string, err error) {
// Set the authUrl and form-encoded data for the POST to the access token endpoint
authUrl := fmt.Sprintf("%s/token", authDomain)
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
data := fmt.Sprintf(

@@ -270,3 +280,3 @@ "grant_type=authorization_code&client_id=%s"+

// Create the request and execute it
req, _ := http.NewRequest("POST", authUrl, payload)
req, _ := http.NewRequest("POST", idpWellKnownConfig.TokenEndpoint, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")

@@ -342,1 +352,46 @@ httpClient := &http.Client{}

}
// parseWellKnownConfiguration gets the well-known OpenID configuration from the provided URL and returns it as a JSON
// the method also stores the IDP token endpoint in the authentication storage
func parseWellKnownConfiguration(httpClient apiClient, wellKnownConfigURL string) (wellKnownConfig *wellKnownConfig, err error) {
req, _ := http.NewRequest("GET", wellKnownConfigURL, http.NoBody)
res, err := httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("make the request: %w", err)
}
// Process the response
defer func() {
closeErr := res.Body.Close()
if closeErr != nil {
err = fmt.Errorf("close response body: %w", closeErr)
}
}()
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("read response body: %w", err)
}
err = json.Unmarshal(body, &wellKnownConfig)
if err != nil {
return nil, fmt.Errorf("unmarshal response: %w", err)
}
if wellKnownConfig == nil {
return nil, fmt.Errorf("nil well-known configuration response")
}
if wellKnownConfig.Issuer == "" {
return nil, fmt.Errorf("found no issuer")
}
if wellKnownConfig.AuthorizationEndpoint == "" {
return nil, fmt.Errorf("found no authorization endpoint")
}
if wellKnownConfig.TokenEndpoint == "" {
return nil, fmt.Errorf("found no token endpoint")
}
err = SetAuthField(IDP_TOKEN_ENDPOINT, wellKnownConfig.TokenEndpoint)
if err != nil {
return nil, fmt.Errorf("set token endpoint in the authentication storage: %w", err)
}
return wellKnownConfig, err
}

@@ -17,2 +17,6 @@ package auth

const (
testTokenEndpoint = "https://accounts.stackit.cloud/oauth/v2/token" //nolint:gosec // linter false positive
)
type clientTransport struct {

@@ -32,7 +36,3 @@ t *testing.T // May write test errors

}
idpEndpoint, err := getIDPEndpoint()
if err != nil {
rt.t.Fatalf("get IDP endpoint for test: %v", err)
}
if fmt.Sprintf("https://%s", reqURL) == fmt.Sprintf("%s/token", idpEndpoint) {
if fmt.Sprintf("https://%s", reqURL) == testTokenEndpoint {
return rt.roundTripRefreshTokens()

@@ -359,4 +359,5 @@ }

err = SetAuthFieldMap(map[authFieldKey]string{
ACCESS_TOKEN: accessToken,
REFRESH_TOKEN: refreshToken,
ACCESS_TOKEN: accessToken,
REFRESH_TOKEN: refreshToken,
IDP_TOKEN_ENDPOINT: testTokenEndpoint,
})

@@ -363,0 +364,0 @@ if err != nil {

@@ -22,2 +22,3 @@ package auth

refreshToken string
tokenEndpoint string
}

@@ -80,4 +81,5 @@

authFields := map[authFieldKey]string{
ACCESS_TOKEN: "",
REFRESH_TOKEN: "",
ACCESS_TOKEN: "",
REFRESH_TOKEN: "",
IDP_TOKEN_ENDPOINT: "",
}

@@ -92,2 +94,3 @@ err = GetAuthFieldMap(authFields)

utf.refreshToken = authFields[REFRESH_TOKEN]
utf.tokenEndpoint = authFields[IDP_TOKEN_ENDPOINT]
return nil

@@ -162,7 +165,2 @@ }

func buildRequestToRefreshTokens(utf *userTokenFlow) (*http.Request, error) {
idpEndpoint, err := getIDPEndpoint()
if err != nil {
return nil, err
}
idpClientID, err := getIDPClientID()

@@ -175,3 +173,3 @@ if err != nil {

http.MethodPost,
fmt.Sprintf("%s/token", idpEndpoint),
utf.tokenEndpoint,
http.NoBody,

@@ -178,0 +176,0 @@ )

@@ -10,3 +10,3 @@ package auth

func TestGetIDPEndpoint(t *testing.T) {
func TestGetWellKnownConfig(t *testing.T) {
tests := []struct {

@@ -57,3 +57,3 @@ name string

isValid: true,
expected: defaultIDPEndpoint,
expected: defaultWellKnownConfig,
},

@@ -64,6 +64,6 @@ }

viper.Reset()
viper.Set(config.IdentityProviderCustomEndpointKey, tt.idpCustomEndpoint)
viper.Set(config.IdentityProviderCustomWellKnownConfigurationKey, tt.idpCustomEndpoint)
viper.Set(config.AllowedUrlDomainKey, tt.allowedUrlDomain)
got, err := getIDPEndpoint()
got, err := getIDPWellKnownConfigURL()

@@ -70,0 +70,0 @@ if tt.isValid && err != nil {

@@ -11,15 +11,21 @@ package auth

func getIDPEndpoint() (string, error) {
idpEndpoint := defaultIDPEndpoint
type wellKnownConfig struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
}
customIDPEndpoint := viper.GetString(config.IdentityProviderCustomEndpointKey)
if customIDPEndpoint != "" {
idpEndpoint = customIDPEndpoint
err := utils.ValidateURLDomain(idpEndpoint)
func getIDPWellKnownConfigURL() (wellKnownConfigURL string, err error) {
wellKnownConfigURL = defaultWellKnownConfig
customWellKnownConfig := viper.GetString(config.IdentityProviderCustomWellKnownConfigurationKey)
if customWellKnownConfig != "" {
wellKnownConfigURL = customWellKnownConfig
err := utils.ValidateURLDomain(wellKnownConfigURL)
if err != nil {
return "", fmt.Errorf("validate custom identity provider endpoint: %w", err)
return "", fmt.Errorf("validate custom identity provider well-known configuration: %w", err)
}
}
return idpEndpoint, nil
return wellKnownConfigURL, nil
}

@@ -26,0 +32,0 @@

@@ -20,5 +20,5 @@ package config

IdentityProviderCustomEndpointKey = "identity_provider_custom_endpoint"
IdentityProviderCustomClientIdKey = "identity_provider_custom_client_id"
AllowedUrlDomainKey = "allowed_url_domain"
IdentityProviderCustomWellKnownConfigurationKey = "identity_provider_custom_well_known_configuration"
IdentityProviderCustomClientIdKey = "identity_provider_custom_client_id"
AllowedUrlDomainKey = "allowed_url_domain"

@@ -75,3 +75,3 @@ AuthorizationCustomEndpointKey = "authorization_custom_endpoint"

IdentityProviderCustomEndpointKey,
IdentityProviderCustomWellKnownConfigurationKey,
IdentityProviderCustomClientIdKey,

@@ -160,3 +160,3 @@ AllowedUrlDomainKey,

viper.SetDefault(SessionTimeLimitKey, SessionTimeLimitDefault)
viper.SetDefault(IdentityProviderCustomEndpointKey, "")
viper.SetDefault(IdentityProviderCustomWellKnownConfigurationKey, "")
viper.SetDefault(IdentityProviderCustomClientIdKey, "")

@@ -163,0 +163,0 @@ viper.SetDefault(AllowedUrlDomainKey, AllowedUrlDomainDefault)

@@ -20,3 +20,3 @@ <div align="center">

> [!WARNING]
> On August 26 2024, The STACKIT Argus service was renamed to STACKIT Observability.
> On August 26 2024, The STACKIT Argus service was renamed to STACKIT Observability.
>

@@ -27,9 +27,2 @@ > This means that there is a new command group `observability`, which offers the same functionality as the deprecated `argus` command.

> [!WARNING]
> On July 9 2024, the new [STACKIT Identity Provider (IDP)](https://docs.stackit.cloud/stackit/en/release-notes-23101442.html#ReleaseNotes-2024-06-21-identity-provider) was released. We are happy to announce that on [v0.9.0](https://github.com/stackitcloud/stackit-cli/releases/tag/v0.9.0), the new IDP was integrated in the STACKIT CLI, where it is used for user authentication.
>
> This also means that the **user authentication on STACKIT CLI versions released before July 9 2024 is no longer guaranteed to work for all services**.
>
> Please make sure to **update your STACKIT CLI to the latest version after July 9 2024** to ensure that you can continue to use all STACKIT services.
## Installation

@@ -78,3 +71,3 @@

| Service | CLI Commands | Status |
|------------------------------------|---------------------------|---------------------------|
| ---------------------------------- | ------------------------- | ------------------------- |
| Observability | `observability` | :white_check_mark: |

@@ -81,0 +74,0 @@ | Infrastructure as a Service (IaaS) | `beta network-area` | :white_check_mark: (beta) |