Skip to content

Commit 2097a64

Browse files
feat: add new token manager for ICP4D (#26)
feat: add new token manager for ICP4D
2 parents 6d24f0a + dc3165d commit 2097a64

19 files changed

+1284
-473
lines changed

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ node_modules/
88
**/*v*.js
99
!test/**/*.js
1010
lib/*.js
11+
auth/*.js
1112
index.js
1213
scripts/typedoc/

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ doc/
99
.env
1010
.eslintcache
1111
lib/*.js
12+
auth/*.js
1213
iam-token-manager/*.js
1314
index.js
1415
.nyc_output

README.md

+17-1
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,28 @@ import { BaseService } from 'ibm-cloud-sdk-core';
1717
class YourSDK extends BaseService { ... }
1818
```
1919

20+
## Authentication Types
21+
There are several flavors of authentication supported in this package. To specify the intended authentication pattern to use, the user can pass in the parameter `authentication_type`. This parameter is optional, but it may become required in a future major release. The options for this parameter are `basic`, `iam`, and `icp4d`.
22+
23+
### basic
24+
This indicates Basic Auth is to be used. Users will pass in a `username` and `password` and the SDK will generate a Basic Auth header to send with requests to the service.
25+
26+
### iam
27+
This indicates that IAM token authentication is to be used. Users can pass in an `iam_apikey` or an `iam_access_token`. If an API key is used, the SDK will manage the token for the user. In either case, the SDK will generate a Bearer Auth header to send with requests to the service.
28+
29+
### icp4d
30+
This indicates that the service is an instance of ICP4D, which has its own version of token authentication. Users can pass in a `username` and `password`, or an `icp4d_access_token`. If a username and password is given, the SDK will manage the token for the user.
31+
A `url` is **required** for this type. In order to use an SDK-managed token with ICP4D authentication, this option **must** be passed in.
32+
2033
## Available Modules
2134
### BaseService
2235
This Class is the base class that all generated service-specific classes inherit from. It implements credentials handling and other shared behavior.
2336

2437
### IamTokenManagerV1
25-
This Class contains logic for managing an IAM token over its lifetime. Tokens can be requested or set manually. When requested, the token manager will either return the current token, request a new token or refresh the current token if it is expired. If a token is manually set, it must be managed by the user.
38+
This Class contains logic for managing an IAM token over its lifetime. Tokens can be requested or set manually. When requested, the token manager will either return the current token or request a new token if one is not saved or the the current token is expired. If a token is manually set, it must be managed by the user.
39+
40+
### Icp4dTokenManagerV1
41+
This Class is similar in function to IamTokenManagerV1. The only difference is that the `url` parameter is required, it takes a `username` and `password` instead of an API key, and manages tokens for instances of ICP4D. To use this token manager in an SDK, the parameter `authentication_type` must be set to `icp4d` in the constructor.
2642

2743
### isFileParam
2844
This function takes an Object and returns `true` if the object is a Stream, a Buffer, has a `value` property, or has a `data` property that is a file param (checked recursively).

auth/iam-token-manager-v1.ts

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/**
2+
* Copyright 2019 IBM Corp. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import extend = require('extend');
18+
import { JwtTokenManagerV1 } from './jwt-token-manager-v1';
19+
import { computeBasicAuthHeader } from './utils';
20+
21+
/**
22+
* Check for only one of two elements being defined.
23+
* Returns true if a is defined and b is undefined,
24+
* or vice versa. Returns false if both are defined
25+
* or both are undefined.
26+
*
27+
* @param {any} a - The first object
28+
* @param {any} b - The second object
29+
* @returns {boolean}
30+
*/
31+
function onlyOne(a: any, b: any): boolean {
32+
return Boolean((a && !b) || (b && !a));
33+
}
34+
35+
const CLIENT_ID_SECRET_WARNING = 'Warning: Client ID and Secret must BOTH be given, or the defaults will be used.';
36+
37+
export type Options = {
38+
url?: string;
39+
iamUrl?: string;
40+
iamApikey?: string;
41+
accessToken?: string;
42+
iamAccessToken?: string;
43+
iamClientId?: string;
44+
iamClientSecret?: string;
45+
}
46+
47+
// this interface is a representation of the response
48+
// object from the IAM service, hence the snake_case
49+
// parameter names
50+
export interface IamTokenData {
51+
access_token: string;
52+
refresh_token: string;
53+
token_type: string;
54+
expires_in: number;
55+
expiration: number;
56+
}
57+
58+
export class IamTokenManagerV1 extends JwtTokenManagerV1 {
59+
private iamApikey: string;
60+
private iamClientId: string;
61+
private iamClientSecret: string;
62+
63+
/**
64+
* IAM Token Manager Service
65+
*
66+
* Retreives and stores IAM access tokens.
67+
*
68+
* @param {Object} options
69+
* @param {String} options.iamApikey
70+
* @param {String} options.iamAccessToken
71+
* @param {String} options.iamUrl - url of the iam api to retrieve tokens from
72+
* @constructor
73+
*/
74+
constructor(options: Options) {
75+
super(options);
76+
77+
this.url = this.url || options.iamUrl || 'https://iam.cloud.ibm.com/identity/token';
78+
79+
if (options.iamApikey) {
80+
this.iamApikey = options.iamApikey;
81+
}
82+
if (options.iamAccessToken) {
83+
this.userAccessToken = options.iamAccessToken;
84+
}
85+
if (options.iamClientId) {
86+
this.iamClientId = options.iamClientId;
87+
}
88+
if (options.iamClientSecret) {
89+
this.iamClientSecret = options.iamClientSecret;
90+
}
91+
if (onlyOne(options.iamClientId, options.iamClientSecret)) {
92+
// tslint:disable-next-line
93+
console.log(CLIENT_ID_SECRET_WARNING);
94+
}
95+
}
96+
97+
/**
98+
* Set the IAM 'client_id' and 'client_secret' values.
99+
* These values are used to compute the Authorization header used
100+
* when retrieving the IAM access token.
101+
* If these values are not set, then a default Authorization header
102+
* will be used when interacting with the IAM token server.
103+
*
104+
* @param {string} iamClientId - The client id
105+
* @param {string} iamClientSecret - The client secret
106+
* @returns {void}
107+
*/
108+
public setIamAuthorizationInfo(iamClientId: string, iamClientSecret: string): void {
109+
this.iamClientId = iamClientId;
110+
this.iamClientSecret = iamClientSecret;
111+
if (onlyOne(iamClientId, iamClientSecret)) {
112+
// tslint:disable-next-line
113+
console.log(CLIENT_ID_SECRET_WARNING);
114+
}
115+
}
116+
117+
/**
118+
* Callback for handling response.
119+
*
120+
* @callback requestTokenCallback
121+
* @param {Error} An error if there is one, null otherwise
122+
* @param {Object} The response if request is successful, null otherwise
123+
*/
124+
/**
125+
* Request an IAM token using an API key.
126+
*
127+
* @param {requestTokenCallback} callback - The callback that handles the response.
128+
* @returns {void}
129+
*/
130+
protected requestToken(callback: Function): void {
131+
// Use bx:bx as default auth header creds.
132+
let clientId = 'bx';
133+
let clientSecret = 'bx';
134+
135+
// If both the clientId and secret were specified by the user, then use them.
136+
if (this.iamClientId && this.iamClientSecret) {
137+
clientId = this.iamClientId;
138+
clientSecret = this.iamClientSecret;
139+
}
140+
141+
const parameters = {
142+
options: {
143+
url: this.url,
144+
method: 'POST',
145+
headers: {
146+
'Content-type': 'application/x-www-form-urlencoded',
147+
Authorization: computeBasicAuthHeader(clientId, clientSecret),
148+
},
149+
form: {
150+
grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
151+
apikey: this.iamApikey,
152+
response_type: 'cloud_iam'
153+
},
154+
}
155+
};
156+
this.requestWrapperInstance.sendRequest(parameters, callback);
157+
}
158+
}

auth/icp4d-token-manager-v1.ts

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Copyright 2019 IBM Corp. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import extend = require('extend');
18+
import { JwtTokenManagerV1 } from './jwt-token-manager-v1';
19+
import { computeBasicAuthHeader } from './utils';
20+
21+
export type Options = {
22+
url: string;
23+
accessToken?: string;
24+
username?: string;
25+
password?: string;
26+
disableSslVerification?: boolean;
27+
}
28+
29+
// this interface is a representation of the response
30+
// object from the ICP4D authentication service
31+
export interface IcpTokenData {
32+
username: string;
33+
role: string;
34+
permissions: string[];
35+
sub: string;
36+
iss: string;
37+
aud: string;
38+
uid: string;
39+
_messageCode_: string;
40+
message: string;
41+
accessToken: string;
42+
}
43+
44+
export class Icp4dTokenManagerV1 extends JwtTokenManagerV1 {
45+
private username: string;
46+
private password: string;
47+
48+
/**
49+
* ICP Token Manager Service
50+
*
51+
* Retreives and stores ICP access tokens.
52+
*
53+
* @param {Object} options
54+
* @param {String} options.username
55+
* @param {String} options.password
56+
* @param {String} options.accessToken - user-managed access token
57+
* @param {String} options.url - URL for the ICP4D cluster
58+
* @param {Boolean} options.disableSslVerification - disable SSL verification for token request
59+
* @constructor
60+
*/
61+
constructor(options: Options) {
62+
super(options);
63+
64+
this.tokenName = 'accessToken';
65+
66+
if (this.url) {
67+
this.url = this.url + '/v1/preauth/validateAuth';
68+
} else if (!this.userAccessToken) {
69+
// url is not needed if the user specifies their own access token
70+
throw new Error('`url` is a required parameter for Icp4dTokenManagerV1');
71+
}
72+
73+
if (options.username) {
74+
this.username = options.username;
75+
}
76+
if (options.password) {
77+
this.password = options.password;
78+
}
79+
// username and password are required too, unless there's access token
80+
this.rejectUnauthorized = !options.disableSslVerification;
81+
}
82+
83+
/**
84+
* Callback for handling response.
85+
*
86+
* @callback requestTokenCallback
87+
* @param {Error} An error if there is one, null otherwise
88+
* @param {Object} The response if request is successful, null otherwise
89+
*/
90+
/**
91+
* Request an ICP token using a basic auth header.
92+
*
93+
* @param {requestTokenCallback} callback - The callback that handles the response.
94+
* @returns {void}
95+
*/
96+
protected requestToken(callback: Function): void {
97+
const parameters = {
98+
options: {
99+
url: this.url,
100+
method: 'GET',
101+
headers: {
102+
Authorization: computeBasicAuthHeader(this.username, this.password),
103+
},
104+
rejectUnauthorized: this.rejectUnauthorized,
105+
}
106+
};
107+
this.requestWrapperInstance.sendRequest(parameters, callback);
108+
}
109+
}

auth/index.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Copyright 2019 IBM Corp. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
export { IamTokenManagerV1 } from './iam-token-manager-v1';
18+
export { Icp4dTokenManagerV1 } from './icp4d-token-manager-v1';
19+
export { JwtTokenManagerV1 } from './jwt-token-manager-v1';
20+
export * from './utils';

0 commit comments

Comments
 (0)