Skip to content

Commit

Permalink
feat: implement new authenticators to handle sdk authentication (#37)
Browse files Browse the repository at this point in the history
* feat: implement new authenticators to handle sdk authentication
* refactor: remove support for user-managed access tokens in the token managers
* refactor(iam-token-manager): do not use a default auth header if client id/secret are not set
* docs: update the migration document to reflect these changes
* refactor: rename token managers
* refactor(iam-token-manager): rename method `setAuthorizationInfo` to `setClientIdAndSecret`

BREAKING CHANGE: The old style of passing credentials to the base service will no longer work. An Authenticator instance MUST be passed in to the base service constructor.

BREAKING CHANGE: token managers no longer support user access tokens. use BearerTokenAuthenticator instead

BREAKING CHANGE: The class names of the token managers have changed.
* `Icp4dTokenManagerV1` renamed to `Cp4dTokenManager`
* `IamTokenManagerV1` renamed to `IamTokenManager`
* `JwtTokenManagerV1` renamed to `JwtTokenManager`

BREAKING CHANGE: The public method `setAuthorizationInfo` is renamed to `setClientIdAndSecret`
  • Loading branch information
dpopp07 authored and Mike Kistler committed Sep 17, 2019
1 parent e122c35 commit 68353b7
Show file tree
Hide file tree
Showing 46 changed files with 2,128 additions and 1,374 deletions.
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ node_modules/
**/*v*.js
!test/**/*.js
lib/*.js
auth/*.js
auth/**/*.js
index.js
scripts/typedoc/
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ doc/
.env
.eslintcache
lib/*.js
auth/*.js
auth/**/*.js
iam-token-manager/*.js
index.js
.nyc_output
Expand Down
31 changes: 31 additions & 0 deletions auth/authenticators/authenticator-interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { OutgoingHttpHeaders } from 'http';

// This could just be the type for the `baseOptions` field of the Base Service
// but to avoid a circular dependency or a refactor, this will do for now
export interface AuthenticateOptions {
headers?: OutgoingHttpHeaders;
[propName: string]: any;
}

// callback can send one arg, error or null
export type AuthenticateCallback = (result: null | Error) => void;

export interface AuthenticatorInterface {
authenticate(options: AuthenticateOptions, callback: AuthenticateCallback): void
}
55 changes: 55 additions & 0 deletions auth/authenticators/authenticator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { OutgoingHttpHeaders } from 'http';
import { getMissingParams } from '../../lib/helper';
import { checkCredentials } from '../utils/helpers'; // just using '../utils' here leads to a test failure. need to open an issue against typescript
import { AuthenticateCallback, AuthenticateOptions, AuthenticatorInterface } from './authenticator-interface';

export class Authenticator implements AuthenticatorInterface {
/**
* Base Authenticator Class
*
* Provides the Base Authenticator class for others to extend.
*/
constructor() {
if (!(this instanceof Authenticator)) {
throw new Error(
'the "new" keyword is required to create authenticator instances'
);
}
}

public authenticate(options: AuthenticateOptions, callback: AuthenticateCallback): void {
throw new Error('Should be implemented by subclass!');
}

protected validate(options: any, requiredOptions: string[]): void {
// check for required params
const missingParamsError = getMissingParams(options, requiredOptions);
if (missingParamsError) {
throw missingParamsError;
}

// check certain credentials for common user errors: username, password, and apikey
// note: will only apply to certain authenticators
const credsToCheck = ['username', 'password', 'apikey']
const credentialProblems = checkCredentials(options, credsToCheck);
if (credentialProblems) {
throw new Error(credentialProblems);
}
}
}
58 changes: 58 additions & 0 deletions auth/authenticators/basic-authenticator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import extend = require('extend');
import { computeBasicAuthHeader } from '../utils';
import { Authenticator } from './authenticator';
import { AuthenticateCallback, AuthenticateOptions, AuthenticatorInterface } from './authenticator-interface';

export type Options = {
username?: string;
password?: string;
}

export class BasicAuthenticator extends Authenticator implements AuthenticatorInterface {
protected requiredOptions = ['username', 'password'];
private username: string;
private password: string;

/**
* Basic Authenticator Class
*
* Handles the Basic Authentication pattern.
*
* @param {Object} options
* @param {String} options.username
* @param {String} options.password
* @constructor
*/
constructor(options: Options) {
super();

this.validate(options, this.requiredOptions);

this.username = options.username;
this.password = options.password;
}

public authenticate(options: AuthenticateOptions, callback: AuthenticateCallback): void {
const authHeaderString = computeBasicAuthHeader(this.username, this.password);
const authHeader = { Authorization: authHeaderString }

options.headers = extend(true, {}, options.headers, authHeader);
callback(null);
}
}
55 changes: 55 additions & 0 deletions auth/authenticators/bearer-token-authenticator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import extend = require('extend');
import { Authenticator } from './authenticator';
import { AuthenticateCallback, AuthenticateOptions, AuthenticatorInterface } from './authenticator-interface';

export type Options = {
bearerToken: string;
}

export class BearerTokenAuthenticator extends Authenticator implements AuthenticatorInterface {
protected requiredOptions = ['bearerToken'];
private bearerToken: string;

/**
* Bearer Token Authenticator Class
*
* Handles the Bearer Token pattern.
*
* @param {Object} options
* @param {String} options.bearerToken - bearer token to pass in header
* @constructor
*/
constructor(options: Options) {
super();

this.validate(options, this.requiredOptions);

this.bearerToken = options.bearerToken;
}

public setBearerToken(bearerToken: string): void {
this.bearerToken = bearerToken;
}

public authenticate(options: AuthenticateOptions, callback: AuthenticateCallback): void {
const authHeader = { Authorization: `Bearer ${this.bearerToken}` };
options.headers = extend(true, {}, options.headers, authHeader);
callback(null);
}
}
53 changes: 53 additions & 0 deletions auth/authenticators/cloud-pak-for-data-authenticator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { OutgoingHttpHeaders } from 'http';
import { Cp4dTokenManager } from '../token-managers';
import { BaseOptions, TokenRequestBasedAuthenticator } from './token-request-based-authenticator';

export interface Options extends BaseOptions {
username: string;
password: string;
url: string;
}

export class CloudPakForDataAuthenticator extends TokenRequestBasedAuthenticator {
protected requiredOptions = ['username', 'password', 'url'];
private username: string;
private password: string;

/**
* Cloud Pak for Data Authenticator Class
*
* Handles the CP4D authentication pattern:
* A username and password are provided and used to retrieve a bearer token.
*
* @param {Object} options
* @constructor
*/
constructor(options: Options) {
super(options);

this.validate(options, this.requiredOptions);

this.username = options.username;
this.password = options.password;

// the param names are shared between the authenticator and the token manager
// so we can just pass along the options object
this.tokenManager = new Cp4dTokenManager(options);
}
}
69 changes: 69 additions & 0 deletions auth/authenticators/iam-authenticator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { OutgoingHttpHeaders } from 'http';
import { IamTokenManager } from '../token-managers';
import { BaseOptions, TokenRequestBasedAuthenticator } from './token-request-based-authenticator';

export interface Options extends BaseOptions {
apikey: string;
clientId?: string;
clientSecret?: string;
}

export class IamAuthenticator extends TokenRequestBasedAuthenticator {
protected requiredOptions = ['apikey'];
private apikey: string;
private clientId: string;
private clientSecret: string;

/**
* IAM Authenticator Class
*
* Handles the IAM authentication pattern.
*
* @param {Object} options
* @constructor
*/
constructor(options: Options) {
super(options);

this.validate(options, this.requiredOptions);

this.apikey = options.apikey;
this.clientId = options.clientId;
this.clientSecret = options.clientSecret;

// the param names are shared between the authenticator and the token manager
// so we can just pass along the options object
this.tokenManager = new IamTokenManager(options);
}

/**
* Setter for the Client ID and the Client Secret. Both should be provided.
*
* @param {string} clientId
* @param {string} clientSecret
* @returns {void}
*/
public setClientIdAndSecret(clientId: string, clientSecret: string): void {
this.clientId = clientId;
this.clientSecret = clientSecret;

// update properties in token manager
this.tokenManager.setClientIdAndSecret(clientId, clientSecret);
}
}
24 changes: 24 additions & 0 deletions auth/authenticators/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

export { AuthenticatorInterface } from './authenticator-interface';
export { Authenticator } from './authenticator';
export { BasicAuthenticator } from './basic-authenticator';
export { BearerTokenAuthenticator } from './bearer-token-authenticator';
export { CloudPakForDataAuthenticator } from './cloud-pak-for-data-authenticator';
export { IamAuthenticator } from './iam-authenticator';
export { NoauthAuthenticator } from './no-auth-authenticator';
export { TokenRequestBasedAuthenticator } from './token-request-based-authenticator';
Loading

0 comments on commit 68353b7

Please sign in to comment.