Skip to content

Commit

Permalink
feat(IamAuthenticator): support refresh token flow in IamAuthenticator
Browse files Browse the repository at this point in the history
This commit updates the IamAuthenticator so that it supports
the "refresh token" auth flow.  In this scenario, the user constructs
an IamAuthenticator with a refresh token (and client id/secret) instead
of an apikey.  The authenticator will use the "POST /identity/token"
operation with grant_type "refresh_token" to obtain an IAM access token.

In this commit, I also added a new "builder" for the IamAuthenticator
as well, and deprecated the legacy ctor function although it is still supported.
  • Loading branch information
padamstx committed Nov 19, 2021
1 parent e9f7e72 commit 27ba218
Show file tree
Hide file tree
Showing 7 changed files with 774 additions and 262 deletions.
72 changes: 48 additions & 24 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": "2021-11-19T15:12:46Z",
"generated_at": "2021-11-19T21:42:10Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -96,19 +96,27 @@
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "e0d246cf37df7d1a561ed649d108dd14f36f28bf",
"is_secret": false,
"is_verified": false,
"line_number": 241,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "98635b2eaa2379f28cd6d72a38299f286b81b459",
"is_secret": false,
"is_verified": false,
"line_number": 522,
"line_number": 546,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "47fcf185ee7e15fe05cae31fbe9e4ebe4a06a40d",
"is_secret": false,
"is_verified": false,
"line_number": 571,
"line_number": 595,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -322,7 +330,7 @@
"hashed_secret": "8318df9ecda039deac9868adf1944a29a95c7114",
"is_secret": false,
"is_verified": false,
"line_number": 47,
"line_number": 48,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -486,81 +494,89 @@
"hashed_secret": "7a5d27bcb7a1e98b6e1bfca4df223ed578a47283",
"is_secret": false,
"is_verified": false,
"line_number": 89,
"line_number": 97,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "c2df5d3d760ff42f33fb38e2534d4c1b7ddde3ab",
"is_secret": false,
"is_verified": false,
"line_number": 89,
"line_number": 97,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "f75b33f87ffeacb3a4f793a09693e672e07449ff",
"hashed_secret": "8b142a91cfb6e617618ad437cedf74a6745f8926",
"is_secret": false,
"is_verified": false,
"line_number": 96,
"line_number": 133,
"type": "Secret Keyword",
"verified_result": null
}
],
"v5/core/iam_authenticator_test.go": [
{
"hashed_secret": "fd08cd887ed1de2f2d3e175117ff607ca65187ae",
"is_secret": false,
"is_verified": false,
"line_number": 34,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "7ea6be9eecb6605329a1b1870c2fd2af9b896991",
"hashed_secret": "1f7e33de15e22de9d2eaf502df284ed25ca40018",
"is_secret": false,
"is_verified": false,
"line_number": 99,
"line_number": 37,
"type": "Secret Keyword",
"verified_result": null
}
],
"v5/core/iam_authenticator_test.go": [
},
{
"hashed_secret": "c8f0df25bade89c1873f5f01b85bcfb921443ac6",
"is_secret": false,
"is_verified": false,
"line_number": 33,
"line_number": 41,
"type": "JSON Web Token",
"verified_result": null
},
{
"hashed_secret": "42de4dc186286dbdc2381b3e09a054f96e1995bc",
"hashed_secret": "1f5e25be9b575e9f5d39c82dfd1d9f4d73f1975c",
"is_secret": false,
"is_verified": false,
"line_number": 589,
"line_number": 194,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "1f5e25be9b575e9f5d39c82dfd1d9f4d73f1975c",
"hashed_secret": "ffc168ba60490856fec503b911fab745e277370b",
"is_secret": false,
"is_verified": false,
"line_number": 734,
"line_number": 209,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "333f0f8814d63e7268f80e1e65e7549137d2350c",
"hashed_secret": "84de897bbaa1dac9c7e13b27ab2afc2a233a5e4e",
"is_secret": false,
"is_verified": false,
"line_number": 748,
"line_number": 230,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "84ba4ce8a59ed2d6e90726d57cdc4a927d3672b2",
"hashed_secret": "7480f0b7140317bd82ade3c7a9526408304d5a7f",
"is_secret": false,
"is_verified": false,
"line_number": 751,
"line_number": 504,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "32e8612d8ca77c7ea8374aa7918db8e5df9252ed",
"is_secret": false,
"is_verified": false,
"line_number": 770,
"line_number": 1047,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down Expand Up @@ -702,11 +718,19 @@
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "00cafd126182e8a9e7c01bb2f0dfd00496be724f",
"is_secret": false,
"is_verified": false,
"line_number": 85,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "9e2659aa7e2b335ec6bdcf180f3b6f41f5191af5",
"is_secret": false,
"is_verified": false,
"line_number": 83,
"line_number": 90,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
34 changes: 29 additions & 5 deletions Authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ token itself in terms of initial acquisition and refreshing as needed.


## Identity and Access Management Authentication (IAM)
The `IamAuthenticator` will accept a user-supplied api key and will perform
The `IamAuthenticator` will accept a user-supplied apikey or refresh token and will perform
the necessary interactions with the IAM token service to obtain a suitable
bearer token for the specified api key. The authenticator will also obtain
bearer token for the specified apikey or refresh token. 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:
Expand All @@ -193,7 +193,13 @@ form:

### Properties

- ApiKey: (required) the IAM api key
- ApiKey: (optional) the IAM apikey to be used to obtain an IAM access token.
One of ApiKey or RefreshToken must be specified.

- RefreshToken: (optional) a refresh token to be used to obtain an IAM access token.
One of ApiKey or RefreshToken must be specified. If RefreshToken is specified, then
the ClientId and ClientSecret properties must also be specified, using the same values that were
used to obtain the refresh token value.

- URL: (optional) The base endpoint URL of the IAM token service.
The default value of this property is the "prod" IAM token service endpoint
Expand Down Expand Up @@ -225,6 +231,21 @@ made to the IAM token service.
- Client: (Optional) The `http.Client` object used to invoke token servive requests. If not specified
by the user, a suitable default Client will be constructed.

### Usage Notes
- The IamAuthenticator is used to obtain an access token (a bearer token) from the IAM token service.

- When constructing an IamAuthenticator instance, you must specify exactly one of ApiKey or RefreshToken.

- If you specify the ApiKey property, the authenticator will use the
IAM token service's `POST /identity/token` operation
with grant_type `urn:ibm:params:oauth:grant-type:apikey` to exchange the apikey value for an access token.

- If you specify the RefreshToken property, the authenticator will use the
IAM token service's `POST /identity/token` operation
with grant_type `refresh_token` to exchange the refresh token value for an access token.
In this scenario, you must also specify the ClientId and ClientSecret properties, using the same values
that were used when initially obtaining the refresh token value from the IAM token service.

### Programming example
```go
import {
Expand All @@ -233,8 +254,11 @@ import {
}
...
// Create the authenticator.
authenticator := &core.IamAuthenticator{
ApiKey: "myapikey",
authenticator, err := core.NewIamAuthenticatorBuilder().
SetApiKey("myapikey").
Build()
if err != nil {
panic(err)
}

// Create the service options struct.
Expand Down
14 changes: 14 additions & 0 deletions v5/core/authenticator_factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,20 @@ func TestGetAuthenticatorFromEnvironment1(t *testing.T) {
assert.Equal(t, "iam-profile1-id", vpcAuth.IAMProfileID)
assert.Empty(t, vpcAuth.URL)

// IAM Authenticator using refresh token.
authenticator, err = GetAuthenticatorFromEnvironment("service9")
assert.Nil(t, err)
assert.NotNil(t, authenticator)
assert.Equal(t, AUTHTYPE_IAM, authenticator.AuthenticationType())
iamAuth, ok := authenticator.(*IamAuthenticator)
assert.True(t, ok)
assert.NotNil(t, iamAuth)
assert.Empty(t, iamAuth.ApiKey)
assert.Equal(t, "refresh-token", iamAuth.RefreshToken)
assert.Equal(t, "user1", iamAuth.ClientId)
assert.Equal(t, "secret1", iamAuth.ClientSecret)
assert.Equal(t, "https://iam.refresh-token.com", iamAuth.URL)

os.Unsetenv("IBM_CREDENTIALS_FILE")
}

Expand Down
1 change: 1 addition & 0 deletions v5/core/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const (
PROPNAME_AUTH_URL = "AUTH_URL"
PROPNAME_AUTH_DISABLE_SSL = "AUTH_DISABLE_SSL"
PROPNAME_APIKEY = "APIKEY"
PROPNAME_REFRESH_TOKEN = "REFRESH_TOKEN" // #nosec G101
PROPNAME_CLIENT_ID = "CLIENT_ID"
PROPNAME_CLIENT_SECRET = "CLIENT_SECRET"
PROPNAME_SCOPE = "SCOPE"
Expand Down
Loading

0 comments on commit 27ba218

Please sign in to comment.