Skip to content

Commit 3c88edb

Browse files
authored
fix: allow iam client id and secret to be read from constructor (#17)
* fix: allow iam client id and secret to be read from constructor * refactor: add a warning for the user if they dont pass both clientid and secret
1 parent e46cbcf commit 3c88edb

File tree

4 files changed

+104
-5
lines changed

4 files changed

+104
-5
lines changed

iam-token-manager/v1.ts

+24
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@
1717
import extend = require('extend');
1818
import { sendRequest } from '../lib/requestwrapper';
1919

20+
/**
21+
* Check for only one of two elements being defined.
22+
* Returns true if a is defined and b is undefined,
23+
* or vice versa. Returns false if both are defined
24+
* or both are undefined.
25+
*
26+
* @param {any} a - The first object
27+
* @param {any} b - The second object
28+
* @returns {boolean}
29+
*/
30+
function onlyOne(a: any, b: any): boolean {
31+
return Boolean((a && !b) || (b && !a));
32+
}
33+
34+
const CLIENT_ID_SECRET_WARNING = 'Warning: Client ID and Secret must BOTH be given, or the defaults will be used.';
35+
2036
export type Options = {
2137
iamApikey?: string;
2238
iamAccessToken?: string;
@@ -72,6 +88,10 @@ export class IamTokenManagerV1 {
7288
if (options.iamSecret) {
7389
this.iamSecret = options.iamSecret;
7490
}
91+
if (onlyOne(options.iamClientId, options.iamSecret)) {
92+
// tslint:disable-next-line
93+
console.log(CLIENT_ID_SECRET_WARNING);
94+
}
7595
}
7696

7797
/**
@@ -120,6 +140,10 @@ export class IamTokenManagerV1 {
120140
public setIamAuthorizationInfo(iamClientId: string, iamSecret: string): void {
121141
this.iamClientId = iamClientId;
122142
this.iamSecret = iamSecret;
143+
if (onlyOne(iamClientId, iamSecret)) {
144+
// tslint:disable-next-line
145+
console.log(CLIENT_ID_SECRET_WARNING);
146+
}
123147
}
124148

125149
/**

lib/base_service.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export interface UserOptions {
4040
iam_access_token?: string;
4141
iam_apikey?: string;
4242
iam_url?: string;
43+
iam_client_id?: string;
44+
iam_secret?: string;
4345
disable_ssl_verification?: boolean;
4446
}
4547

@@ -121,6 +123,11 @@ export class BaseService {
121123
/**
122124
* Internal base class that other services inherit from
123125
* @param {UserOptions} options
126+
* @param {string} [options.iam_apikey] - api key used to retrieve an iam access token
127+
* @param {string} [options.iam_access_token] - iam access token provided and managed by user
128+
* @param {string} [options.iam_url] - url for iam service api, needed for services in staging
129+
* @param {string} [options.iam_client_id] - client id (username) for request to iam service
130+
* @param {string} [options.iam_secret] - secret (password) for request to iam service
124131
* @param {string} [options.username] - required unless use_unauthenticated is set
125132
* @param {string} [options.password] - required unless use_unauthenticated is set
126133
* @param {boolean} [options.use_unauthenticated] - skip credential requirement
@@ -158,12 +165,16 @@ export class BaseService {
158165
this.tokenManager = new IamTokenManagerV1({
159166
iamApikey: _options.iam_apikey,
160167
iamAccessToken: _options.iam_access_token,
161-
iamUrl: _options.iam_url
168+
iamUrl: _options.iam_url,
169+
iamClientId: _options.iam_client_id,
170+
iamSecret: _options.iam_secret
162171
});
163172
} else if (usesBasicForIam(_options)) {
164173
this.tokenManager = new IamTokenManagerV1({
165174
iamApikey: _options.password,
166-
iamUrl: _options.iam_url
175+
iamUrl: _options.iam_url,
176+
iamClientId: _options.iam_client_id,
177+
iamSecret: _options.iam_secret
167178
});
168179
} else {
169180
this.tokenManager = null;

test/unit/baseService.test.js

+35
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,41 @@ describe('BaseService', function() {
285285
});
286286
});
287287

288+
it('should pass all credentials to token manager when given iam creds', function() {
289+
const instance = new TestService({
290+
iam_apikey: 'key1234',
291+
iam_access_token: 'real-token-84',
292+
iam_url: 'iam.com/api',
293+
iam_client_id: 'abc',
294+
iam_secret: 'abc',
295+
});
296+
297+
expect(instance.tokenManager).toBeDefined();
298+
expect(instance.tokenManager).not.toBeNull();
299+
expect(instance.tokenManager.iamApikey).toBeDefined();
300+
expect(instance.tokenManager.userAccessToken).toBeDefined();
301+
expect(instance.tokenManager.iamUrl).toBeDefined();
302+
expect(instance.tokenManager.iamClientId).toBeDefined();
303+
expect(instance.tokenManager.iamSecret).toBeDefined();
304+
});
305+
306+
it('should pass all credentials to token manager when given iam with basic', function() {
307+
const instance = new TestService({
308+
username: 'apikey',
309+
password: 'key1234',
310+
iam_url: 'iam.com/api',
311+
iam_client_id: 'abc',
312+
iam_secret: 'abc',
313+
});
314+
315+
expect(instance.tokenManager).toBeDefined();
316+
expect(instance.tokenManager).not.toBeNull();
317+
expect(instance.tokenManager.iamApikey).toBeDefined();
318+
expect(instance.tokenManager.iamUrl).toBeDefined();
319+
expect(instance.tokenManager.iamClientId).toBeDefined();
320+
expect(instance.tokenManager.iamSecret).toBeDefined();
321+
});
322+
288323
it('should not fail if setAccessToken is called and token manager is null', function() {
289324
const instance = new TestService({ username: 'user', password: 'pass' });
290325
expect(instance.tokenManager).toBeNull();

test/unit/iamTokenManager.test.js

+32-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
/* eslint-disable no-alert, no-console */
12
'use strict';
23

34
const requestWrapper = require('../../lib/requestwrapper');
45
requestWrapper.sendRequest = jest.fn();
56

67
const IamTokenManagerV1 = require('../../iam-token-manager/v1').IamTokenManagerV1;
78

9+
const CLIENT_ID_SECRET_WARNING =
10+
'Warning: Client ID and Secret must BOTH be given, or the defaults will be used.';
11+
812
describe('iam_token_manager_v1', function() {
913
beforeEach(() => {
1014
requestWrapper.sendRequest.mockReset();
@@ -235,11 +239,18 @@ describe('iam_token_manager_v1', function() {
235239
});
236240

237241
it('should use the default Authorization header - clientid only via ctor', function(done) {
242+
jest.spyOn(console, 'log').mockImplementation(() => {});
243+
238244
const instance = new IamTokenManagerV1({
239245
iamApikey: 'abcd-1234',
240246
iamClientId: 'foo',
241247
});
242248

249+
// verify warning was triggered
250+
expect(console.log).toHaveBeenCalled();
251+
expect(console.log.mock.calls[0][0]).toBe(CLIENT_ID_SECRET_WARNING);
252+
console.log.mockRestore();
253+
243254
requestWrapper.sendRequest.mockImplementation((parameters, _callback) => {
244255
_callback();
245256
});
@@ -253,11 +264,17 @@ describe('iam_token_manager_v1', function() {
253264
});
254265

255266
it('should use the default Authorization header, secret only via ctor', function(done) {
267+
jest.spyOn(console, 'log').mockImplementation(() => {});
256268
const instance = new IamTokenManagerV1({
257269
iamApikey: 'abcd-1234',
258270
iamSecret: 'bar',
259271
});
260272

273+
// verify warning was triggered
274+
expect(console.log).toHaveBeenCalled();
275+
expect(console.log.mock.calls[0][0]).toBe(CLIENT_ID_SECRET_WARNING);
276+
console.log.mockRestore();
277+
261278
requestWrapper.sendRequest.mockImplementation((parameters, _callback) => {
262279
_callback();
263280
});
@@ -294,8 +311,15 @@ describe('iam_token_manager_v1', function() {
294311
iamApikey: 'abcd-1234',
295312
});
296313

314+
jest.spyOn(console, 'log').mockImplementation(() => {});
315+
297316
instance.setIamAuthorizationInfo('foo', null);
298317

318+
// verify warning was triggered
319+
expect(console.log).toHaveBeenCalled();
320+
expect(console.log.mock.calls[0][0]).toBe(CLIENT_ID_SECRET_WARNING);
321+
console.log.mockRestore();
322+
299323
requestWrapper.sendRequest.mockImplementation((parameters, _callback) => {
300324
_callback();
301325
});
@@ -308,14 +332,20 @@ describe('iam_token_manager_v1', function() {
308332
});
309333
});
310334

311-
it('should use the default Authorization header, secret only via ctor', function(done) {
335+
it('should use the default Authorization header, secret only via setter', function(done) {
312336
const instance = new IamTokenManagerV1({
313337
iamApikey: 'abcd-1234',
314-
iamSecret: 'bar',
315338
});
316339

340+
jest.spyOn(console, 'log').mockImplementation(() => {});
341+
317342
instance.setIamAuthorizationInfo(null, 'bar');
318343

344+
// verify warning was triggered
345+
expect(console.log).toHaveBeenCalled();
346+
expect(console.log.mock.calls[0][0]).toBe(CLIENT_ID_SECRET_WARNING);
347+
console.log.mockRestore();
348+
319349
requestWrapper.sendRequest.mockImplementation((parameters, _callback) => {
320350
_callback();
321351
});
@@ -331,7 +361,6 @@ describe('iam_token_manager_v1', function() {
331361
it('should use the default Authorization header, nulls passed to setter', function(done) {
332362
const instance = new IamTokenManagerV1({
333363
iamApikey: 'abcd-1234',
334-
iamSecret: 'bar',
335364
});
336365

337366
instance.setIamAuthorizationInfo(null, null);

0 commit comments

Comments
 (0)