You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by ja...@apache.org on 2018/08/17 08:28:07 UTC
[incubator-openwhisk-client-js] branch master updated: add
authHandler option to deal with authorization header (#132)
This is an automated email from the ASF dual-hosted git repository.
jamesthomas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-client-js.git
The following commit(s) were added to refs/heads/master by this push:
new 5e2b541 add authHandler option to deal with authorization header (#132)
5e2b541 is described below
commit 5e2b541b413a9df2a3d9a01596ee1bf2129e2634
Author: Carlos Santana <cs...@apache.org>
AuthorDate: Fri Aug 17 04:28:05 2018 -0400
add authHandler option to deal with authorization header (#132)
* add authHandler option
Closes #131
---
README.md | 18 ++++++++++++++++++
lib/client.js | 42 ++++++++++++++++++++++++------------------
test/unit/client.test.js | 28 +++++++++++++++++++---------
3 files changed, 61 insertions(+), 27 deletions(-)
diff --git a/README.md b/README.md
index 74df04e..dd4a346 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,24 @@ var ow = openwhisk(options);
ow.actions.invoke('sample').then(result => console.log(result))
```
+#### using 3rd party authentication handler
+You can specify an authentication handler in `options.auth_handler` this is an object that provides a function `getAuthHeader` that returns a Promise or String to be used in the `Authorization` http header for every http request.
+```javascript
+const authHandler = {
+ getAuthHeader: ()=>{
+ return Promise.resolve('Basic user:password')
+ }
+}
+var openwhisk = require('openwhisk');
+var options = {
+ apihost: 'openwhisk.ng.bluemix.net',
+ auth_handler: authHandler
+}
+var ow = openwhisk(options)
+ow.actions.invoke('sample').then(result => console.log(result))
+```
+
+
### constructor options
_Client constructor supports the following mandatory parameters:_
diff --git a/lib/client.js b/lib/client.js
index 48723e3..7dd0982 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -66,6 +66,7 @@ class Client {
* @param {boolean} [options.ignore_certs]
* @param {string} [options.apigw_token]
* @param {string} [options.apigw_space_guid]
+ * @param {Function} [options.auth_handler]
*/
constructor (options) {
this.options = this.parseOptions(options || {})
@@ -91,13 +92,13 @@ class Client {
apigwSpaceGuid = apiKey.split(':')[0]
}
- if (!apiKey) {
- throw new Error(`${messages.INVALID_OPTIONS_ERROR} Missing api_key parameter.`)
+ if (!apiKey && !options.auth_handler) {
+ throw new Error(`${messages.INVALID_OPTIONS_ERROR} Missing api_key parameter or token plugin.`)
} else if (!api) {
throw new Error(`${messages.INVALID_OPTIONS_ERROR} Missing either api or apihost parameters.`)
}
- return {apiKey: apiKey, api, ignoreCerts: ignoreCerts, namespace: options.namespace, apigwToken: apigwToken, apigwSpaceGuid: apigwSpaceGuid}
+ return {apiKey: apiKey, api, ignoreCerts: ignoreCerts, namespace: options.namespace, apigwToken: apigwToken, apigwSpaceGuid: apigwSpaceGuid, authHandler: options.auth_handler}
}
urlFromApihost (apihost) {
@@ -113,21 +114,23 @@ class Client {
}
request (method, path, options) {
- const req = this.params(method, path, options)
- return rp(req).catch(err => this.handleErrors(err))
+ const params = this.params(method, path, options)
+ return params.then(req => rp(req)).catch(err => this.handleErrors(err))
}
params (method, path, options) {
- return Object.assign({
- json: true,
- method: method,
- url: this.pathUrl(path),
- rejectUnauthorized: !this.options.ignoreCerts,
- headers: {
- 'User-Agent': (options && options['User-Agent']) || 'openwhisk-client-js',
- Authorization: this.authHeader()
- }
- }, options)
+ return this.authHeader().then(header => {
+ return Object.assign({
+ json: true,
+ method: method,
+ url: this.pathUrl(path),
+ rejectUnauthorized: !this.options.ignoreCerts,
+ headers: {
+ 'User-Agent': (options && options['User-Agent']) || 'openwhisk-client-js',
+ Authorization: header
+ }
+ }, options)
+ })
}
pathUrl (urlPath) {
@@ -143,10 +146,13 @@ class Client {
}
authHeader () {
- const apiKeyBase64 = Buffer.from(this.options.apiKey).toString('base64')
- return `Basic ${apiKeyBase64}`
+ if (this.options.authHandler) {
+ return this.options.authHandler.getAuthHeader()
+ } else {
+ const apiKeyBase64 = Buffer.from(this.options.apiKey).toString('base64')
+ return Promise.resolve(`Basic ${apiKeyBase64}`)
+ }
}
-
handleErrors (reason) {
let message = `Unknown Error From API: ${reason.message}`
if (reason.hasOwnProperty('statusCode')) {
diff --git a/test/unit/client.test.js b/test/unit/client.test.js
index dc97643..6d8fad3 100644
--- a/test/unit/client.test.js
+++ b/test/unit/client.test.js
@@ -108,12 +108,12 @@ test('should handle multiple api parameter formats', t => {
t.is(client.urlFromApihost('http://my_host:80'), 'http://my_host:80/api/v1/')
})
-test('should return default request parameters without options', t => {
+test('should return default request parameters without options', async t => {
const client = new Client({api_key: 'username:password', apihost: 'blah'})
const METHOD = 'get'
const PATH = 'some/path/to/resource'
- const params = client.params(METHOD, PATH)
+ const params = await client.params(METHOD, PATH)
t.is(params.url, 'https://blah/api/v1/some/path/to/resource')
t.is(params.method, METHOD)
t.true(params.json)
@@ -121,13 +121,13 @@ test('should return default request parameters without options', t => {
t.true(params.headers.hasOwnProperty('Authorization'))
})
-test('should return request parameters with merged options', t => {
+test('should return request parameters with merged options', async t => {
const client = new Client({api_key: 'username:password', apihost: 'blah'})
const METHOD = 'get'
const PATH = 'some/path/to/resource'
const OPTIONS = {b: {bar: 'foo'}, a: {foo: 'bar'}}
- const params = client.params(METHOD, PATH, OPTIONS)
+ const params = await client.params(METHOD, PATH, OPTIONS)
t.is(params.url, 'https://blah/api/v1/some/path/to/resource')
t.is(params.method, METHOD)
t.true(params.json)
@@ -137,20 +137,30 @@ test('should return request parameters with merged options', t => {
t.deepEqual(params.b, {bar: 'foo'})
})
-test('should return request parameters with explicit api option', t => {
+test('should return request parameters with explicit api option', async t => {
const client = new Client({api_key: 'username:password', api: 'https://api.com/api/v1'})
const METHOD = 'get'
const PATH = 'some/path/to/resource'
- t.is(client.params(METHOD, PATH).url, 'https://api.com/api/v1/some/path/to/resource')
+ t.is((await client.params(METHOD, PATH)).url, 'https://api.com/api/v1/some/path/to/resource')
client.options.api += '/'
- t.is(client.params(METHOD, PATH).url, 'https://api.com/api/v1/some/path/to/resource')
+ t.is((await client.params(METHOD, PATH)).url, 'https://api.com/api/v1/some/path/to/resource')
})
-test('should generate auth header from API key', t => {
+test('should generate auth header from API key', async t => {
const apiKey = 'some sample api key'
const client = new Client({api: true, api_key: apiKey})
- t.is(client.authHeader(), `Basic ${Buffer.from(apiKey).toString('base64')}`)
+ t.is(await client.authHeader(), `Basic ${Buffer.from(apiKey).toString('base64')}`)
+})
+
+test('should generate auth header from 3rd party authHandler plugin', async t => {
+ const authHandler = {
+ getAuthHeader: () => {
+ return Promise.resolve('Basic user:password')
+ }
+ }
+ const client = new Client({api: true, auth_handler: authHandler})
+ t.is(await client.authHeader(), `Basic user:password`)
})
test('should return path and status code in error message', t => {