Skip to content

Commit b82f326

Browse files
committed
feat: introduce new container authenticator
This commit introduces the new ContainerAuthenticator class, along with associated tests and documentation. The ContainerAuthenticator implements the authentication flow to be used in IKS-managed compute resources where a secure compute resource token has been injected into the local file system by the IKS compute resource provider. The authenticator will read the cr token, then use it to obtain an IAM access token by invoking the IAM "get token" operation with grant-type "cr-token".
1 parent a44720b commit b82f326

15 files changed

+1291
-62
lines changed

Authentication.md

Lines changed: 127 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# Authentication
22
The java-sdk-core project supports the following types of authentication:
33
- Basic Authentication
4-
- Bearer Token
5-
- Identity and Access Management (IAM)
6-
- Cloud Pak for Data
4+
- Bearer Token Authentication
5+
- Identity and Access Management (IAM) Authentication
6+
- Container Authentication
7+
- Cloud Pak for Data Authentication
78
- No Authentication
89

910
The SDK user configures the appropriate type of authentication for use with service instances.
@@ -23,15 +24,20 @@ configuration information. The configuration examples below will use
2324
environment variables, although the same properties could be specified in a
2425
credentials file instead.
2526

27+
2628
## Basic Authentication
2729
The `BasicAuthenticator` is used to add Basic Authentication information to
2830
each outbound request in the `Authorization` header in the form:
2931
```
3032
Authorization: Basic <encoded username and password>
3133
```
34+
3235
### Properties
36+
3337
- username: (required) the basic auth username
38+
3439
- password: (required) the basic auth password
40+
3541
### Programming example
3642
```java
3743
import com.ibm.cloud.sdk.core.security.BasicAuthenticator;
@@ -48,6 +54,7 @@ ExampleService service = new ExampleService(authenticator);
4854

4955
// 'service' can now be used to invoke operations.
5056
```
57+
5158
### Configuration example
5259
External configuration:
5360
```
@@ -69,14 +76,18 @@ ExampleService service = new ExampleService(authenticator);
6976
// 'service' can now be used to invoke operations.
7077
```
7178

79+
7280
## Bearer Token Authentication
7381
The `BearerTokenAuthenticator` will add a user-supplied bearer token to
7482
each outbound request in the `Authorization` header in the form:
7583
```
7684
Authorization: Bearer <bearer-token>
7785
```
86+
7887
### Properties
88+
7989
- bearerToken: (required) the bearer token value
90+
8091
### Programming example
8192
```java
8293
import com.ibm.cloud.sdk.core.security.BearerTokenAuthenticator;
@@ -96,6 +107,7 @@ ExampleService service = new ExampleService(authenticator);
96107
newToken = // ... obtain new bearer token value
97108
authenticator.setBearerToken(newToken);
98109
```
110+
99111
### Configuration example
100112
External configuration:
101113
```
@@ -120,13 +132,15 @@ ExampleService service = new ExampleService(authenticator);
120132
newToken = // ... obtain new bearer token value
121133
((BearerTokenAuthenticator) authenticator).setBearerToken(newToken);
122134
```
135+
123136
Note that the use of external configuration is not as useful with the `BearerTokenAuthenticator` as it
124137
is for other authenticator types because bearer tokens typically need to be obtained and refreshed
125138
programmatically since they normally have a relatively short lifespan before they expire. This
126139
authenticator type is intended for situations in which the application will be managing the bearer
127140
token itself in terms of initial acquisition and refreshing as needed.
128141

129-
## Identity and Access Management Authentication (IAM)
142+
143+
## Identity and Access Management (IAM) Authentication
130144
The `IamAuthenticator` will accept a user-supplied api key and will perform
131145
the necessary interactions with the IAM token service to obtain a suitable
132146
bearer token for the specified api key. The authenticator will also obtain
@@ -136,18 +150,25 @@ form:
136150
```
137151
Authorization: Bearer <bearer-token>
138152
```
153+
139154
### Properties
155+
140156
- apikey: (required) the IAM api key
157+
141158
- url: (optional) The URL representing the IAM token service endpoint. If not specified, a suitable
142159
default value is used.
160+
143161
- clientId/clientSecret: (optional) The `clientId` and `clientSecret` fields are used to form a
144162
"basic auth" Authorization header for interactions with the IAM token server. If neither field
145163
is specified, then no Authorization header will be sent with token server requests. These fields
146164
are optional, but must be specified together.
165+
147166
- disableSSLVerification: (optional) A flag that indicates whether verificaton of the server's SSL
148167
certificate should be disabled or not. The default value is `false`.
168+
149169
- headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
150170
made to the IAM token service.
171+
151172
### Programming example
152173
```java
153174
import com.ibm.cloud.sdk.core.security.IamAuthenticator;
@@ -163,6 +184,7 @@ ExampleService service = new ExampleService(authenticator);
163184

164185
// 'service' can now be used to invoke operations.
165186
```
187+
166188
### Configuration example
167189
External configuration:
168190
```
@@ -183,7 +205,99 @@ ExampleService service = new ExampleService(authenticator);
183205
// 'service' can now be used to invoke operations.
184206
```
185207

186-
## Cloud Pak for Data
208+
209+
## Container Authentication
210+
The `ContainerAuthenticator` is intended to be used by application code
211+
running inside a compute resource managed by the IBM Kubernetes Service (IKS)
212+
in which a secure compute resource token (CR token) has been stored in a file
213+
within the compute resource's local file system.
214+
The CR token is similar to an IAM apikey except that it is managed automatically by
215+
the compute resource provider (IKS).
216+
This allows the application developer to:
217+
- avoid storing credentials in application code, configuraton files or a password vault
218+
- avoid managing or rotating credentials
219+
220+
The `ContainerAuthenticator` will retrieve the CR token from
221+
the compute resource in which the application is running, and will then perform
222+
the necessary interactions with the IAM token service to obtain an IAM access token
223+
using the IAM "get token" operation with grant-type `cr-token`.
224+
The authenticator will repeat these steps to obtain a new IAM access token when the
225+
current access token expires.
226+
The IAM access token is added to each outbound request in the `Authorization` header in the form:
227+
```
228+
Authorization: Bearer <IAM-access-token>
229+
```
230+
231+
### Properties
232+
233+
- crTokenFilename: (optional) the name of the file containing the injected CR token value.
234+
If not specified, then `/var/run/secrets/tokens/vault-token` is used as the default value.
235+
The application must have `read` permissions on the file containing the CR token value.
236+
237+
- iamProfileName: (optional) the name of the linked trusted IAM profile to be used when obtaining the
238+
IAM access token (a CR token might map to multiple IAM profiles).
239+
One of `iamProfileName` or `iamProfileID` must be specified.
240+
241+
- iamProfileID: (optional) the id of the linked trusted IAM profile to be used when obtaining the
242+
IAM access token (a CR token might map to multiple IAM profiles).
243+
One of `iamProfileName` or `iamProfileID` must be specified.
244+
245+
- url: (optional) The base endpoint URL of the IAM token service.
246+
The default value of this property is the "prod" IAM token service endpoint
247+
(`https://iam.cloud.ibm.com`).
248+
249+
- clientId/clientSecret: (optional) The `clientId` and `clientSecret` fields are used to form a
250+
"basic auth" Authorization header for interactions with the IAM token service. If neither field
251+
is specified, then no Authorization header will be sent with token server requests. These fields
252+
are optional, but must be specified together.
253+
254+
- scope: (optional) the scope to be associated with the IAM access token.
255+
If not specified, then no scope will be associated with the access token.
256+
257+
- disableSSLVerification: (optional) A flag that indicates whether verificaton of the server's SSL
258+
certificate should be disabled or not. The default value is `false`.
259+
260+
- headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
261+
made to the IAM token service.
262+
263+
### Programming example
264+
```java
265+
import com.ibm.cloud.sdk.core.security.ContainerAuthenticator;
266+
import <sdk_base_package>.ExampleService.v1.ExampleService;
267+
...
268+
// Create the authenticator.
269+
ContainerAuthenticator authenticator = new ContainerAuthenticator.Builder()
270+
.iamProfileName("iam-user123")
271+
.build();
272+
273+
// Create the service instance.
274+
ExampleService service = new ExampleService(authenticator);
275+
276+
// 'service' can now be used to invoke operations.
277+
```
278+
279+
### Configuration example
280+
External configuration:
281+
```
282+
export EXAMPLE_SERVICE_AUTH_TYPE=container
283+
export EXAMPLE_SERVICE_IAM_PROFILE_NAME=iam-user123
284+
```
285+
Application code:
286+
```java
287+
import com.ibm.cloud.sdk.core.security.ConfigBaseAuthenticatorFactory;
288+
import <sdk_base_package>.ExampleService.v1.ExampleService;
289+
...
290+
// Create the authenticator.
291+
Authenticator authenticator = ConfigBasedAuthenticatorFactory.getAuthenticator("example_service");
292+
293+
// Create the service instance.
294+
ExampleService service = new ExampleService(authenticator);
295+
296+
// 'service' can now be used to invoke operations.
297+
```
298+
299+
300+
## Cloud Pak for Data Authentication
187301
The `CloudPakForDataAuthenticator` will accept user-supplied values for the username and either a password or apikey, and will
188302
perform the necessary interactions with the Cloud Pak for Data token service to obtain a suitable
189303
bearer token. The authenticator will also obtain a new bearer token when the current token expires.
@@ -192,15 +306,23 @@ form:
192306
```
193307
Authorization: Bearer <bearer-token>
194308
```
309+
195310
### Properties
311+
196312
- username: (required) the username used to obtain a bearer token.
313+
197314
- password: (required if apikey is not specified) the password used to obtain a bearer token.
315+
198316
- apikey: (required if password is not specified) the apikey used to obtain a bearer token.
317+
199318
- url: (required) The base URL associated with the Cloud Pak for Data token service.
319+
200320
- disableSSLVerification: (optional) A flag that indicates whether verificaton of the server's SSL
201321
certificate should be disabled or not. The default value is `false`.
322+
202323
- headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
203324
made to the IAM token service.
325+
204326
### Programming example
205327
```java
206328
import com.ibm.cloud.sdk.core.security.CloudPakForDataAuthenticator;

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public interface Authenticator {
2929
String AUTHTYPE_CP4D = "cp4d";
3030
String AUTHTYPE_CP4D_SERVICE = "cp4dService";
3131
String AUTHTYPE_BEARER_TOKEN = "bearerToken";
32+
String AUTHTYPE_CONTAINER = "container";
3233

3334
/**
3435
* Constants which define the names of external config propreties (credential file, environment variable, etc.).
@@ -48,6 +49,9 @@ public interface Authenticator {
4849
String PROPNAME_PERMISSIONS = "PERMISSIONS";
4950
String PROPNAME_EXPIRATION_TIME = "EXPIRATION_TIME";
5051
String PROPNAME_SERVICE_BROKER_SECRET = "SERVICE_BROKER_SECRET";
52+
String PROPNAME_CR_TOKEN_FILENAME = "CR_TOKEN_FILENAME";
53+
String PROPNAME_IAM_PROFILE_ID = "IAM_PROFILE_ID";
54+
String PROPNAME_IAM_PROFILE_NAME = "IAM_PROFILE_NAME";
5155

5256
/**
5357
* Validates the current set of configuration information in the Authenticator.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class AuthenticatorBase {
3030
"The %s property is invalid. Please remove any surrounding {, }, or \" characters.";
3131
public static final String ERRORMSG_REQ_FAILED = "Error while fetching access token from token service: ";
3232
public static final String ERRORMSG_EXCLUSIVE_PROP_ERROR = "Exactly one of %s or %s must be specified.";
33+
public static final String ERRORMSG_ATLEAST_ONE_PROP_ERROR = "At least one of %s or %s must be specified.";
3334
public static final String ERRORMSG_PROP_INVALID_INTEGER_VALUE =
3435
"The %s property must be a valid integer but was %s.";
3536
/**

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,15 @@ public static Authenticator getAuthenticator(String serviceName) {
6161
private static Authenticator createAuthenticator(Map<String, String> props) {
6262
Authenticator authenticator = null;
6363

64-
// If auth type was not specified, we'll use "iam" as the default.
64+
// If auth type was not specified, we'll use "iam" as the default if the "apikey" property
65+
// is present, otherwise we'll use "container" as the default.
6566
String authType = props.get(Authenticator.PROPNAME_AUTH_TYPE);
6667
if (StringUtils.isEmpty(authType)) {
67-
authType = Authenticator.AUTHTYPE_IAM;
68+
if (props.get(Authenticator.PROPNAME_APIKEY) != null || props.get("IAM_APIKEY") != null) {
69+
authType = Authenticator.AUTHTYPE_IAM;
70+
} else {
71+
authType = Authenticator.AUTHTYPE_CONTAINER;
72+
}
6873
}
6974

7075
// Create the appropriate authenticator based on the auth type.
@@ -76,8 +81,10 @@ private static Authenticator createAuthenticator(Map<String, String> props) {
7681
authenticator = CloudPakForDataAuthenticator.fromConfiguration(props);
7782
} else if (authType.equalsIgnoreCase(Authenticator.AUTHTYPE_CP4D_SERVICE)) {
7883
authenticator = CloudPakForDataServiceAuthenticator.fromConfiguration(props);
79-
} else if (authType.equalsIgnoreCase(Authenticator.AUTHTYPE_IAM)) {
84+
} else if (authType.equalsIgnoreCase(Authenticator.AUTHTYPE_IAM)) {
8085
authenticator = IamAuthenticator.fromConfiguration(props);
86+
} else if (authType.equalsIgnoreCase(Authenticator.AUTHTYPE_CONTAINER)) {
87+
authenticator = ContainerAuthenticator.fromConfiguration(props);
8188
} else if (authType.equalsIgnoreCase(Authenticator.AUTHTYPE_NOAUTH)) {
8289
authenticator = new NoAuthAuthenticator(props);
8390
} else {

0 commit comments

Comments
 (0)