From 9c52265ab85c75e5a97da3acc2013639d0a71303 Mon Sep 17 00:00:00 2001 From: Gabriela Limberea Date: Mon, 23 Dec 2024 14:58:57 +0200 Subject: [PATCH 1/3] feat: add ttl flag to token generate --- commands/token/create.go | 65 +++- commands/token/token_integration_test.go | 2 + go.mod | 2 +- go.sum | 4 +- internal/utils/convert.go | 299 ++++++++++++++++++ .../auth-v1/resources/mocks/TokenService.go | 4 +- services/auth-v1/resources/token.go | 7 +- .../ionos-cloud/sdk-go-auth/.gitignore | 1 - .../ionos-cloud/sdk-go-auth/README.md | 160 ++++++---- .../ionos-cloud/sdk-go-auth/api_tokens.go | 179 ++++++----- .../ionos-cloud/sdk-go-auth/client.go | 116 ++++++- .../ionos-cloud/sdk-go-auth/configuration.go | 16 +- .../ionos-cloud/sdk-go-auth/logger.go | 4 +- .../sdk-go-auth/model_delete_response.go | 21 +- .../ionos-cloud/sdk-go-auth/model_error.go | 22 +- .../sdk-go-auth/model_error_messages.go | 22 +- .../ionos-cloud/sdk-go-auth/model_jwt.go | 21 +- .../ionos-cloud/sdk-go-auth/model_token.go | 29 +- .../ionos-cloud/sdk-go-auth/model_tokens.go | 21 +- .../ionos-cloud/sdk-go-auth/response.go | 30 +- .../ionos-cloud/sdk-go-auth/utils.go | 8 +- vendor/modules.txt | 4 +- 22 files changed, 824 insertions(+), 213 deletions(-) diff --git a/commands/token/create.go b/commands/token/create.go index 72e6e0665..a85ecfd45 100644 --- a/commands/token/create.go +++ b/commands/token/create.go @@ -5,26 +5,37 @@ import ( "errors" "fmt" + "github.com/ionos-cloud/ionosctl/v6/internal/constants" "github.com/ionos-cloud/ionosctl/v6/internal/core" "github.com/ionos-cloud/ionosctl/v6/internal/printer/jsontabwriter" + "github.com/ionos-cloud/ionosctl/v6/internal/utils" authservice "github.com/ionos-cloud/ionosctl/v6/services/auth-v1" "github.com/spf13/viper" ) func TokenPostCmd() *core.Command { - cmd := core.NewCommand(context.Background(), nil, core.CommandBuilder{ - Namespace: "token", - Resource: "token", - Verb: "generate", - Aliases: []string{"create"}, - ShortDesc: "Create a new Token", - LongDesc: "Use this command to generate a new Token. Only the JSON Web Token, associated with user credentials, will be displayed.", - Example: generateTokenExample, - PreCmdRun: core.NoPreRun, - CmdRun: runTokenCreate, - InitClient: true, - }) - cmd.AddIntFlag(authservice.ArgContractNo, "", 0, "Users with multiple contracts can provide the contract number, for which the token is generated") + cmd := core.NewCommand( + context.Background(), nil, core.CommandBuilder{ + Namespace: "token", + Resource: "token", + Verb: "generate", + Aliases: []string{"create"}, + ShortDesc: "Create a new Token", + LongDesc: "Use this command to generate a new Token. Only the JSON Web Token, associated with user credentials, will be displayed.", + Example: generateTokenExample, + PreCmdRun: core.NoPreRun, + CmdRun: runTokenCreate, + InitClient: true, + }, + ) + cmd.AddIntFlag( + authservice.ArgContractNo, "", 0, + "Users with multiple contracts can provide the contract number, for which the token is generated", + ) + cmd.AddSetFlag( + constants.FlagTtl, "", "1Y", []string{"1h", "4h", "1D", "7D", "1M", "2M", "3M", "6M", "1Y"}, + "Token Time to Live in seconds", + ) return cmd } @@ -32,12 +43,34 @@ func TokenPostCmd() *core.Command { func runTokenCreate(c *core.CommandConfig) error { fmt.Fprintf(c.Command.Command.ErrOrStderr(), jsontabwriter.GenerateVerboseOutput("Generating new token..")) + var contractNumber int32 if viper.IsSet(core.GetFlagName(c.NS, authservice.ArgContractNo)) { - fmt.Fprintf(c.Command.Command.ErrOrStderr(), jsontabwriter.GenerateVerboseOutput(contractNumberMessage, - viper.GetInt32(core.GetFlagName(c.NS, authservice.ArgContractNo)))) + fmt.Fprintf( + c.Command.Command.ErrOrStderr(), jsontabwriter.GenerateVerboseOutput( + contractNumberMessage, + viper.GetInt32(core.GetFlagName(c.NS, authservice.ArgContractNo)), + ), + ) + contractNumber = viper.GetInt32(core.GetFlagName(c.NS, authservice.ArgContractNo)) } - newJwt, _, err := c.AuthV1Services.Tokens().Create(viper.GetInt32(core.GetFlagName(c.NS, authservice.ArgContractNo))) + var ttl int + var err error + if viper.IsSet(core.GetFlagName(c.NS, constants.FlagTtl)) { + fmt.Fprintf( + c.Command.Command.ErrOrStderr(), + jsontabwriter.GenerateVerboseOutput( + "Token TTL: %v", + viper.GetString(core.GetFlagName(c.NS, constants.FlagTtl)), + ), + ) + + ttl, err = utils.ConvertTime(viper.GetString(core.GetFlagName(c.NS, constants.FlagTtl)), utils.Seconds) + if err != nil { + return err + } + } + newJwt, _, err := c.AuthV1Services.Tokens().Create(contractNumber, int32(ttl)) if err != nil { return err } diff --git a/commands/token/token_integration_test.go b/commands/token/token_integration_test.go index 139080029..aca060095 100644 --- a/commands/token/token_integration_test.go +++ b/commands/token/token_integration_test.go @@ -66,6 +66,7 @@ func testCreateToken(t *testing.T) { tokFirstCreationTime = time.Now().In(time.UTC) c := token.TokenPostCmd() + c.Command.Flags().Set(constants.FlagTtl, "1h") err = c.Command.Execute() assert.NoError(t, err) @@ -109,6 +110,7 @@ func testCreateToken(t *testing.T) { buff := bytes.NewBuffer([]byte{}) c = token.TokenPostCmd() c.Command.SetOut(buff) + c.Command.Flags().Set(constants.FlagTtl, "1h") err = c.Command.Execute() assert.NoError(t, err) diff --git a/go.mod b/go.mod index 3f44a40db..d51a3e6c1 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/fatih/structs v1.1.0 github.com/gofrs/uuid/v5 v5.0.0 github.com/golang/mock v1.6.0 - github.com/ionos-cloud/sdk-go-auth v1.0.6 + github.com/ionos-cloud/sdk-go-auth v1.0.10 github.com/ionos-cloud/sdk-go-container-registry v1.1.0 github.com/ionos-cloud/sdk-go-dataplatform v1.0.2 github.com/ionos-cloud/sdk-go-dbaas-mongo v1.3.1 diff --git a/go.sum b/go.sum index d85840587..2451b53d0 100644 --- a/go.sum +++ b/go.sum @@ -244,8 +244,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/ionos-cloud/sdk-go-auth v1.0.6 h1:N7XQ8JLKM9OS1DDlDCIN3Nk4RV4MuNvHFd50evuWgSM= -github.com/ionos-cloud/sdk-go-auth v1.0.6/go.mod h1:4MuUIZbnQjgNalEB9LUzIuBTI1keqgA7EpJsjEvMAls= +github.com/ionos-cloud/sdk-go-auth v1.0.10 h1:aHWstSqtmWZxvNVEye42MBK9WcbTQnbc3GBgPj6tmcE= +github.com/ionos-cloud/sdk-go-auth v1.0.10/go.mod h1:yVHBsuAWLbcnlgfviCDZ5HE7k3KwkmK7GjgaAvnnKxI= github.com/ionos-cloud/sdk-go-cdn v1.1.0 h1:bwtrey2m1mElQV9TlhzR39mC6IMeWF2P5ztd6cmRKfw= github.com/ionos-cloud/sdk-go-cdn v1.1.0/go.mod h1:W2XZ5CYhKROyvtLaz3VgTKe+nXI1+NZD1gE/YliHUeU= github.com/ionos-cloud/sdk-go-cert-manager v1.0.1 h1:QGnenRREavvU0ZrXvY4hmCMXRyvmKj5jaXsFX9Apfd0= diff --git a/internal/utils/convert.go b/internal/utils/convert.go index 0df28371f..2b161fed0 100644 --- a/internal/utils/convert.go +++ b/internal/utils/convert.go @@ -102,3 +102,302 @@ func convertToGB(size, unit string) (int, error) { return 0, errors.New("error converting in GB, no suffix: MB, GB, TB, PB matched") } } + +const ( + Seconds = "s" + Minutes = "m" + Hours = "h" + Days = "D" + Months = "M" + Years = "Y" +) + +func ConvertTime(timeToConvert, unitToConvertTo string) (int, error) { + for _, unit := range []string{Seconds, Minutes, Hours, Days, Months, Years} { + if !strings.HasSuffix(timeToConvert, unit) { + continue + } + timeToConvert = strings.ReplaceAll(timeToConvert, " ", "") + switch unitToConvertTo { + case Seconds: + return convertToSeconds(timeToConvert, unit) + case Minutes: + return convertToMinutes(timeToConvert, unit) + case Hours: + return convertToHours(timeToConvert, unit) + case Days: + return convertToDays(timeToConvert, unit) + case Months: + return convertToMonths(timeToConvert, unit) + case Years: + return convertToYears(timeToConvert, unit) + default: + return 0, errors.New("error converting to the specified unit") + } + } + return strconv.Atoi(timeToConvert) +} + +func convertToSeconds(time, unit string) (int, error) { + switch unit { + case Seconds: + s := strings.ReplaceAll(time, unit, "") + return strconv.Atoi(s) + case Minutes: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m * 60, nil + case Hours: + s := strings.ReplaceAll(time, unit, "") + h, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return h * 60 * 60, nil + case Days: + s := strings.ReplaceAll(time, unit, "") + d, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return d * 60 * 60 * 24, nil + case Months: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m * 60 * 60 * 24 * 30, nil + case Years: + s := strings.ReplaceAll(time, unit, "") + y, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return y * 60 * 60 * 24 * 365, nil + } + return 0, errors.New("error converting to seconds, no suffix: s, m, h, D, M, Y matched") +} + +func convertToMinutes(time, unit string) (int, error) { + switch unit { + case Seconds: + s := strings.ReplaceAll(time, unit, "") + sec, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return sec / 60, nil + case Minutes: + s := strings.ReplaceAll(time, unit, "") + return strconv.Atoi(s) + case Hours: + s := strings.ReplaceAll(time, unit, "") + h, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return h * 60, nil + case Days: + s := strings.ReplaceAll(time, unit, "") + d, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return d * 60 * 24, nil + case Months: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m * 60 * 24 * 30, nil + case Years: + s := strings.ReplaceAll(time, unit, "") + y, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return y * 60 * 24 * 365, nil + } + return 0, errors.New("error converting to minutes, no suffix: s, m, h, D, M, Y matched") +} + +func convertToHours(time, unit string) (int, error) { + switch unit { + case Seconds: + s := strings.ReplaceAll(time, unit, "") + sec, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return sec / (60 * 60), nil + case Minutes: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m / 60, nil + case Hours: + s := strings.ReplaceAll(time, unit, "") + return strconv.Atoi(s) + case Days: + s := strings.ReplaceAll(time, unit, "") + d, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return d * 24, nil + case Months: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m * 24 * 30, nil + case Years: + s := strings.ReplaceAll(time, unit, "") + y, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return y * 24 * 365, nil + } + return 0, errors.New("error converting to hours, no suffix: s, m, h, D, M, Y matched") +} + +func convertToDays(time, unit string) (int, error) { + switch unit { + case Seconds: + s := strings.ReplaceAll(time, unit, "") + sec, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return sec / (60 * 60 * 24), nil + case Minutes: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m / (60 * 24), nil + case Hours: + s := strings.ReplaceAll(time, unit, "") + h, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return h / 24, nil + case Days: + s := strings.ReplaceAll(time, unit, "") + return strconv.Atoi(s) + case Months: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m * 30, nil + case Years: + s := strings.ReplaceAll(time, unit, "") + y, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return y * 365, nil + } + return 0, errors.New("error converting to days, no suffix: s, m, h, D, M, Y matched") +} + +func convertToMonths(time, unit string) (int, error) { + switch unit { + case Seconds: + s := strings.ReplaceAll(time, unit, "") + sec, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return sec / (60 * 60 * 24 * 30), nil + case Minutes: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m / (60 * 24 * 30), nil + case Hours: + s := strings.ReplaceAll(time, unit, "") + h, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return h / (24 * 30), nil + case Days: + s := strings.ReplaceAll(time, unit, "") + d, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return d / 30, nil + case Months: + s := strings.ReplaceAll(time, unit, "") + return strconv.Atoi(s) + case Years: + s := strings.ReplaceAll(time, unit, "") + y, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return y * 12, nil + } + return 0, errors.New("error converting to months, no suffix: s, m, h, D, M, Y matched") +} + +func convertToYears(time, unit string) (int, error) { + switch unit { + case Seconds: + s := strings.ReplaceAll(time, unit, "") + sec, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return sec / (60 * 60 * 24 * 365), nil + case Minutes: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m / (60 * 24 * 365), nil + case Hours: + s := strings.ReplaceAll(time, unit, "") + h, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return h / (24 * 365), nil + case Days: + s := strings.ReplaceAll(time, unit, "") + d, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return d / 365, nil + case Months: + s := strings.ReplaceAll(time, unit, "") + m, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return m / 12, nil + case Years: + s := strings.ReplaceAll(time, unit, "") + return strconv.Atoi(s) + } + return 0, errors.New("error converting to years, no suffix: s, m, h, D, M, Y matched") +} diff --git a/services/auth-v1/resources/mocks/TokenService.go b/services/auth-v1/resources/mocks/TokenService.go index 7c8a8e8ae..d20edf885 100644 --- a/services/auth-v1/resources/mocks/TokenService.go +++ b/services/auth-v1/resources/mocks/TokenService.go @@ -35,9 +35,9 @@ func (m *MockTokensService) EXPECT() *MockTokensServiceMockRecorder { } // Create mocks base method. -func (m *MockTokensService) Create(contractNumber int32) (*resources.Jwt, *resources.Response, error) { +func (m *MockTokensService) Create(contractNumber int32, ttl int32) (*resources.Jwt, *resources.Response, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", contractNumber) + ret := m.ctrl.Call(m, "Create", contractNumber, ttl) ret0, _ := ret[0].(*resources.Jwt) ret1, _ := ret[1].(*resources.Response) ret2, _ := ret[2].(error) diff --git a/services/auth-v1/resources/token.go b/services/auth-v1/resources/token.go index cb5078fc6..58ee24004 100644 --- a/services/auth-v1/resources/token.go +++ b/services/auth-v1/resources/token.go @@ -32,7 +32,7 @@ type DeleteResponse struct { type TokensService interface { List(contractNumber int32) (Tokens, *Response, error) Get(tokenId string, contractNumber int32) (*Token, *Response, error) - Create(contractNumber int32) (*Jwt, *Response, error) + Create(contractNumber int32, ttl int32) (*Jwt, *Response, error) DeleteByID(tokenId string, contractNumber int32) (*DeleteResponse, *Response, error) DeleteByCriteria(criteria string, contractNumber int32) (*DeleteResponse, *Response, error) } @@ -69,11 +69,14 @@ func (ts *tokensService) Get(tokenId string, contractNumber int32) (*Token, *Res return &Token{token}, &Response{*res}, err } -func (ts *tokensService) Create(contractNumber int32) (*Jwt, *Response, error) { +func (ts *tokensService) Create(contractNumber int32, ttl int32) (*Jwt, *Response, error) { req := ts.client.TokensApi.TokensGenerate(ts.context) if contractNumber != 0 { req = req.XContractNumber(contractNumber) } + if ttl != 0 { + req = req.Ttl(ttl) + } token, res, err := ts.client.TokensApi.TokensGenerateExecute(req) return &Jwt{token}, &Response{*res}, err } diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/.gitignore b/vendor/github.com/ionos-cloud/sdk-go-auth/.gitignore index 8a5a70956..daf913b1b 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/.gitignore +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/.gitignore @@ -6,7 +6,6 @@ # Folders _obj _test -.idea/ # Architecture specific extensions/prefixes *.[568vq] diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/README.md b/vendor/github.com/ionos-cloud/sdk-go-auth/README.md index 975e899c8..a341d7416 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/README.md +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/README.md @@ -1,120 +1,140 @@ -[![CI](https://github.com/ionos-cloud/ionosctl/workflows/CI/badge.svg)](https://github.com/ionos-cloud/sdk-go-auth/actions) -[![Gitter](https://img.shields.io/gitter/room/ionos-cloud/sdk-general)](https://gitter.im/ionos-cloud/sdk-general) -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=sdk-go-auth&metric=alert_status)](https://sonarcloud.io/dashboard?id=sdk-go-auth) -[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=sdk-go-auth&metric=bugs)](https://sonarcloud.io/dashboard?id=sdk-go-auth) -[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=sdk-go-auth&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=sdk-go-auth) -[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=sdk-go-auth&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=sdk-go-auth) -[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=sdk-go-auth&metric=security_rating)](https://sonarcloud.io/dashboard?id=sdk-go-auth) -[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=sdk-go-auth&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=sdk-go-auth) -[![Release](https://img.shields.io/github/v/release/ionos-cloud/sdk-go-auth.svg)](https://github.com/ionos-cloud/sdk-go-auth/releases/latest) -[![Release Date](https://img.shields.io/github/release-date/ionos-cloud/sdk-go-auth.svg)](https://github.com/ionos-cloud/sdk-go-auth/releases/latest) -[![Go](https://img.shields.io/github/go-mod/go-version/ionos-cloud/sdk-go-auth.svg)](https://github.com/ionos-cloud/sdk-go-auth) +# Go API client for ionoscloud -![Alt text](.github/IONOS.CLOUD.BLU.svg?raw=true "Title") +Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). -# Go Auth API client for ionoscloud - -The IONOS Cloud SDK Auth for GO provides you with access to the IONOS Cloud Auth API. Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). ## Overview - -This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [OpenAPI-spec](https://www.openapis.org/) from a remote server, you can easily generate an API client. +This API client was generated by the [OpenAPI Generator](https://openapi-generator.tech) project. By using the [OpenAPI-spec](https://www.openapis.org/) from a remote server, you can easily generate an API client. - API version: 1.0 -- Package version: 1.0.0 +- Package version: 1.0.10 - Build package: org.openapitools.codegen.languages.GoClientCodegen -## Getting Started - -An IONOS account is required for access to the Cloud API; credentials from your registration are used to authenticate against the IONOS Cloud API. - ## Installation -Install the Go language from the official [Go installation](https://golang.org/doc/install) guide. - Install the following dependencies: ```shell go get github.com/stretchr/testify/assert -go get golang.org/x/oauth2 go get golang.org/x/net/context -go get github.com/antihax/optional ``` -Put the package under your project folder by adding it to the `go.mod`: +Put the package under your project folder and add the following in import: ```golang -require "github.com/ionos-cloud/sdk-go-auth" +import ionoscloud "github.com/ionos-cloud/sdk-go-auth" ``` -You can get the package locally using: +To use a proxy, set the environment variable `HTTP_PROXY`: ```golang -go get "github.com/ionos-cloud/sdk-go-auth" +os.Setenv("HTTP_PROXY", "http://proxy_name:proxy_port") ``` -## Authentication +## Configuration of Server URL + +Default configuration comes with `Servers` field that contains server objects as defined in the OpenAPI specification. + +### Select Server Configuration -The username and password or the authentication token can be manually specified when initializing the sdk client: +For using other server than the one defined on index 0 set context value `sw.ContextServerIndex` of type `int`. ```golang +ctx := context.WithValue(context.Background(), ionoscloud.ContextServerIndex, 1) +``` + +### Templated Server URL -client := ionossdk.NewAPIClient(ionossdk.NewConfiguration(username, password, token, hostUrl)) +Templated server URL is formatted using default variables from configuration or from context value `sw.ContextServerVariables` of type `map[string]string`. + +```golang +ctx := context.WithValue(context.Background(), ionoscloud.ContextServerVariables, map[string]string{ + "basePath": "v2", +}) ``` -Environment variables can also be used. The sdk uses the following variables: +Note, enum values are always validated and all unused variables are silently ignored. -- IONOS_USERNAME - to specify the username used to log in -- IONOS_PASSWORD - to specify the password -- IONOS_TOKEN - if an authentication token is being used -- IONOS_API_URL - to specify the API endpoint in order to overwrite it +## Documentation for API Endpoints -In this case, the client configuration needs to be initialized using `NewConfigurationFromEnv()` +All URIs are relative to *https://api.ionos.com/auth/v1* -```golang +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*TokensApi* | [**TokensDeleteByCriteria**](docs/api/TokensApi.md#tokensdeletebycriteria) | **Delete** /tokens | Delete tokens by criteria +*TokensApi* | [**TokensDeleteById**](docs/api/TokensApi.md#tokensdeletebyid) | **Delete** /tokens/{tokenId} | Delete tokens +*TokensApi* | [**TokensFindById**](docs/api/TokensApi.md#tokensfindbyid) | **Get** /tokens/{tokenId} | Get tokens by Key ID +*TokensApi* | [**TokensGenerate**](docs/api/TokensApi.md#tokensgenerate) | **Get** /tokens/generate | Create new tokens +*TokensApi* | [**TokensGet**](docs/api/TokensApi.md#tokensget) | **Get** /tokens | List all tokens -client := ionossdk.NewAPIClient(ionossdk.NewConfigurationFromEnv()) +## Documentation For Models + + - [DeleteResponse](docs/models/DeleteResponse.md) + - [Error](docs/models/Error.md) + - [ErrorMessages](docs/models/ErrorMessages.md) + - [Jwt](docs/models/Jwt.md) + - [Token](docs/models/Token.md) + - [Tokens](docs/models/Tokens.md) + + +## Documentation For Authorization + + +Authentication schemes defined for the API: +### BasicAuthentication + +- **Type**: HTTP basic authentication + +Example + +```golang +auth := context.WithValue(context.Background(), sw.ContextBasicAuth, sw.BasicAuth{ + UserName: "username", + Password: "password", +}) +r, err := client.Service.Operation(auth, args) ``` -## Environment Variables +### TokenAuthentication -Environment Variable | Description ---- | --- -`IONOS_USERNAME` | Specify the username used to login, to authenticate against the IONOS Cloud API | -`IONOS_PASSWORD` | Specify the password used to login, to authenticate against the IONOS Cloud API | -`IONOS_TOKEN` | Specify the token used to login, if a token is being used instead of username and password | -`IONOS_API_URL` | Specify the API URL. It will overwrite the API endpoint default value `api.ionos.com`. Note: the host URL does not contain the `/cloudapi/v5` path, so it should _not_ be included in the `IONOS_API_URL` environment variable | +- **Type**: API key +- **API key parameter name**: Authorization +- **Location**: HTTP header -## Documentation for API Endpoints +Note, each API key must be added to a map of `map[string]APIKey` where the key is: Authorization and passed in as the auth context for each request. -All paths are relative to *https://api.ionos.com/auth/v1* +Example -### TokenApi +```golang +auth := context.WithValue( + context.Background(), + sw.ContextAPIKeys, + map[string]sw.APIKey{ + "Authorization": {Key: "API_KEY_STRING"}, + }, + ) +r, err := client.Service.Operation(auth, args) +``` -Method | HTTP request | Description -------------- | ------------- | ------------- -[**CreateToken**](docs/api/TokenApi.md#createtoken) | **Get** /tokens/generate | Create new tokens -[**DeleteTokenByCriteria**](docs/api/TokenApi.md#deletetokenbycriteria) | **Delete** /tokens | Delete tokens by criteria -[**DeleteTokenById**](docs/api/TokenApi.md#deletetokenbyid) | **Delete** /tokens/{tokenId} | Delete tokens -[**GetAllTokens**](docs/api/TokenApi.md#getalltokens) | **Get** /tokens | List all tokens -[**GetTokenById**](docs/api/TokenApi.md#gettokenbyid) | **Get** /tokens/{tokenId} | Get tokens by Key ID -## Documentation For Models +## Documentation for Utility Methods -- [DeleteResponse](docs/models/DeleteResponse.md) -- [Error](docs/models/Error.md) -- [ErrorMessages](docs/models/ErrorMessages.md) -- [Jwt](docs/models/Jwt.md) -- [Token](docs/models/Token.md) -- [Tokens](docs/models/Tokens.md) +Due to the fact that model structure members are all pointers, this package contains +a number of utility functions to easily obtain pointers to values of basic types. +Each of these functions takes a value of the given basic type and returns a pointer to it: -## FAQ +* `PtrBool` +* `PtrInt` +* `PtrInt32` +* `PtrInt64` +* `PtrFloat` +* `PtrFloat32` +* `PtrFloat64` +* `PtrString` +* `PtrTime` -* How can I open a bug report/feature request? +## Author -Bug reports and feature requests can be opened in the Issues repository: [https://github.com/ionos-cloud/sdk-go-auth/issues/new/choose](https://github.com/ionos-cloud/sdk-go-auth/issues/new/choose) -* Can I contribute to the GO SDK for Auth API? -Pure SDKs are automatically generated using OpenAPI Generator and don’t support manual changes. If you require changes, please open an issue, and we will try to address it. diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/api_tokens.go b/vendor/github.com/ionos-cloud/sdk-go-auth/api_tokens.go index 172758d92..ffbdfc82e 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/api_tokens.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/api_tokens.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -11,13 +11,12 @@ package ionoscloud import ( - "fmt" - "strings" - _context "context" - _ioutil "io/ioutil" + "fmt" + "io" _nethttp "net/http" _neturl "net/url" + "strings" ) // Linger please @@ -49,10 +48,11 @@ func (r ApiTokensDeleteByCriteriaRequest) Execute() (DeleteResponse, *APIRespons } /* - * TokensDeleteByCriteria Delete tokens by criteria - * Delete one or multiple tokens by the required `criteria` parameter values: `ALL`, `EXPIRED` and `CURRENT`. With parameter values `ALL` and `EXPIRED`, 'Basic Authentication' or 'Token Authentication' tokens with valid credentials must be encapsulated in the header. With value `CURRENT`, only the 'Token Authentication' with valid credentials is required. Users with multiple contracts must also provide a valid contract number in the `X-Contract-Number` header. - * @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - * @return ApiTokensDeleteByCriteriaRequest +* TokensDeleteByCriteria Delete tokens by criteria +* Delete one or multiple tokens by the required `criteria` parameter values: `ALL`, `EXPIRED` and `CURRENT`. With parameter values `ALL` and `EXPIRED`, 'Basic Authentication' or 'Token Authentication' tokens with valid credentials must be encapsulated in the header.
Note:

From **March 15, 2024**, users with **2-Factor Authentication** must use **2FA-secured** tokens to delete existing tokens. Token deletion can only be performed through DCD in the **Token Manager**.
With value `CURRENT`, only the 'Token Authentication' with valid credentials is required. Users with multiple contracts must also provide a valid contract number in the `X-Contract-Number` header. + +* @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). +* @return ApiTokensDeleteByCriteriaRequest */ func (a *TokensApiService) TokensDeleteByCriteria(ctx _context.Context) ApiTokensDeleteByCriteriaRequest { return ApiTokensDeleteByCriteriaRequest{ @@ -90,7 +90,6 @@ func (a *TokensApiService) TokensDeleteByCriteriaExecute(r ApiTokensDeleteByCrit } localVarQueryParams.Add("criteria", parameterToString(*r.criteria, "")) - // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -114,7 +113,7 @@ func (a *TokensApiService) TokensDeleteByCriteriaExecute(r ApiTokensDeleteByCrit if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["Token Authentication"]; ok { + if apiKey, ok := auth["TokenAuthentication"]; ok { var key string if apiKey.Prefix != "" { key = apiKey.Prefix + " " + apiKey.Key @@ -130,20 +129,21 @@ func (a *TokensApiService) TokensDeleteByCriteriaExecute(r ApiTokensDeleteByCrit return localVarReturnValue, nil, err } - localVarHTTPResponse, err := a.client.callAPI(req) + localVarHTTPResponse, httpRequestTime, err := a.client.callAPI(req) localVarAPIResponse := &APIResponse{ - Response: localVarHTTPResponse, - Method: localVarHTTPMethod, - RequestURL: localVarPath, - Operation: "TokensDeleteByCriteria", + Response: localVarHTTPResponse, + Method: localVarHTTPMethod, + RequestTime: httpRequestTime, + RequestURL: localVarPath, + Operation: "TokensDeleteByCriteria", } if err != nil || localVarHTTPResponse == nil { return localVarReturnValue, localVarAPIResponse, err } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() localVarAPIResponse.Payload = localVarBody if err != nil { @@ -154,13 +154,13 @@ func (a *TokensApiService) TokensDeleteByCriteriaExecute(r ApiTokensDeleteByCrit newErr := GenericOpenAPIError{ statusCode: localVarHTTPResponse.StatusCode, body: localVarBody, - error: fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, string(localVarBody)), + error: fmt.Sprintf("%s: %s", localVarHTTPResponse.Status, string(localVarBody)), } if localVarHTTPResponse.StatusCode == 401 { var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -169,7 +169,7 @@ func (a *TokensApiService) TokensDeleteByCriteriaExecute(r ApiTokensDeleteByCrit var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -178,7 +178,7 @@ func (a *TokensApiService) TokensDeleteByCriteriaExecute(r ApiTokensDeleteByCrit var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -187,7 +187,7 @@ func (a *TokensApiService) TokensDeleteByCriteriaExecute(r ApiTokensDeleteByCrit var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -225,12 +225,18 @@ func (r ApiTokensDeleteByIdRequest) Execute() (DeleteResponse, *APIResponse, err } /* - * TokensDeleteById Delete tokens - * Delete a token by Key ID (`tokenId`). To access the endpoint, 'Basic Authentication' or 'Token Authentication' tokens with valid credentials must be encapsulated in the header. Users with multiple contracts must also provide a valid contract number in the `X-Contract-Number` header. - * @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - * @param tokenId The Key ID of the token (can be retrieved from the header section of the token). - * @return ApiTokensDeleteByIdRequest - */ + - TokensDeleteById Delete tokens + - Delete a token by Key ID (`tokenId`). To access the endpoint, 'Basic Authentication' or 'Token Authentication' tokens with valid credentials must be encapsulated in the header.
+ Note:

+ From March 15, 2024, users with 2-Factor Authentication must use 2FA-secured tokens to delete existing + tokens. Token deletion can only be performed through DCD in the Token Manager. + +
Users with multiple contracts must also provide a valid contract number in the `X-Contract-Number` header. + + - @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + - @param tokenId The Key ID of the token (can be retrieved from the header section of the token). + - @return ApiTokensDeleteByIdRequest +*/ func (a *TokensApiService) TokensDeleteById(ctx _context.Context, tokenId string) ApiTokensDeleteByIdRequest { return ApiTokensDeleteByIdRequest{ ApiService: a, @@ -288,7 +294,7 @@ func (a *TokensApiService) TokensDeleteByIdExecute(r ApiTokensDeleteByIdRequest) if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["Token Authentication"]; ok { + if apiKey, ok := auth["TokenAuthentication"]; ok { var key string if apiKey.Prefix != "" { key = apiKey.Prefix + " " + apiKey.Key @@ -304,20 +310,21 @@ func (a *TokensApiService) TokensDeleteByIdExecute(r ApiTokensDeleteByIdRequest) return localVarReturnValue, nil, err } - localVarHTTPResponse, err := a.client.callAPI(req) + localVarHTTPResponse, httpRequestTime, err := a.client.callAPI(req) localVarAPIResponse := &APIResponse{ - Response: localVarHTTPResponse, - Method: localVarHTTPMethod, - RequestURL: localVarPath, - Operation: "TokensDeleteById", + Response: localVarHTTPResponse, + Method: localVarHTTPMethod, + RequestTime: httpRequestTime, + RequestURL: localVarPath, + Operation: "TokensDeleteById", } if err != nil || localVarHTTPResponse == nil { return localVarReturnValue, localVarAPIResponse, err } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() localVarAPIResponse.Payload = localVarBody if err != nil { @@ -328,13 +335,13 @@ func (a *TokensApiService) TokensDeleteByIdExecute(r ApiTokensDeleteByIdRequest) newErr := GenericOpenAPIError{ statusCode: localVarHTTPResponse.StatusCode, body: localVarBody, - error: fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, string(localVarBody)), + error: fmt.Sprintf("%s: %s", localVarHTTPResponse.Status, string(localVarBody)), } if localVarHTTPResponse.StatusCode == 401 { var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -343,7 +350,7 @@ func (a *TokensApiService) TokensDeleteByIdExecute(r ApiTokensDeleteByIdRequest) var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -352,7 +359,7 @@ func (a *TokensApiService) TokensDeleteByIdExecute(r ApiTokensDeleteByIdRequest) var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -361,7 +368,7 @@ func (a *TokensApiService) TokensDeleteByIdExecute(r ApiTokensDeleteByIdRequest) var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -462,7 +469,7 @@ func (a *TokensApiService) TokensFindByIdExecute(r ApiTokensFindByIdRequest) (To if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["Token Authentication"]; ok { + if apiKey, ok := auth["TokenAuthentication"]; ok { var key string if apiKey.Prefix != "" { key = apiKey.Prefix + " " + apiKey.Key @@ -478,20 +485,21 @@ func (a *TokensApiService) TokensFindByIdExecute(r ApiTokensFindByIdRequest) (To return localVarReturnValue, nil, err } - localVarHTTPResponse, err := a.client.callAPI(req) + localVarHTTPResponse, httpRequestTime, err := a.client.callAPI(req) localVarAPIResponse := &APIResponse{ - Response: localVarHTTPResponse, - Method: localVarHTTPMethod, - RequestURL: localVarPath, - Operation: "TokensFindById", + Response: localVarHTTPResponse, + Method: localVarHTTPMethod, + RequestTime: httpRequestTime, + RequestURL: localVarPath, + Operation: "TokensFindById", } if err != nil || localVarHTTPResponse == nil { return localVarReturnValue, localVarAPIResponse, err } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() localVarAPIResponse.Payload = localVarBody if err != nil { @@ -502,13 +510,13 @@ func (a *TokensApiService) TokensFindByIdExecute(r ApiTokensFindByIdRequest) (To newErr := GenericOpenAPIError{ statusCode: localVarHTTPResponse.StatusCode, body: localVarBody, - error: fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, string(localVarBody)), + error: fmt.Sprintf("%s: %s", localVarHTTPResponse.Status, string(localVarBody)), } if localVarHTTPResponse.StatusCode == 401 { var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -517,7 +525,7 @@ func (a *TokensApiService) TokensFindByIdExecute(r ApiTokensFindByIdRequest) (To var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -526,7 +534,7 @@ func (a *TokensApiService) TokensFindByIdExecute(r ApiTokensFindByIdRequest) (To var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -535,7 +543,7 @@ func (a *TokensApiService) TokensFindByIdExecute(r ApiTokensFindByIdRequest) (To var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -544,7 +552,7 @@ func (a *TokensApiService) TokensFindByIdExecute(r ApiTokensFindByIdRequest) (To var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -569,12 +577,17 @@ type ApiTokensGenerateRequest struct { ctx _context.Context ApiService *TokensApiService xContractNumber *int32 + ttl *int32 } func (r ApiTokensGenerateRequest) XContractNumber(xContractNumber int32) ApiTokensGenerateRequest { r.xContractNumber = &xContractNumber return r } +func (r ApiTokensGenerateRequest) Ttl(ttl int32) ApiTokensGenerateRequest { + r.ttl = &ttl + return r +} func (r ApiTokensGenerateRequest) Execute() (Jwt, *APIResponse, error) { return r.ApiService.TokensGenerateExecute(r) @@ -582,11 +595,14 @@ func (r ApiTokensGenerateRequest) Execute() (Jwt, *APIResponse, error) { /* - TokensGenerate Create new tokens - - Users can generate new tokens ([JWT](https://jwt.io/) or [JSON Web Token](https://tools.ietf.org/html/rfc7519)). By default, new tokens are linked to the user’s contract. Users with multiple contracts must provide the contract number, for which the token is generated, in the `X-Contract-Number` header; otherwise, an error response is returned. + - Users can generate new tokens ([JWT](https://jwt.io/) or [JSON Web Token](https://tools.ietf.org/html/rfc7519)). By default, new tokens are linked to the user’s contract. Users with multiple contracts must provide the contract number, for which the token is generated, in the `X-Contract-Number` header; otherwise, an error response is returned.

To access this endpoint, 'Basic Authentication' or 'Token Authentication' tokens with valid credentials must be encapsulated in the header, by users with one or with multiple contracts.
+ Note:

+ From March 15, 2024, users with 2-Factor + Authentication enabled must generate new tokens using 2FA-secured tokens through DCD in the Token Manager. + Tokens generated this way will not automatically inherit the 2FA-secured property. -To access this endpoint, 'Basic Authentication' or 'Token Authentication' tokens with valid credentials must be encapsulated in the header, by users with one or with multiple contracts. +
The response will contain a newly-generated token for accessing any IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). The token can be used to access the APIs without providing the contract number in the `X-Contract-Number` header, by users with one or with multiple contracts. However, a valid contract number must be provided in the `X-Contract-Number` header to access the Auth API. By default, generated access tokens will expire after one year (subject to change). -The response will contain a newly-generated token for accessing any IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). The token can be used to access the APIs without providing the contract number in the `X-Contract-Number` header, by users with one or with multiple contracts. However, a valid contract number must be provided in the `X-Contract-Number` header to access the Auth API. By default, generated access tokens will expire after one year (subject to change). - @param ctx _context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). - @return ApiTokensGenerateRequest */ @@ -622,6 +638,9 @@ func (a *TokensApiService) TokensGenerateExecute(r ApiTokensGenerateRequest) (Jw localVarQueryParams := _neturl.Values{} localVarFormParams := _neturl.Values{} + if r.ttl != nil { + localVarQueryParams.Add("ttl", parameterToString(*r.ttl, "")) + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -645,7 +664,7 @@ func (a *TokensApiService) TokensGenerateExecute(r ApiTokensGenerateRequest) (Jw if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["Token Authentication"]; ok { + if apiKey, ok := auth["TokenAuthentication"]; ok { var key string if apiKey.Prefix != "" { key = apiKey.Prefix + " " + apiKey.Key @@ -661,20 +680,21 @@ func (a *TokensApiService) TokensGenerateExecute(r ApiTokensGenerateRequest) (Jw return localVarReturnValue, nil, err } - localVarHTTPResponse, err := a.client.callAPI(req) + localVarHTTPResponse, httpRequestTime, err := a.client.callAPI(req) localVarAPIResponse := &APIResponse{ - Response: localVarHTTPResponse, - Method: localVarHTTPMethod, - RequestURL: localVarPath, - Operation: "TokensGenerate", + Response: localVarHTTPResponse, + Method: localVarHTTPMethod, + RequestTime: httpRequestTime, + RequestURL: localVarPath, + Operation: "TokensGenerate", } if err != nil || localVarHTTPResponse == nil { return localVarReturnValue, localVarAPIResponse, err } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() localVarAPIResponse.Payload = localVarBody if err != nil { @@ -685,13 +705,13 @@ func (a *TokensApiService) TokensGenerateExecute(r ApiTokensGenerateRequest) (Jw newErr := GenericOpenAPIError{ statusCode: localVarHTTPResponse.StatusCode, body: localVarBody, - error: fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, string(localVarBody)), + error: fmt.Sprintf("%s: %s", localVarHTTPResponse.Status, string(localVarBody)), } if localVarHTTPResponse.StatusCode == 401 { var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -700,7 +720,7 @@ func (a *TokensApiService) TokensGenerateExecute(r ApiTokensGenerateRequest) (Jw var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -709,7 +729,7 @@ func (a *TokensApiService) TokensGenerateExecute(r ApiTokensGenerateRequest) (Jw var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -806,7 +826,7 @@ func (a *TokensApiService) TokensGetExecute(r ApiTokensGetRequest) (Tokens, *API if r.ctx != nil { // API Key Authentication if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { - if apiKey, ok := auth["Token Authentication"]; ok { + if apiKey, ok := auth["TokenAuthentication"]; ok { var key string if apiKey.Prefix != "" { key = apiKey.Prefix + " " + apiKey.Key @@ -822,20 +842,21 @@ func (a *TokensApiService) TokensGetExecute(r ApiTokensGetRequest) (Tokens, *API return localVarReturnValue, nil, err } - localVarHTTPResponse, err := a.client.callAPI(req) + localVarHTTPResponse, httpRequestTime, err := a.client.callAPI(req) localVarAPIResponse := &APIResponse{ - Response: localVarHTTPResponse, - Method: localVarHTTPMethod, - RequestURL: localVarPath, - Operation: "TokensGet", + Response: localVarHTTPResponse, + Method: localVarHTTPMethod, + RequestTime: httpRequestTime, + RequestURL: localVarPath, + Operation: "TokensGet", } if err != nil || localVarHTTPResponse == nil { return localVarReturnValue, localVarAPIResponse, err } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() localVarAPIResponse.Payload = localVarBody if err != nil { @@ -846,13 +867,13 @@ func (a *TokensApiService) TokensGetExecute(r ApiTokensGetRequest) (Tokens, *API newErr := GenericOpenAPIError{ statusCode: localVarHTTPResponse.StatusCode, body: localVarBody, - error: fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, string(localVarBody)), + error: fmt.Sprintf("%s: %s", localVarHTTPResponse.Status, string(localVarBody)), } if localVarHTTPResponse.StatusCode == 401 { var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -861,7 +882,7 @@ func (a *TokensApiService) TokensGetExecute(r ApiTokensGetRequest) (Tokens, *API var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -870,7 +891,7 @@ func (a *TokensApiService) TokensGetExecute(r ApiTokensGetRequest) (Tokens, *API var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v @@ -879,7 +900,7 @@ func (a *TokensApiService) TokensGetExecute(r ApiTokensGetRequest) (Tokens, *API var v Error err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) if err != nil { - newErr.error = fmt.Sprintf(FormatStringErr, localVarHTTPResponse.Status, err.Error()) + newErr.error = err.Error() return localVarReturnValue, localVarAPIResponse, newErr } newErr.model = v diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/client.go b/vendor/github.com/ionos-cloud/sdk-go-auth/client.go index 710d7439e..ef5e99d1f 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/client.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/client.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -13,12 +13,17 @@ package ionoscloud import ( "bytes" "context" + "crypto/sha256" + "crypto/tls" + "crypto/x509" + "encoding/hex" "encoding/json" "encoding/xml" "errors" "fmt" "io" "mime/multipart" + "net" "net/http" "net/http/httputil" "net/url" @@ -35,7 +40,7 @@ import ( ) var ( - jsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:vnd\.[^;]+\+)?json)`) + jsonCheck = regexp.MustCompile(`(?i:(?:application|text)\/(?:vnd\.[^;]+|problem\+)?json)`) xmlCheck = regexp.MustCompile(`(?i:(?:application|text)/xml)`) ) @@ -45,12 +50,9 @@ const ( RequestStatusFailed = "FAILED" RequestStatusDone = "DONE" - Version = "1.0.6" + Version = "1.0.10" ) -// Constants for APIs -const FormatStringErr = "%s %s" - // APIClient manages communication with the Auth API API v1.0 // In most cases there should be only one, shared, APIClient. type APIClient struct { @@ -72,6 +74,13 @@ func NewAPIClient(cfg *Configuration) *APIClient { if cfg.HTTPClient == nil { cfg.HTTPClient = http.DefaultClient } + //enable certificate pinning if the env variable is set + pkFingerprint := os.Getenv(IonosPinnedCertEnvVar) + if pkFingerprint != "" { + httpTransport := &http.Transport{} + AddPinnedCert(httpTransport, pkFingerprint) + cfg.HTTPClient.Transport = httpTransport + } c := &APIClient{} c.cfg = cfg @@ -83,6 +92,63 @@ func NewAPIClient(cfg *Configuration) *APIClient { return c } +// AddPinnedCert - enables pinning of the sha256 public fingerprint to the http client's transport +func AddPinnedCert(transport *http.Transport, pkFingerprint string) { + if pkFingerprint != "" { + transport.DialTLSContext = addPinnedCertVerification([]byte(pkFingerprint), new(tls.Config)) + } +} + +// TLSDial can be assigned to a http.Transport's DialTLS field. +type TLSDial func(ctx context.Context, network, addr string) (net.Conn, error) + +// addPinnedCertVerification returns a TLSDial function which checks that +// the remote server provides a certificate whose SHA256 fingerprint matches +// the provided value. +// +// The returned dialer function can be plugged into a http.Transport's DialTLS +// field to allow for certificate pinning. +func addPinnedCertVerification(fingerprint []byte, tlsConfig *tls.Config) TLSDial { + return func(ctx context.Context, network, addr string) (net.Conn, error) { + //fingerprints can be added with ':', we need to trim + fingerprint = bytes.ReplaceAll(fingerprint, []byte(":"), []byte("")) + fingerprint = bytes.ReplaceAll(fingerprint, []byte(" "), []byte("")) + //we are manually checking a certificate, so we need to enable insecure + tlsConfig.InsecureSkipVerify = true + + // Dial the connection to get certificates to check + conn, err := tls.Dial(network, addr, tlsConfig) + if err != nil { + return nil, err + } + + if err := verifyPinnedCert(fingerprint, conn.ConnectionState().PeerCertificates); err != nil { + _ = conn.Close() + return nil, err + } + + return conn, nil + } +} + +// verifyPinnedCert iterates the list of peer certificates and attempts to +// locate a certificate that is not a CA and whose public key fingerprint matches pkFingerprint. +func verifyPinnedCert(pkFingerprint []byte, peerCerts []*x509.Certificate) error { + for _, cert := range peerCerts { + fingerprint := sha256.Sum256(cert.Raw) + + var bytesFingerPrint = make([]byte, hex.EncodedLen(len(fingerprint[:]))) + hex.Encode(bytesFingerPrint, fingerprint[:]) + + // we have a match, and it's not an authority certificate + if cert.IsCA == false && bytes.EqualFold(bytesFingerPrint, pkFingerprint) { + return nil + } + } + + return fmt.Errorf("remote server presented a certificate which does not match the provided fingerprint") +} + func atoi(in string) (int, error) { return strconv.Atoi(in) } @@ -169,10 +235,11 @@ func parameterToJson(obj interface{}) (string, error) { } // callAPI do the request. -func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { +func (c *APIClient) callAPI(request *http.Request) (*http.Response, time.Duration, error) { retryCount := 0 var resp *http.Response + var httpRequestTime time.Duration var err error for { @@ -184,7 +251,7 @@ func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { if request.Body != nil { clonedRequest.Body, err = request.GetBody() if err != nil { - return nil, err + return nil, httpRequestTime, err } } @@ -198,10 +265,12 @@ func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { c.cfg.Logger.Printf("\n try no: %d\n", retryCount) } + httpRequestStartTime := time.Now() clonedRequest.Close = true resp, err = c.cfg.HTTPClient.Do(clonedRequest) + httpRequestTime = time.Since(httpRequestStartTime) if err != nil { - return resp, err + return resp, httpRequestTime, err } if c.cfg.Debug || c.cfg.LogLevel.Satisfies(Trace) { @@ -219,20 +288,23 @@ func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { case http.StatusServiceUnavailable, http.StatusGatewayTimeout, http.StatusBadGateway: + if request.Method == http.MethodPost { + return resp, httpRequestTime, err + } backoffTime = c.GetConfig().WaitTime case http.StatusTooManyRequests: if retryAfterSeconds := resp.Header.Get("Retry-After"); retryAfterSeconds != "" { waitTime, err := time.ParseDuration(retryAfterSeconds + "s") if err != nil { - return resp, err + return resp, httpRequestTime, err } backoffTime = waitTime } else { backoffTime = c.GetConfig().WaitTime } default: - return resp, err + return resp, httpRequestTime, err } @@ -242,21 +314,31 @@ func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { } break } else { - c.backOff(backoffTime) + c.backOff(request.Context(), backoffTime) } } - return resp, err + return resp, httpRequestTime, err } -func (c *APIClient) backOff(t time.Duration) { +func (c *APIClient) backOff(ctx context.Context, t time.Duration) { if t > c.GetConfig().MaxWaitTime { t = c.GetConfig().MaxWaitTime } if c.cfg.Debug || c.cfg.LogLevel.Satisfies(Debug) { c.cfg.Logger.Printf(" Sleeping %s before retrying request\n", t.String()) } - time.Sleep(t) + if t <= 0 { + return + } + + timer := time.NewTimer(t) + defer timer.Stop() + + select { + case <-ctx.Done(): + case <-timer.C: + } } // Allow modification of underlying config for alternate implementations and testing @@ -463,14 +545,14 @@ func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err err return err } } else { - return errors.New("Unknown type with GetActualInstance but no unmarshalObj.UnmarshalJSON defined") + return errors.New("unknown type with GetActualInstance but no unmarshalObj.UnmarshalJSON defined") } } else if err = json.Unmarshal(b, v); err != nil { // simple model return err } return nil } - return errors.New("undefined response type") + return fmt.Errorf("undefined response type for content %s", contentType) } // Add a file to the multipart request diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/configuration.go b/vendor/github.com/ionos-cloud/sdk-go-auth/configuration.go index fd33dc7c2..c64d43fac 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/configuration.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/configuration.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -25,6 +25,7 @@ const ( IonosPasswordEnvVar = "IONOS_PASSWORD" IonosTokenEnvVar = "IONOS_TOKEN" IonosApiUrlEnvVar = "IONOS_API_URL" + IonosPinnedCertEnvVar = "IONOS_PINNED_CERT" IonosLogLevelEnvVar = "IONOS_LOG_LEVEL" DefaultIonosServerUrl = "https://api.ionos.com/auth/v1" DefaultIonosBasePath = "/auth/v1" @@ -33,6 +34,12 @@ const ( defaultMaxWaitTime = time.Duration(2000) * time.Millisecond ) +var ( + IonosServerUrls = []string{ + "https://api.ionos.com/auth/v1", + } +) + // contextKeys are used to identify the type of value in the context. // Since these are string, it is possible to get a short description of the // context key for logging and debugging using key.String(). @@ -112,14 +119,14 @@ type Configuration struct { Servers ServerConfigurations OperationServers map[string]ServerConfigurations HTTPClient *http.Client + LogLevel LogLevel + Logger Logger Username string `json:"username,omitempty"` Password string `json:"password,omitempty"` Token string `json:"token,omitempty"` MaxRetries int `json:"maxRetries,omitempty"` WaitTime time.Duration `json:"waitTime,omitempty"` MaxWaitTime time.Duration `json:"maxWaitTime,omitempty"` - LogLevel LogLevel - Logger Logger } // NewConfiguration returns a new Configuration object @@ -127,7 +134,7 @@ func NewConfiguration(username, password, token, hostUrl string) *Configuration cfg := &Configuration{ DefaultHeader: make(map[string]string), DefaultQueryParams: url.Values{}, - UserAgent: "ionos-cloud-sdk-go-auth/v1.0.6", + UserAgent: "ionos-cloud-sdk-go-auth/v1.0.10", Debug: false, Username: username, Password: password, @@ -250,6 +257,7 @@ func getServerUrl(serverUrl string) string { if serverUrl == "" { return DefaultIonosServerUrl } + // Support both HTTPS & HTTP schemas if !strings.HasPrefix(serverUrl, "https://") && !strings.HasPrefix(serverUrl, "http://") { serverUrl = fmt.Sprintf("https://%s", serverUrl) } diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/logger.go b/vendor/github.com/ionos-cloud/sdk-go-auth/logger.go index b125f0147..e404835af 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/logger.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/logger.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -46,7 +46,7 @@ var LogLevelMap = map[string]LogLevel{ "trace": Trace, } -// getLogLevelFromEnv - gets LogLevel type from env variable IonosLogLevelEnvVar +// getLogLevelFromEnv - gets LogLevel type from env variable IONOS_LOG_LEVEL // returns Off if an invalid log level is encountered func getLogLevelFromEnv() LogLevel { strLogLevel := "off" diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/model_delete_response.go b/vendor/github.com/ionos-cloud/sdk-go-auth/model_delete_response.go index c96d0ea4d..d7213abbe 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/model_delete_response.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/model_delete_response.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -19,6 +19,24 @@ type DeleteResponse struct { Success *bool `json:"success,omitempty"` } +// NewDeleteResponse instantiates a new DeleteResponse object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewDeleteResponse() *DeleteResponse { + this := DeleteResponse{} + + return &this +} + +// NewDeleteResponseWithDefaults instantiates a new DeleteResponse object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewDeleteResponseWithDefaults() *DeleteResponse { + this := DeleteResponse{} + return &this +} + // GetSuccess returns the Success field value // If the value is explicit nil, the zero value for bool will be returned func (o *DeleteResponse) GetSuccess() *bool { @@ -62,6 +80,7 @@ func (o DeleteResponse) MarshalJSON() ([]byte, error) { if o.Success != nil { toSerialize["success"] = o.Success } + return json.Marshal(toSerialize) } diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/model_error.go b/vendor/github.com/ionos-cloud/sdk-go-auth/model_error.go index 0e5a18175..715b67aaf 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/model_error.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/model_error.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -21,6 +21,24 @@ type Error struct { Messages *[]ErrorMessages `json:"messages,omitempty"` } +// NewError instantiates a new Error object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewError() *Error { + this := Error{} + + return &this +} + +// NewErrorWithDefaults instantiates a new Error object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewErrorWithDefaults() *Error { + this := Error{} + return &this +} + // GetHttpStatus returns the HttpStatus field value // If the value is explicit nil, the zero value for int32 will be returned func (o *Error) GetHttpStatus() *int32 { @@ -102,9 +120,11 @@ func (o Error) MarshalJSON() ([]byte, error) { if o.HttpStatus != nil { toSerialize["httpStatus"] = o.HttpStatus } + if o.Messages != nil { toSerialize["messages"] = o.Messages } + return json.Marshal(toSerialize) } diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/model_error_messages.go b/vendor/github.com/ionos-cloud/sdk-go-auth/model_error_messages.go index 020b279e1..8d77ee1c2 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/model_error_messages.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/model_error_messages.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -22,6 +22,24 @@ type ErrorMessages struct { Message *string `json:"message,omitempty"` } +// NewErrorMessages instantiates a new ErrorMessages object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewErrorMessages() *ErrorMessages { + this := ErrorMessages{} + + return &this +} + +// NewErrorMessagesWithDefaults instantiates a new ErrorMessages object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewErrorMessagesWithDefaults() *ErrorMessages { + this := ErrorMessages{} + return &this +} + // GetErrorCode returns the ErrorCode field value // If the value is explicit nil, the zero value for string will be returned func (o *ErrorMessages) GetErrorCode() *string { @@ -103,9 +121,11 @@ func (o ErrorMessages) MarshalJSON() ([]byte, error) { if o.ErrorCode != nil { toSerialize["errorCode"] = o.ErrorCode } + if o.Message != nil { toSerialize["message"] = o.Message } + return json.Marshal(toSerialize) } diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/model_jwt.go b/vendor/github.com/ionos-cloud/sdk-go-auth/model_jwt.go index f22f02144..b6651d250 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/model_jwt.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/model_jwt.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -20,6 +20,24 @@ type Jwt struct { Token *string `json:"token,omitempty"` } +// NewJwt instantiates a new Jwt object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewJwt() *Jwt { + this := Jwt{} + + return &this +} + +// NewJwtWithDefaults instantiates a new Jwt object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewJwtWithDefaults() *Jwt { + this := Jwt{} + return &this +} + // GetToken returns the Token field value // If the value is explicit nil, the zero value for string will be returned func (o *Jwt) GetToken() *string { @@ -63,6 +81,7 @@ func (o Jwt) MarshalJSON() ([]byte, error) { if o.Token != nil { toSerialize["token"] = o.Token } + return json.Marshal(toSerialize) } diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/model_token.go b/vendor/github.com/ionos-cloud/sdk-go-auth/model_token.go index 76d6fd10a..e9756fcd3 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/model_token.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/model_token.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -26,6 +26,29 @@ type Token struct { ExpirationDate *string `json:"expirationDate"` } +// NewToken instantiates a new Token object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewToken(id string, href string, createdDate string, expirationDate string) *Token { + this := Token{} + + this.Id = &id + this.Href = &href + this.CreatedDate = &createdDate + this.ExpirationDate = &expirationDate + + return &this +} + +// NewTokenWithDefaults instantiates a new Token object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewTokenWithDefaults() *Token { + this := Token{} + return &this +} + // GetId returns the Id field value // If the value is explicit nil, the zero value for string will be returned func (o *Token) GetId() *string { @@ -183,15 +206,19 @@ func (o Token) MarshalJSON() ([]byte, error) { if o.Id != nil { toSerialize["id"] = o.Id } + if o.Href != nil { toSerialize["href"] = o.Href } + if o.CreatedDate != nil { toSerialize["createdDate"] = o.CreatedDate } + if o.ExpirationDate != nil { toSerialize["expirationDate"] = o.ExpirationDate } + return json.Marshal(toSerialize) } diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/model_tokens.go b/vendor/github.com/ionos-cloud/sdk-go-auth/model_tokens.go index 93d7aa52f..ef7ff14de 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/model_tokens.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/model_tokens.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -20,6 +20,24 @@ type Tokens struct { Tokens *[]Token `json:"tokens,omitempty"` } +// NewTokens instantiates a new Tokens object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewTokens() *Tokens { + this := Tokens{} + + return &this +} + +// NewTokensWithDefaults instantiates a new Tokens object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewTokensWithDefaults() *Tokens { + this := Tokens{} + return &this +} + // GetTokens returns the Tokens field value // If the value is explicit nil, the zero value for []Token will be returned func (o *Tokens) GetTokens() *[]Token { @@ -63,6 +81,7 @@ func (o Tokens) MarshalJSON() ([]byte, error) { if o.Tokens != nil { toSerialize["tokens"] = o.Tokens } + return json.Marshal(toSerialize) } diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/response.go b/vendor/github.com/ionos-cloud/sdk-go-auth/response.go index b2385e1a4..08621afe8 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/response.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/response.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -11,7 +11,9 @@ package ionoscloud import ( + "log" "net/http" + "time" ) // APIResponse stores the API response returned by the server. @@ -23,6 +25,9 @@ type APIResponse struct { // RequestURL is the request URL. This value is always available, even if the // embedded *http.Response is nil. RequestURL string `json:"url,omitempty"` + // RequestTime is the time duration from the moment the APIClient sends + // the HTTP request to the moment it receives an HTTP response. + RequestTime time.Duration `json:"duration,omitempty"` // Method is the HTTP method used for the request. This value is always // available, even if the embedded *http.Response is nil. Method string `json:"method,omitempty"` @@ -32,7 +37,7 @@ type APIResponse struct { Payload []byte `json:"-"` } -// NewAPIResponse returns a new APIResonse object. +// NewAPIResponse returns a new APIResponse object. func NewAPIResponse(r *http.Response) *APIResponse { response := &APIResponse{Response: r} @@ -45,3 +50,24 @@ func NewAPIResponseWithError(errorMessage string) *APIResponse { response := &APIResponse{Message: errorMessage} return response } + +// HttpNotFound - returns true if a 404 status code was returned +// returns false for nil APIResponse values +func (resp *APIResponse) HttpNotFound() bool { + if resp != nil && resp.Response != nil && resp.StatusCode == http.StatusNotFound { + return true + } + return false +} + +// LogInfo - logs APIResponse values like RequestTime, Operation and StatusCode +// does not print anything for nil APIResponse values +func (resp *APIResponse) LogInfo() { + if resp != nil { + log.Printf("[DEBUG] Request time : %s for operation : %s", + resp.RequestTime, resp.Operation) + if resp.Response != nil { + log.Printf("[DEBUG] response status code : %d\n", resp.StatusCode) + } + } +} diff --git a/vendor/github.com/ionos-cloud/sdk-go-auth/utils.go b/vendor/github.com/ionos-cloud/sdk-go-auth/utils.go index f1b55a3cf..01a7e22ea 100644 --- a/vendor/github.com/ionos-cloud/sdk-go-auth/utils.go +++ b/vendor/github.com/ionos-cloud/sdk-go-auth/utils.go @@ -1,7 +1,7 @@ /* * Auth API * - * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). + * Use the Auth API to manage tokens for secure access to IONOS Cloud APIs (Auth API, Cloud API, Reseller API, Activity Log API, and others). * * API version: 1.0 */ @@ -13,7 +13,6 @@ package ionoscloud import ( "encoding/json" "reflect" - "strings" "time" ) @@ -754,11 +753,6 @@ func (t *IonosTime) UnmarshalJSON(data []byte) error { if str[len(str)-1] == '"' { str = str[:len(str)-1] } - if !strings.Contains(str, "Z") { - /* forcefully adding timezone suffix to be able to parse the - * string using RFC3339 */ - str += "Z" - } tt, err := time.Parse(time.RFC3339, str) if err != nil { return err diff --git a/vendor/modules.txt b/vendor/modules.txt index e28126acc..e5216e356 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -60,8 +60,8 @@ github.com/hashicorp/hcl/json/token # github.com/inconshreveable/mousetrap v1.1.0 ## explicit; go 1.18 github.com/inconshreveable/mousetrap -# github.com/ionos-cloud/sdk-go-auth v1.0.6 -## explicit; go 1.19 +# github.com/ionos-cloud/sdk-go-auth v1.0.10 +## explicit; go 1.18 github.com/ionos-cloud/sdk-go-auth # github.com/ionos-cloud/sdk-go-cdn v1.1.0 ## explicit; go 1.18 From 2ff4c8c8d1a79eeea20d4325d6c2bb0fb4cec5ed Mon Sep 17 00:00:00 2001 From: Gabriela Limberea Date: Mon, 23 Dec 2024 16:24:20 +0200 Subject: [PATCH 2/3] add ttl to token tests, s3key test not passing --- test/bats/cloudapi/user.bats | 37 ++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/test/bats/cloudapi/user.bats b/test/bats/cloudapi/user.bats index 53a254b43..8af986224 100644 --- a/test/bats/cloudapi/user.bats +++ b/test/bats/cloudapi/user.bats @@ -49,12 +49,12 @@ setup_file() { user_id=$(cat /tmp/bats_test/user_id) group_name="group-$(randStr 8)" - run ionosctl group create --s3privilege --name "$group_name" --cols GroupId --no-headers + run ionosctl group create --s3privilege=true --name "$group_name" --cols GroupId --no-headers assert_success group_id=$output echo "$group_id" > /tmp/bats_test/group_id - run ionosctl group user add --group-id "$(cat /tmp/bats_test/group_id)" \ + run ionosctl group user add --group-id "$group_id" \ --user-id "$user_id" --cols UserId --no-headers 2> /dev/null assert_success assert_output "$user_id" @@ -65,38 +65,39 @@ setup_file() { } @test "Create and verify S3Key" { - run ionosctl user s3key create --user-id "$(cat /tmp/bats_test/user_id)" -o json 2> /dev/null + user_id=$(cat /tmp/bats_test/user_id) + run ionosctl user s3key create --user-id "$user_id" -o json 2> /dev/null assert_success access_key=$(echo "$output" | jq -r '.id') secret_key=$(echo "$output" | jq -r '.properties.secretKey') # TODO: Make a request to the S3 server to test the credentials - run ionosctl user s3key list --user-id "$(cat /tmp/bats_test/user_id)" --cols S3KeyId --no-headers + run ionosctl user s3key list --user-id "$user_id" --cols S3KeyId --no-headers assert_output -p "$access_key" assert_success - run ionosctl user s3key get --user-id "$(cat /tmp/bats_test/user_id)" --s3key-id "$access_key" -o json 2> /dev/null + run ionosctl user s3key get --user-id "$user_id" --s3key-id "$access_key" -o json 2> /dev/null assert_success assert_equal "$access_key" "$(echo "$output" | jq -r '.id')" assert_equal "$secret_key" "$(echo "$output" | jq -r '.properties.secretKey')" - run ionosctl user s3key delete --user-id "$(cat /tmp/bats_test/user_id)" --s3key-id "$access_key" -f + run ionosctl user s3key delete --user-id "$user_id" --s3key-id "$access_key" -f assert_success } @test "Test 'ionosctl token' commands" { - unset IONOS_USERNAME IONOS_PASSWORD + unset IONOS_USERNAME IONOS_PASSWORD IONOS_TOKEN email="$(cat /tmp/bats_test/email)" password="$(cat /tmp/bats_test/password)" user_id=$(cat /tmp/bats_test/user_id) - run ionosctl login --user "$(cat /tmp/bats_test/email)" --password "$(cat /tmp/bats_test/password)" --force + run ionosctl login --user "$email" --password "$password" --force assert_success # Generate a token and ensure it belongs to this user - run ionosctl token generate + run ionosctl token generate --ttl 1h assert_success jwt="$output" @@ -120,7 +121,7 @@ setup_file() { } @test "Test 'ionosctl cfg' commands" { - unset IONOS_USERNAME IONOS_PASSWORD + unset IONOS_USERNAME IONOS_PASSWORD IONOS_TOKEN email="$(cat /tmp/bats_test/email)" password="$(cat /tmp/bats_test/password)" @@ -186,7 +187,12 @@ setup_file() { } @test "Config file should only work for permissions 600" { - run ionosctl login --user "$(cat /tmp/bats_test/email)" --password "$(cat /tmp/bats_test/password)" --force + unset IONOS_USERNAME IONOS_PASSWORD IONOS_TOKEN + + email="$(cat /tmp/bats_test/email)" + password="$(cat /tmp/bats_test/password)" + + run ionosctl login --user "$email" --password "$password" --force assert_success run ionosctl config location @@ -217,9 +223,12 @@ setup_file() { } teardown_file() { - echo "cleaning up user $(cat /tmp/bats_test/user_id) and group $(cat /tmp/bats_test/group_id)" - run ionosctl user delete --user-id "$(cat /tmp/bats_test/user_id)" -f - run ionosctl group delete --group-id "$(cat /tmp/bats_test/group_id)" -f + user_id=$(cat /tmp/bats_test/user_id) + group_id=$(cat /tmp/bats_test/group_id) + + echo "cleaning up user $user_id and group $group_id" + run ionosctl user delete --user-id "$user_id" -f + run ionosctl group delete --group-id "$group_id" -f run ionosctl token delete -af rm -rf /tmp/bats_test From 346785f6ab2bdaf2b2d7d996aab7961f867c48ea Mon Sep 17 00:00:00 2001 From: Gabriela Limberea Date: Mon, 23 Dec 2024 16:26:47 +0200 Subject: [PATCH 3/3] make docs --- docs/subcommands/Authentication/token/generate.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/subcommands/Authentication/token/generate.md b/docs/subcommands/Authentication/token/generate.md index 8faf01135..fcc5c5d35 100644 --- a/docs/subcommands/Authentication/token/generate.md +++ b/docs/subcommands/Authentication/token/generate.md @@ -35,6 +35,7 @@ Use this command to generate a new Token. Only the JSON Web Token, associated wi --no-headers Don't print table headers when table output is used -o, --output string Desired output format [text|json|api-json] (default "text") -q, --quiet Quiet output + --ttl string Token Time to Live in seconds. Can be one of: 1h, 4h, 1D, 7D, 1M, 2M, 3M, 6M, 1Y (default "1Y") -v, --verbose Print step-by-step process when running command ```