Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/go_modules/github.com/hashicorp/t…
Browse files Browse the repository at this point in the history
…erraform-plugin-sdk/v2-2.33.0
  • Loading branch information
eamonnotoole authored May 20, 2024
2 parents 6c1a451 + f5d0721 commit e09c849
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 39 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ require (
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1085,8 +1085,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down
8 changes: 4 additions & 4 deletions pkg/mocks/IdentityAPI_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 75 additions & 8 deletions pkg/provider/provider.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
// (C) Copyright 2021 Hewlett Packard Enterprise Development LP
// (C) Copyright 2021-2024 Hewlett Packard Enterprise Development LP

package provider

import (
"fmt"
"net/url"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"

"github.com/hewlettpackard/hpegl-provider-lib/pkg/registration"
)

// IAMVersion is a type definition for the IAM version
type IAMVersion string

const (
// IAMVersionGLCS is the IAM version for GLCS
IAMVersionGLCS IAMVersion = "glcs"
// IAMVersionGLP is the IAM version for GLP
IAMVersionGLP IAMVersion = "glp"
)

// Update this list with any new IAM versions
var iamVersionList = [...]IAMVersion{IAMVersionGLCS, IAMVersionGLP}

// ConfigureFunc is a type definition of a function that returns a ConfigureContextFunc object
// A function of this type is passed in to NewProviderFunc below
type ConfigureFunc func(p *schema.Provider) schema.ConfigureContextFunc
Expand Down Expand Up @@ -78,12 +92,22 @@ func Schema() map[string]*schema.Schema {
}

providerSchema["iam_service_url"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("HPEGL_IAM_SERVICE_URL", "https://client.greenlake.hpe.com/api/iam"),
Description: `The IAM service URL to be used to generate tokens. In the case of API-vended API clients
(the default) then this should be set to the "issuer url" for the client. In the case of non-API-vended
API clients use the appropriate GL "client" URL. Can be set by HPEGL_IAM_SERVICE_URL env-var`,
Type: schema.TypeString,
Optional: true,
ValidateFunc: ValidateServiceURL,
DefaultFunc: schema.EnvDefaultFunc("HPEGL_IAM_SERVICE_URL", "https://client.greenlake.hpe.com/api/iam"),
Description: `The IAM service URL to be used to generate tokens. In the case of GLCS API clients
(the default) then this should be set to the "issuer url" for the client. In the case of GLP
API clients use the appropriate "Token URL" from the API screen. Can be set by HPEGL_IAM_SERVICE_URL env-var`,
}

providerSchema["iam_version"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("HPEGL_IAM_VERSION", string(IAMVersionGLCS)),
ValidateFunc: ValidateIAMVersion,
Description: `The IAM version to be used. Can be set by HPEGL_IAM_VERSION env-var. Valid values are:
` + fmt.Sprintf("%v", iamVersionList) + `The default is ` + string(IAMVersionGLCS) + `.`,
}

providerSchema["api_vended_service_client"] = &schema.Schema{
Expand All @@ -98,7 +122,7 @@ func Schema() map[string]*schema.Schema {
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.EnvDefaultFunc("HPEGL_TENANT_ID", ""),
Description: "The tenant-id to be used, can be set by HPEGL_TENANT_ID env-var",
Description: "The tenant-id to be used for GLCS IAM, can be set by HPEGL_TENANT_ID env-var",
}

providerSchema["user_id"] = &schema.Schema{
Expand Down Expand Up @@ -137,3 +161,46 @@ func convertToTypeSet(r *schema.Resource) *schema.Schema {
Elem: r,
}
}

// ValidateIAMVersion is a ValidateFunc for the "iam_version" field in the provider schema
func ValidateIAMVersion(v interface{}, k string) ([]string, []error) {
// This isn't strictly necessary, but it's a good idea to check that the input is a string
versionInput, ok := v.(string)
if !ok {
return []string{}, []error{fmt.Errorf("IAM version must be a string")}
}

// check that versionInput is in iamVersionList
found := false
for _, version := range iamVersionList {
if string(version) == versionInput {
found = true
break
}
}

// add error if not found
es := make([]error, 0)
if !found {
es = append(es, fmt.Errorf("IAM version must be one of %v", iamVersionList))
}

return []string{}, es
}

// ValidateServiceURL is a ValidateFunc for the "iam_service_url" field in the provider schema
func ValidateServiceURL(v interface{}, k string) ([]string, []error) {
// check that v is a string, this should not be necessary but it's a good idea
serviceURL, ok := v.(string)
if !ok {
return []string{}, []error{fmt.Errorf("Service URL must be a string")}
}

// check that serviceURL is a valid URL
_, err := url.ParseRequestURI(serviceURL)
if err != nil {
return []string{}, []error{fmt.Errorf("Service URL must be a valid URL")}
}

return []string{}, []error{}
}
76 changes: 74 additions & 2 deletions pkg/provider/provider_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Copyright 2021 Hewlett Packard Enterprise Development LP
// (C) Copyright 2021-2024 Hewlett Packard Enterprise Development LP

package provider

Expand All @@ -8,8 +8,9 @@ import (

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hewlettpackard/hpegl-provider-lib/pkg/registration"
"github.com/stretchr/testify/assert"

"github.com/hewlettpackard/hpegl-provider-lib/pkg/registration"
)

func testResource() *schema.Resource {
Expand Down Expand Up @@ -170,3 +171,74 @@ func TestNewProviderFunc(t *testing.T) {
})
}
}

func TestValidateIAMVersion(t *testing.T) {
t.Parallel()
testcases := []struct {
name string
version string
hasError bool
}{
{
name: "valid IAM version GLCS",
version: string(IAMVersionGLCS),
hasError: false,
},
{
name: "valid IAM version GLP",
version: string(IAMVersionGLP),
hasError: false,
},
{
name: "invalid IAM version",
version: "invalid",
hasError: true,
},
}

for _, testcase := range testcases {
tc := testcase
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
_, es := ValidateIAMVersion(tc.version, "iam_version")
if tc.hasError {
assert.NotEmpty(t, es)
} else {
assert.Empty(t, es)
}
})
}
}

func TestValidateServiceURL(t *testing.T) {
t.Parallel()
testcases := []struct {
name string
url string
hasError bool
}{
{
name: "valid URL",
url: "https://client.greenlake.hpe.com/api/iam",
hasError: false,
},
{
name: "invalid URL",
url: "invalid",
hasError: true,
},
}

for _, testcase := range testcases {
tc := testcase
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
_, es := ValidateServiceURL(tc.url, "iam_service_url")
if tc.hasError {
assert.NotEmpty(t, es)
} else {
assert.Empty(t, es)
}
})
}
}
7 changes: 4 additions & 3 deletions pkg/token/httpclient/httpclient.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Copyright 2021 Hewlett Packard Enterprise Development LP
// (C) Copyright 2021-2024 Hewlett Packard Enterprise Development LP

package httpclient

Expand Down Expand Up @@ -33,11 +33,12 @@ func New(identityServiceURL string, vendedServiceClient bool, passedInToken stri
}
}

func (c *Client) GenerateToken(ctx context.Context, tenantID, clientID, clientSecret string) (string, error) {
func (c *Client) GenerateToken(ctx context.Context, tenantID, clientID, clientSecret, iamVersion string) (string, error) {
// we don't have a passed-in token, so we need to actually generate a token
if c.passedInToken == "" {
if c.vendedServiceClient {
token, err := issuertoken.GenerateToken(ctx, tenantID, clientID, clientSecret, c.identityServiceURL, c.httpClient)
token, err := issuertoken.GenerateToken(
ctx, clientID, clientSecret, c.identityServiceURL, c.httpClient, iamVersion)

return token, err
}
Expand Down
12 changes: 7 additions & 5 deletions pkg/token/httpclient/httpclient_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Copyright 2021 Hewlett Packard Enterprise Development LP
// (C) Copyright 2021-2024 Hewlett Packard Enterprise Development LP

//nolint:structcheck
package httpclient
Expand All @@ -11,9 +11,11 @@ import (
"net/http"
"testing"

"github.com/stretchr/testify/assert"

"github.com/hewlettpackard/hpegl-provider-lib/pkg/provider"
"github.com/hewlettpackard/hpegl-provider-lib/pkg/token/identitytoken"
"github.com/hewlettpackard/hpegl-provider-lib/pkg/token/issuertoken"
"github.com/stretchr/testify/assert"
)

type testCaseIssuer struct {
Expand Down Expand Up @@ -205,7 +207,7 @@ func TestGenerateToken(t *testing.T) {

c = createTestClient(tc.url, "", tc.statusCode, tc.token, true)

token, err := c.GenerateToken(tc.ctx, "", "", "")
token, err := c.GenerateToken(tc.ctx, "", "", "", string(provider.IAMVersionGLCS))
if tc.err != nil {
assert.EqualError(t, err, tc.err.Error())
}
Expand All @@ -219,7 +221,7 @@ func TestGenerateToken(t *testing.T) {

c = createTestClient(tc.url, "", tc.statusCode, tc.token, false)

token, err := c.GenerateToken(tc.ctx, "", "", "")
token, err := c.GenerateToken(tc.ctx, "", "", "", string(provider.IAMVersionGLCS))
if tc.err != nil {
assert.EqualError(t, err, tc.err.Error())
}
Expand All @@ -232,7 +234,7 @@ func TestGenerateTokenPassedInToken(t *testing.T) {
t.Parallel()
c := createTestClient("", "testToken", http.StatusAccepted, nil, true)

token, err := c.GenerateToken(context.Background(), "", "", "")
token, err := c.GenerateToken(context.Background(), "", "", "", "")
assert.Equal(t, "testToken", token)
assert.NoError(t, err)
}
46 changes: 37 additions & 9 deletions pkg/token/issuertoken/issuertoken.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// (C) Copyright 2021-2023 Hewlett Packard Enterprise Development LP
// (C) Copyright 2021-2024 Hewlett Packard Enterprise Development LP

package issuertoken

Expand All @@ -11,6 +11,7 @@ import (
"net/url"
"strings"

"github.com/hewlettpackard/hpegl-provider-lib/pkg/provider"
tokenutil "github.com/hewlettpackard/hpegl-provider-lib/pkg/token/token-util"
)

Expand All @@ -27,25 +28,26 @@ type TokenResponse struct {

func GenerateToken(
ctx context.Context,
tenantID,
clientID,
clientSecret string,
identityServiceURL string,
httpClient tokenutil.HttpClient,
iamVersion string,
) (string, error) {
params := url.Values{}
params.Add("client_id", clientID)
params.Add("client_secret", clientSecret)
params.Add("grant_type", "client_credentials")
params.Add("scope", "hpe-tenant")
// Generate the parameters and URL for the request
params, clientURL, err := generateParamsAndURL(clientID, clientSecret, identityServiceURL, iamVersion)
if err != nil {
return "", err
}

url := fmt.Sprintf("%s/v1/token", identityServiceURL)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, strings.NewReader(params.Encode()))
// Create the request
req, err := http.NewRequestWithContext(ctx, http.MethodPost, clientURL, strings.NewReader(params.Encode()))
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

// Execute the request, with retries
resp, err := tokenutil.DoRetries(func() (*http.Response, error) {
return httpClient.Do(req)
}, retryLimit)
Expand Down Expand Up @@ -73,3 +75,29 @@ func GenerateToken(

return token.AccessToken, nil
}

// generateParamsAndURL generates the parameters and URL for the request
func generateParamsAndURL(clientID, clientSecret, identityServiceURL, iamVersion string) (url.Values, string, error) {
params := url.Values{}

// Add common parameters for an API Client
params.Add("client_id", clientID)
params.Add("client_secret", clientSecret)
params.Add("grant_type", "client_credentials")

// Add specific parameters and generate URL for the IAM version
var clientURL string
switch provider.IAMVersion(iamVersion) {
case provider.IAMVersionGLCS:
params.Add("scope", "hpe-tenant")
clientURL = fmt.Sprintf("%s/v1/token", identityServiceURL)

case provider.IAMVersionGLP:
clientURL = identityServiceURL

default:
return nil, "", fmt.Errorf("invalid IAM version")
}

return params, clientURL, nil
}
Loading

0 comments on commit e09c849

Please sign in to comment.