Skip to content

Commit

Permalink
feat(MCSPAuthenticator): add new authenticator for Multi-Cloud Saas P…
Browse files Browse the repository at this point in the history
…latform (#198)

This commit introduces the new MCSPAuthenticator that can be used
to exchange an apikey for an MCSP access token using the Multi-Cloud Saas Platform
authentication token server's 'POST /siusermgr/api/1.0/apikeys/token' operation.

Signed-off-by: Phil Adams <phil_adams@us.ibm.com>
  • Loading branch information
padamstx authored Nov 15, 2023
1 parent 1aa3ec0 commit 8987085
Show file tree
Hide file tree
Showing 10 changed files with 1,355 additions and 22 deletions.
92 changes: 76 additions & 16 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": "go.sum|package-lock.json|^.secrets.baseline$",
"lines": null
},
"generated_at": "2023-09-22T20:47:15Z",
"generated_at": "2023-11-06T17:25:56Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -247,26 +247,26 @@
"verified_result": null
},
{
"hashed_secret": "f2e7745f43b0ef0e2c2faf61d6c6a28be2965750",
"hashed_secret": "2a68d46242baf9214502d1dc240a9075a7c6ed55",
"is_secret": false,
"is_verified": false,
"line_number": 71,
"line_number": 79,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "2a68d46242baf9214502d1dc240a9075a7c6ed55",
"hashed_secret": "333f0f8814d63e7268f80e1e65e7549137d2350c",
"is_secret": false,
"is_verified": false,
"line_number": 79,
"line_number": 88,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "333f0f8814d63e7268f80e1e65e7549137d2350c",
"hashed_secret": "f2e7745f43b0ef0e2c2faf61d6c6a28be2965750",
"is_secret": false,
"is_verified": false,
"line_number": 88,
"line_number": 92,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -320,15 +320,15 @@
"hashed_secret": "d4c3d66fd0c38547a3c7a4c6bdc29c36911bc030",
"is_secret": false,
"is_verified": false,
"line_number": 45,
"line_number": 46,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "8318df9ecda039deac9868adf1944a29a95c7114",
"is_secret": false,
"is_verified": false,
"line_number": 48,
"line_number": 49,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -637,6 +637,66 @@
"verified_result": null
}
],
"core/mcsp_authenticator.go": [
{
"hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3",
"is_secret": false,
"is_verified": false,
"line_number": 279,
"type": "Secret Keyword",
"verified_result": null
}
],
"core/mcsp_authenticator_test.go": [
{
"hashed_secret": "fd08cd887ed1de2f2d3e175117ff607ca65187ae",
"is_secret": false,
"is_verified": false,
"line_number": 35,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "d03d939c22ad66a948ec8b4649add9b12b8a3cf6",
"is_secret": false,
"is_verified": false,
"line_number": 38,
"type": "JSON Web Token",
"verified_result": null
},
{
"hashed_secret": "5dcb6cb71ea20f1a58387e3d36d77bd123eb9f3b",
"is_secret": false,
"is_verified": false,
"line_number": 39,
"type": "JSON Web Token",
"verified_result": null
},
{
"hashed_secret": "65e496a8c40e0364f378688b5e612a2386ad38d1",
"is_secret": false,
"is_verified": false,
"line_number": 646,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "4c809455939f19c33c732b56a8417e509f4885e8",
"is_secret": false,
"is_verified": false,
"line_number": 647,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "32e8612d8ca77c7ea8374aa7918db8e5df9252ed",
"is_secret": false,
"is_verified": false,
"line_number": 669,
"type": "Secret Keyword",
"verified_result": null
}
],
"core/utils_test.go": [
{
"hashed_secret": "0266262f439c732a31b9353ced05c9e777a07c54",
Expand Down Expand Up @@ -741,34 +801,34 @@
"verified_result": null
},
{
"hashed_secret": "f2e7745f43b0ef0e2c2faf61d6c6a28be2965750",
"hashed_secret": "4e44e97dae1aa4e93c01536f48bbd8602133a86d",
"is_secret": false,
"is_verified": false,
"line_number": 54,
"line_number": 66,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "4e44e97dae1aa4e93c01536f48bbd8602133a86d",
"hashed_secret": "00cafd126182e8a9e7c01bb2f0dfd00496be724f",
"is_secret": false,
"is_verified": false,
"line_number": 66,
"line_number": 85,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "00cafd126182e8a9e7c01bb2f0dfd00496be724f",
"hashed_secret": "f2e7745f43b0ef0e2c2faf61d6c6a28be2965750",
"is_secret": false,
"is_verified": false,
"line_number": 85,
"line_number": 90,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "9e2659aa7e2b335ec6bdcf180f3b6f41f5191af5",
"is_secret": false,
"is_verified": false,
"line_number": 90,
"line_number": 96,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
101 changes: 98 additions & 3 deletions Authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The go-sdk-core project supports the following types of authentication:
- Container Authentication
- VPC Instance Authentication
- Cloud Pak for Data Authentication
- Multi-Cloud Saas Platform (MCSP) Authentication
- No Authentication (for testing)

The SDK user configures the appropriate type of authentication for use with service instances.
Expand Down Expand Up @@ -228,7 +229,7 @@ certificate should be disabled or not. The default value is `false`.
- Headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
made to the IAM token service.

- Client: (Optional) The `http.Client` object used to invoke token servive requests. If not specified
- Client: (Optional) The `http.Client` object used to invoke token service requests. If not specified
by the user, a suitable default Client will be constructed.

### Usage Notes
Expand Down Expand Up @@ -367,7 +368,7 @@ certificate should be disabled or not. The default value is `false`.
- Headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
made to the IAM token service.

- Client: (optional) The `http.Client` object used to invoke token servive requests. If not specified
- Client: (optional) The `http.Client` object used to invoke token service requests. If not specified
by the user, a suitable default Client will be constructed.

### Programming example
Expand Down Expand Up @@ -557,7 +558,7 @@ certificate should be disabled or not. The default value is `false`.
- Headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
made to the Cloud Pak for Data token service.

- Client: (Optional) The `http.Client` object used to invoke token servive requests. If not specified
- Client: (Optional) The `http.Client` object used to invoke token service requests. If not specified
by the user, a suitable default Client will be constructed.

### Programming example
Expand Down Expand Up @@ -619,6 +620,100 @@ if err != nil {
```


## Multi-Cloud Saas Platform (MCSP) Authentication
The `MCSPAuthenticator` can be used in scenarios where an application needs to
interact with an IBM Cloud service that has been deployed to a non-IBM Cloud environment (e.g. AWS).
It accepts a user-supplied apikey and performs the necessary interactions with the
Multi-Cloud Saas Platform token service to obtain a suitable MCSP access token (a bearer token)
for the specified apikey.
The authenticator will also obtain a new bearer token when the current token expires.
The bearer token is then added to each outbound request in the `Authorization` header in the
form:
```
Authorization: Bearer <bearer-token>
```

### Properties

- ApiKey: (required) the apikey to be used to obtain an MCSP access token.

- URL: (required) The URL representing the MCSP token service endpoint's base URL string. Do not include the
operation path (e.g. `/siusermgr/api/1.0/apikeys/token`) as part of this property's value.

- DisableSSLVerification: (optional) A flag that indicates whether verificaton of the server's SSL
certificate should be disabled or not. The default value is `false`.

- Headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
made to the MCSP token service.

- Client: (optional) The `http.Client` object used to invoke token service requests. If not specified
by the user, a suitable default Client will be constructed.

### Usage Notes
- When constructing an MCSPAuthenticator instance, you must specify the ApiKey and URL properties.

- The authenticator will use the token server's `POST /siusermgr/api/1.0/apikeys/token` operation to
exchange the user-supplied apikey for an MCSP access token (the bearer token).

### Programming example
```go
import {
"github.com/IBM/go-sdk-core/v5/core"
"<appropriate-git-repo-url>/exampleservicev1"
}
...
// Create the authenticator.
authenticator, err := core.NewMCSPAuthenticatorBuilder().
SetApiKey("myapikey").
SetURL("https://example.mcsp.token-exchange.com").
Build()
if err != nil {
panic(err)
}

// Create the service options struct.
options := &exampleservicev1.ExampleServiceV1Options{
Authenticator: authenticator,
}

// Construct the service instance.
service, err := exampleservicev1.NewExampleServiceV1(options)
if err != nil {
panic(err)
}

// 'service' can now be used to invoke operations.
```

### Configuration example
External configuration:
```
export EXAMPLE_SERVICE_AUTH_TYPE=mcsp
export EXAMPLE_SERVICE_APIKEY=myapikey
export EXAMPLE_SERVICE_AUTH_URL=https://example.mcsp.token-exchange.com
```
Application code:
```go
import {
"<appropriate-git-repo-url>/exampleservicev1"
}
...

// Create the service options struct.
options := &exampleservicev1.ExampleServiceV1Options{
ServiceName: "example_service",
}

// Construct the service instance.
service, err := exampleservicev1.NewExampleServiceV1UsingExternalConfig(options)
if err != nil {
panic(err)
}

// 'service' can now be used to invoke operations.
```


## No Auth Authentication
The `NoAuthAuthenticator` is a placeholder authenticator which performs no actual authentication function.
It can be used in situations where authentication needs to be bypassed, perhaps while developing
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ The go-sdk-core project supports the following types of authentication:
- Container Authentication
- VPC Instance Authentication
- Cloud Pak for Data Authentication
- Multi-Cloud Saas Platform (MCSP) Authentication
- No Authentication (for testing)

For more information about the various authentication types and how to use them with your services, click [here](Authentication.md).
Expand Down
4 changes: 3 additions & 1 deletion core/authenticator_factory.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package core

// (C) Copyright IBM Corp. 2019, 2021.
// (C) Copyright IBM Corp. 2019, 2023.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -58,6 +58,8 @@ func GetAuthenticatorFromEnvironment(credentialKey string) (authenticator Authen
authenticator, err = newVpcInstanceAuthenticatorFromMap(properties)
} else if strings.EqualFold(authType, AUTHTYPE_CP4D) {
authenticator, err = newCloudPakForDataAuthenticatorFromMap(properties)
} else if strings.EqualFold(authType, AUTHTYPE_MCSP) {
authenticator, err = newMCSPAuthenticatorFromMap(properties)
} else if strings.EqualFold(authType, AUTHTYPE_NOAUTH) {
authenticator, err = NewNoAuthAuthenticator()
} else {
Expand Down
25 changes: 24 additions & 1 deletion core/authenticator_factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

package core

// (C) Copyright IBM Corp. 2019.
// (C) Copyright IBM Corp. 2019, 2023.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -119,6 +119,18 @@ func TestGetAuthenticatorFromEnvironment1(t *testing.T) {
assert.Equal(t, "user1", iamAuth.ClientId)
assert.Equal(t, "secret1", iamAuth.ClientSecret)
assert.Equal(t, "https://iam.refresh-token.com", iamAuth.URL)

// MCSP Authenticator.
authenticator, err = GetAuthenticatorFromEnvironment("service10")
assert.Nil(t, err)
assert.NotNil(t, authenticator)
assert.Equal(t, AUTHTYPE_MCSP, authenticator.AuthenticationType())
mcspAuth, ok := authenticator.(*MCSPAuthenticator)
assert.True(t, ok)
assert.NotNil(t, mcspAuth)
assert.Equal(t, "my-api-key", mcspAuth.ApiKey)
assert.Equal(t, "https://mcsp.ibm.com", mcspAuth.URL)
assert.True(t, mcspAuth.DisableSSLVerification)
}

func TestGetAuthenticatorFromEnvironment2(t *testing.T) {
Expand Down Expand Up @@ -207,6 +219,17 @@ func TestGetAuthenticatorFromEnvironment2(t *testing.T) {
assert.True(t, ok)
assert.NotNil(t, containerAuth)
assert.Equal(t, "iam-user2", containerAuth.IAMProfileName)

authenticator, err = GetAuthenticatorFromEnvironment("service14")
assert.Nil(t, err)
assert.NotNil(t, authenticator)
assert.Equal(t, AUTHTYPE_MCSP, authenticator.AuthenticationType())
mcspAuth, ok := authenticator.(*MCSPAuthenticator)
assert.True(t, ok)
assert.NotNil(t, mcspAuth)
assert.Equal(t, "my-api-key", mcspAuth.ApiKey)
assert.Equal(t, "https://mcsp.ibm.com", mcspAuth.URL)
assert.True(t, mcspAuth.DisableSSLVerification)
}

func TestGetAuthenticatorFromEnvironment3(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions core/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ var testEnvironment = map[string]string{
"SERVICE11_AUTH_TYPE": "bad_auth_type",
"SERVICE12_APIKEY": "my-apikey",
"SERVICE13_IAM_PROFILE_NAME": "iam-user2",
"SERVICE14_AUTH_TYPE": "mcsp",
"SERVICE14_AUTH_URL": "https://mcsp.ibm.com",
"SERVICE14_APIKEY": "my-api-key",
"SERVICE14_AUTH_DISABLE_SSL": "true",
}

// setTestEnvironment sets the environment variables described in our map.
Expand Down
Loading

0 comments on commit 8987085

Please sign in to comment.