Skip to content

Commit 9cc61e0

Browse files
committed
feat(IamAssumeAuthenticator): introduce new authenticator type
This commit introduces the new IamAssumeAuthenticator which will fetch an IAM access token using the IAM getToken operation's "assume" grant type. The resulting access token allows the application to assume the identity of a trusted profile, similar to the "sudo" feature of Linux. Signed-off-by: Phil Adams <[email protected]>
1 parent a261640 commit 9cc61e0

File tree

13 files changed

+1323
-18
lines changed

13 files changed

+1323
-18
lines changed

.secrets.baseline

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "package-lock.json|^.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2024-09-03T23:09:01Z",
6+
"generated_at": "2024-10-01T19:33:35Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"
@@ -70,23 +70,55 @@
7070
"hashed_secret": "91dfd9ddb4198affc5c194cd8ce6d338fde470e2",
7171
"is_secret": false,
7272
"is_verified": false,
73-
"line_number": 72,
73+
"line_number": 73,
74+
"type": "Secret Keyword",
75+
"verified_result": null
76+
},
77+
{
78+
"hashed_secret": "4f51cde3ac0a5504afa4bc06859b098366592c19",
79+
"is_secret": false,
80+
"is_verified": false,
81+
"line_number": 222,
82+
"type": "Secret Keyword",
83+
"verified_result": null
84+
},
85+
{
86+
"hashed_secret": "e87559ed7decb62d0733ae251ae58d42a55291d8",
87+
"is_secret": false,
88+
"is_verified": false,
89+
"line_number": 224,
90+
"type": "Secret Keyword",
91+
"verified_result": null
92+
},
93+
{
94+
"hashed_secret": "12f4a68ed3d0863e56497c9cdb1e2e4e91d5cb68",
95+
"is_secret": false,
96+
"is_verified": false,
97+
"line_number": 288,
98+
"type": "Secret Keyword",
99+
"verified_result": null
100+
},
101+
{
102+
"hashed_secret": "c837b75d7cd93ef9c2243ca28d6e5156259fd253",
103+
"is_secret": false,
104+
"is_verified": false,
105+
"line_number": 292,
74106
"type": "Secret Keyword",
75107
"verified_result": null
76108
},
77109
{
78110
"hashed_secret": "98635b2eaa2379f28cd6d72a38299f286b81b459",
79111
"is_secret": false,
80112
"is_verified": false,
81-
"line_number": 407,
113+
"line_number": 526,
82114
"type": "Secret Keyword",
83115
"verified_result": null
84116
},
85117
{
86118
"hashed_secret": "47fcf185ee7e15fe05cae31fbe9e4ebe4a06a40d",
87119
"is_secret": false,
88120
"is_verified": false,
89-
"line_number": 510,
121+
"line_number": 629,
90122
"type": "Secret Keyword",
91123
"verified_result": null
92124
}
@@ -104,23 +136,23 @@
104136
"hashed_secret": "d4c3d66fd0c38547a3c7a4c6bdc29c36911bc030",
105137
"is_secret": false,
106138
"is_verified": false,
107-
"line_number": 46,
139+
"line_number": 47,
108140
"type": "Secret Keyword",
109141
"verified_result": null
110142
},
111143
{
112144
"hashed_secret": "8318df9ecda039deac9868adf1944a29a95c7114",
113145
"is_secret": false,
114146
"is_verified": false,
115-
"line_number": 49,
147+
"line_number": 50,
116148
"type": "Secret Keyword",
117149
"verified_result": null
118150
},
119151
{
120152
"hashed_secret": "9a66213cc16d178fdbf9f4da6b7bd92497fda404",
121153
"is_secret": false,
122154
"is_verified": false,
123-
"line_number": 55,
155+
"line_number": 56,
124156
"type": "Secret Keyword",
125157
"verified_result": null
126158
}
@@ -183,6 +215,16 @@
183215
"verified_result": null
184216
}
185217
],
218+
"src/test/java/com/ibm/cloud/sdk/core/test/security/IamAssumeAuthenticatorTest.java": [
219+
{
220+
"hashed_secret": "333f0f8814d63e7268f80e1e65e7549137d2350c",
221+
"is_secret": false,
222+
"is_verified": false,
223+
"line_number": 57,
224+
"type": "Secret Keyword",
225+
"verified_result": null
226+
}
227+
],
186228
"src/test/java/com/ibm/cloud/sdk/core/test/security/JsonWebTokenTest.java": [
187229
{
188230
"hashed_secret": "c6ba9cef42f298486a61546fefd03a4177e60a99",

Authentication.md

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
The java-sdk-core project supports the following types of authentication:
33
- Basic Authentication
44
- Bearer Token Authentication
5-
- Identity and Access Management (IAM) Authentication
5+
- Identity and Access Management (IAM) Authentication (grant type: apikey)
6+
- Identity and Access Management (IAM) Authentication (grant type: assume)
67
- Container Authentication
78
- VPC Instance Authentication
89
- Cloud Pak for Data Authentication
@@ -12,11 +13,11 @@ The java-sdk-core project supports the following types of authentication:
1213
The SDK user configures the appropriate type of authentication for use with service instances.
1314
The authentication types that are appropriate for a particular service may vary from service to service,
1415
so it is important for the SDK user to consult with the appropriate service documentation to understand
15-
which authenticators are supported for that service.
16+
which authentication types are supported for that service.
1617

1718
The java-sdk-core allows an authenticator to be specified in one of two ways:
1819
1. programmatically - the SDK user constructs an instance of the desired authenticator using the appropriate Builder class or constructor,
19-
and then passes the authenticator instance when constructing an instance of the service.
20+
and then passes the authenticator instance when constructing an instance of the service client.
2021
2. configuration - the SDK user provides external configuration information (in the form of environment variables
2122
or a credentials file) to indicate the type of authenticator, along with the configuration of the necessary properties
2223
for that authenticator.
@@ -138,10 +139,10 @@ authenticator type is intended for situations in which the application will be m
138139
token itself in terms of initial acquisition and refreshing as needed.
139140

140141

141-
## Identity and Access Management (IAM) Authentication
142-
The `IamAuthenticator` will accept a user-supplied api key and will perform
142+
## Identity and Access Management (IAM) Authentication (grant type: apikey)
143+
The `IamAuthenticator` will accept a user-supplied apikey and will perform
143144
the necessary interactions with the IAM token service to obtain a suitable
144-
bearer token for the specified api key. The authenticator will also obtain
145+
bearer token for the specified apikey. The authenticator will also obtain
145146
a new bearer token when the current token expires. The bearer token is
146147
then added to each outbound request in the `Authorization` header in the
147148
form:
@@ -151,7 +152,7 @@ form:
151152

152153
### Properties
153154

154-
- apikey: (required) the IAM api key
155+
- apikey: (required) the IAM apikey to be used to obtain an IAM access token.
155156

156157
- url: (optional) The base endpoint URL of the IAM token service.
157158
The default value of this property is the "prod" IAM token service endpoint
@@ -214,6 +215,124 @@ ExampleService service = ExampleService.newInstance("example_service");
214215
```
215216

216217

218+
## Identity and Access Management (IAM) Authentication (grant type: assume)
219+
The `IamAssumeAuthenticator` performs a two-step token fetch sequence to obtain
220+
a bearer token that allows the application to assume the identity of a trusted profile:
221+
1. First, the authenticator obtains an initial bearer token using grant type
222+
`urn:ibm:params:oauth:grant-type:apikey`.
223+
This initial token will reflect the identity associated with the input apikey.
224+
2. Second, the authenticator uses the grant type `urn:ibm:params:oauth:grant-type:assume` to obtain a bearer token
225+
that reflects the identity of the trusted profile, passing in the initial bearer token
226+
from the first step, along with the trusted profile-related inputs.
227+
228+
The authenticator will also obtain a new bearer token when the current token expires.
229+
The bearer token is then added to each outbound request in the `Authorization` header in the
230+
form:
231+
```
232+
Authorization: Bearer <bearer-token>
233+
```
234+
235+
### Properties
236+
237+
- apikey: (required) the IAM apikey to be used to obtain the initial IAM access token.
238+
239+
- iamProfileCrn: (optional) the Cloud Resource Name (CRN) associated with the trusted profile
240+
for which an access token should be fetched.
241+
Exactly one of iamProfileCrn, iamProfileId or iamProfileName must be specified.
242+
243+
- iamProfileId: (optional) the ID associated with the trusted profile
244+
for which an access token should be fetched.
245+
Exactly one of iamProfileCrn, iamProfileId or iamProfileName must be specified.
246+
247+
- iamProfileName: (optional) the name associated with the trusted profile
248+
for which an access token should be fetched. When specifying this property, you must also
249+
specify the iamAccountId property as well.
250+
Exactly one of iamProfileCrn, iamProfileId or iamProfileName must be specified.
251+
252+
- iamAccountId: (optional) the ID associated with the IAM account that contains the trusted profile
253+
referenced by the iamProfileName property. The imaAccountId property must be specified if and only if
254+
the iamProfileName property is specified.
255+
256+
- url: (optional) The base endpoint URL of the IAM token service.
257+
The default value of this property is the "prod" IAM token service endpoint
258+
(`https://iam.cloud.ibm.com`).
259+
Make sure that you use an IAM token service endpoint that is appropriate for the
260+
location of the service being used by your application.
261+
For example, if you are using an instance of a service in the "production" environment
262+
(e.g. `https://resource-controller.cloud.ibm.com`),
263+
then the default "prod" IAM token service endpoint should suffice.
264+
However, if your application is using an instance of a service in the "staging" environment
265+
(e.g. `https://resource-controller.test.cloud.ibm.com`),
266+
then you would also need to configure the authenticator to use the IAM token service "staging"
267+
endpoint as well (`https://iam.test.cloud.ibm.com`).
268+
269+
- clientId/clientSecret: (optional) The `clientId` and `clientSecret` fields are used to form a
270+
"basic auth" Authorization header for interactions with the IAM token server when fetching the
271+
initial IAM access token. These fields are optional, but must be specified together.
272+
273+
- scope: (optional) the scope to be used when obtaining the initial IAM access token.
274+
If not specified, then no scope will be associated with the access token.
275+
276+
- disableSSLVerification: (optional) A flag that indicates whether verification of the server's SSL
277+
certificate should be disabled or not. The default value is `false`.
278+
279+
- headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
280+
made to the IAM token service.
281+
282+
### Usage Notes
283+
- The IamAssumeAuthenticator is used to obtain an access token (a bearer token) from the IAM token service
284+
that allows an application to "assume" the identity of a trusted profile.
285+
286+
- The authenticator first uses the apikey, url, clientId/clientSecret, scope, disableSSLVerification, and headers
287+
properties to obtain an initial access token by invoking the IAM `getToken`
288+
(grant_type=`urn:ibm:params:oauth:grant-type:apikey`) operation.
289+
290+
- The authenticator then uses the initial access token along with the url, iamProfileCrn, iamProfileId,
291+
iamProfileName, iamAccountId, disableSSLVerification, and headers properties to obtain an access token by invoking
292+
the IAM `getToken` (grant_type=`urn:ibm:params:oauth:grant-type:assume`) operation.
293+
The access token resulting from this second step will reflect the identity of the specified trusted profile.
294+
295+
- When providing the trusted profile information, you must specify exactly one of: iamProfileCrn, iamProfileId
296+
or iamProfileName. If you specify iamProfileCrn or iamProfileId, then the trusted profile must exist in the same account that is
297+
associated with the input apikey. If you specify iamProfileName, then you must also specify the iamAccountId property
298+
to indicate the IAM account in which the named trusted profile can be found.
299+
300+
### Programming example
301+
```java
302+
import com.ibm.cloud.sdk.core.security.IamAssumeAuthenticator;
303+
import <sdk_base_package>.ExampleService.v1.ExampleService;
304+
...
305+
// Create the authenticator.
306+
IamAssumeAuthenticator authenticator = new IamAssumeAuthenticator.Builder()
307+
.iamProfileId("myprofile-1")
308+
.apikey("myapikey")
309+
.build();
310+
311+
// Create the service instance.
312+
ExampleService service = new ExampleService(ExampleService.DEFAULT_SERVICE_NAME, authenticator);
313+
314+
// 'service' can now be used to invoke operations.
315+
```
316+
317+
### Configuration example
318+
External configuration:
319+
```
320+
export EXAMPLE_SERVICE_AUTH_TYPE=iamAssume
321+
export EXAMPLE_SERVICE_APIKEY=myapikey
322+
export EXAMPLE_SERVICE_IAM_PROFILE_ID=myprofile-1
323+
```
324+
Application code:
325+
```java
326+
import <sdk_base_package>.ExampleService.v1.ExampleService;
327+
...
328+
329+
// Create the service instance.
330+
ExampleService service = ExampleService.newInstance("example_service");
331+
332+
// 'service' can now be used to invoke operations.
333+
```
334+
335+
217336
## Container Authentication
218337
The `ContainerAuthenticator` is intended to be used by application code
219338
running inside a compute resource managed by the IBM Kubernetes Service (IKS)

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ You can find the Javadoc for this project here: https://ibm.github.io/java-sdk-c
3939
The java-sdk-core project supports the following types of authentication:
4040
- Basic Authentication
4141
- Bearer Token Authentication
42-
- Identity and Access Management (IAM) Authentication
42+
- Identity and Access Management (IAM) Authentication (grant type: apikey)
43+
- Identity and Access Management (IAM) Authentication (grant type: assume)
4344
- Container Authentication
4445
- VPC Instance Authentication
4546
- Cloud Pak for Data Authentication
47+
- Multi-Cloud Saas Platform (MCSP) Authentication
4648
- No Authentication (for testing)
4749

4850
For more information about the various authentication types and how to use them with your services, click [here](Authentication.md).

src/main/java/com/ibm/cloud/sdk/core/security/Authenticator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* (C) Copyright IBM Corp. 2019, 2021.
2+
* (C) Copyright IBM Corp. 2019, 2024.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
55
* the License. You may obtain a copy of the License at
@@ -26,6 +26,7 @@ public interface Authenticator {
2626
String AUTHTYPE_BASIC = "basic";
2727
String AUTHTYPE_NOAUTH = "noAuth";
2828
String AUTHTYPE_IAM = "iam";
29+
String AUTHTYPE_IAM_ASSUME = "iamAssume";
2930
String AUTHTYPE_CP4D = "cp4d";
3031
String AUTHTYPE_CP4D_SERVICE = "cp4dService";
3132
String AUTHTYPE_CP4D_SERVICE_INSTANCE = "cp4dServiceInstance";
@@ -57,6 +58,7 @@ public interface Authenticator {
5758
String PROPNAME_IAM_PROFILE_CRN = "IAM_PROFILE_CRN";
5859
String PROPNAME_IAM_PROFILE_ID = "IAM_PROFILE_ID";
5960
String PROPNAME_IAM_PROFILE_NAME = "IAM_PROFILE_NAME";
61+
String PROPNAME_IAM_ACCOUNT_ID = "IAM_ACCOUNT_ID";
6062

6163
/**
6264
* Validates the current set of configuration information in the Authenticator.

src/main/java/com/ibm/cloud/sdk/core/security/AuthenticatorBase.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* (C) Copyright IBM Corp. 2019, 2023.
2+
* (C) Copyright IBM Corp. 2019, 2024.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
55
* the License. You may obtain a copy of the License at
@@ -32,7 +32,10 @@ public class AuthenticatorBase {
3232
public static final String ERRORMSG_ATLEAST_ONE_PROP_ERROR = "At least one of %s or %s must be specified.";
3333
public static final String ERRORMSG_ATMOST_ONE_PROP_ERROR = "At most one of %s or %s may be specified.";
3434
public static final String ERRORMSG_PROP_INVALID_INTEGER_VALUE =
35-
"The %s property must be a valid integer but was %s.";
35+
"The %s property must be a valid integer but was %s.";
36+
public static final String ERRORMSG_ACCOUNTID_PROP_ERROR =
37+
"iamAccountId must be specified if and only if iamProfileName is specified";
38+
3639
/**
3740
* Returns a "Basic" Authorization header value for the specified username and password.
3841
* @param username the username

src/main/java/com/ibm/cloud/sdk/core/security/ConfigBasedAuthenticatorFactory.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ protected static Authenticator createAuthenticator(Map<String, String> props) {
101101
authenticator = CloudPakForDataServiceInstanceAuthenticator.fromConfiguration(props);
102102
} else if (authType.equalsIgnoreCase(Authenticator.AUTHTYPE_IAM)) {
103103
authenticator = IamAuthenticator.fromConfiguration(props);
104+
} else if (authType.equalsIgnoreCase(Authenticator.AUTHTYPE_IAM_ASSUME)) {
105+
authenticator = IamAssumeAuthenticator.fromConfiguration(props);
104106
} else if (authType.equalsIgnoreCase(Authenticator.AUTHTYPE_CONTAINER)) {
105107
authenticator = ContainerAuthenticator.fromConfiguration(props);
106108
} else if (authType.equalsIgnoreCase(Authenticator.AUTHTYPE_VPC)) {

0 commit comments

Comments
 (0)