From 6d357d3f4d2bb93c4865806e66c37d3ec5164349 Mon Sep 17 00:00:00 2001
From: "Steven R. Loomis" Example credentials such as for documentation. Example IAM credentials such as for documentation. Example credentials string Example IAM credentials string Current version Construct a g11n-pipeline client.
-params.credentials is required unless params.appEnv is supplied.var credentials = require('cfEnv')
var credentials = require('cfEnv')
Client
Promise.<Object>
Read a file, return promise to parsed obj
@@ -1352,6 +1359,18 @@ Example credentials such as for documentation. | --- | | exampleCredentials | + + +## exampleIamCredentials +Example IAM credentials such as for documentation. + +**Kind**: global variable +**Properties** + +| Name | +| --- | +| exampleUamCredentials | + ## exampleCredentialsString @@ -1364,6 +1383,18 @@ Example credentials string | --- | | exampleCredentialsString | + + +## exampleIamCredentialsString +Example IAM credentials string + +**Kind**: global variable +**Properties** + +| Name | +| --- | +| exampleIamCredentialsString | + ## version @@ -1417,6 +1448,7 @@ Possible translation domains. These provide hints as to the type of translation ## getClient(params) ⇒ [Client
](#Client)
Construct a g11n-pipeline client.
params.credentials is required unless params.appEnv is supplied.
+Required either: (userId & password) or (apikey & iam_endpoint)
**Kind**: global function
@@ -1426,8 +1458,10 @@ params.credentials is required unless params.appEnv is supplied.
| params.appEnv | Object
| pass the result of cfEnv.getAppEnv(). Ignored if params.credentials is supplied. |
| params.credentials | Object.<string, string>
| Bound credentials as from the CF service broker (overrides appEnv) |
| params.credentials.url | string
| service URL. (should end in '/translate') |
-| params.credentials.userId | string
| service API key. |
-| params.credentials.password | string
| service API key. |
+| params.credentials.userId | string
| GP auth userid. |
+| params.credentials.password | string
| GP auth password. |
+| params.credentials.apikey | string
| IAM apikey |
+| params.credentials.iam_endpoint | string
| IAM endpoint |
| params.credentials.instanceId | string
| instance ID |
diff --git a/CLI.md b/CLI.md
index 8277dc8..749f685 100644
--- a/CLI.md
+++ b/CLI.md
@@ -35,17 +35,26 @@ Options have a short or a long form. Therefore, the following are all equivalent
Credentials
--
+See also the [`getClient()` API docs](./API.md#getClient)
Credentials may be passed in one of the following ways:
1. Via the `-j/--jsonCreds` option, which takes a path to a JSON file with credentials
-2. Via the four individual options `--serviceUrl`, `--instanceId`, `--user`, and `--password`
+2a. For GP Auth: the four individual options `--serviceUrl`, `--instanceId`, `--user`, and `--password`
+2b. for IAM auth via `--iam_endpoint` and `--apikey`
3. By the following environment variables:
* __GP_URL__: Service URL (e.g. https://gp-rest.ng.bluemix.net/translate/rest)
* __GP_INSTANCE_ID__: Service instance ID (e.g. d3f537cd617f34c86ac6b270f3065e73)
- * __GP_USER_ID__: User ID (e.g. e92a1282a0e4f97bec93aa9f56fdb838)
- * __GP_PASSWORD__: User password (e.g. zg5SlD+ftXYRIZDblLgEA/ILkkCNqE1y)
+ - _if using GP Authentication_:
+
+ * __GP_USER_ID__: User ID (e.g. e92a1282a0e4f97bec93aa9f56fdb838)
+ * __GP_PASSWORD__: User password (e.g. zg5SlD+ftXYRIZDblLgEA/ILkkCNqE1y)
+
+ - _if using IAM Authentication_:
+
+ * __GP_IAM_API_KEY__: IAM API Key
+ * __GP_IAM_ENDPOINT__: IAM endpoint (e.g. https://iam.cloud.ibm.com)
Common Options
--
@@ -54,7 +63,7 @@ Common Options
See [Credentials](#Credentials), above.
- This option specifies a credentials file containing the [GP credentials](https://github.com/IBM-Cloud/gp-common/blob/master/README.md#4-credentials). This is a JSON file with either of the following formats:
+ This option specifies a credentials file containing the [GP credentials](https://github.com/IBM-Cloud/gp-common/blob/master/README.md#4-credentials). This is a JSON file with any of the following formats:
```json
{"url":"≈",
@@ -70,11 +79,31 @@ Common Options
"userId":"≈",
"password":"≈"}}
```
+
+ ```json
+ {"url":"≈",
+ "instanceId":"≈",
+ "iam_endpoint":"≈",
+ "apikey":"≈"}
+ ```
+
+ ```json
+ {"credentials":
+ {"url":"≈",
+ "instanceId":"≈",
+ "iam_endpoint":"≈",
+ "apikey":"≈"}}
+ ```
- `--serviceUrl`, `--instanceId`, `--user`, `--password`
See [Credentials](#Credentials), above.
- These options specify the four credential parameters individually.
+ These options specify the four credential parameters individually for GP Auth.
+
+- `--iam_endpoint`, `--apikey`
+
+ See [Credentials](#Credentials), above.
+ These options specify the two credential parameters individually for IAM Auth.
- `-F json` | `--outputFormat=json`
diff --git a/lib/client.js b/lib/client.js
index 98ab2c9..fcc553b 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -27,6 +27,7 @@
var utils = require('./utils.js');
var SwaggerClient = require('swagger-client');
var GpHmac = require('./gp-hmac');
+var GpIAM = require('./gp-iam');
var cfEnvUtil = require('./cfenv-credsbylabel');
const TranslationRequest = require('./tr.js');
const DocumentTranslationRequest = require('./doctr.js');
@@ -54,11 +55,22 @@ class Client {
}
this._options = options;
if (!this._options.credentials) {
- throw new Error("g11n-pipeline: missing 'credentials' " + Object.keys(Consts.exampleCredentials));
+ throw new Error("g11n-pipeline: missing 'credentials'"); // don't give specific contents
+ // could be CF or IAM.
}
- var missingField = utils.isMissingField(this._options.credentials, Object.keys(Consts.exampleCredentials));
- if (missingField.length !== 0) {
- throw new Error("g11n-pipeline: missing credentials fields: \"" + missingField.join(' ') + "\" - expected: " + Consts.exampleCredentialsString);
+ if(this._options.credentials.apikey) {
+ const missingField = utils.isMissingField(this._options.credentials, Object.keys(Consts.exampleIamCredentials));
+ if (missingField.length !== 0) {
+ throw new Error("g11n-pipeline: missing IAM credentials fields: \"" + missingField.join(' ') +
+ "\" - expected: " + Consts.exampleIamCredentialsString);
+ }
+ } else {
+ // expect 'GP auth' fields
+ const missingField = utils.isMissingField(this._options.credentials, Object.keys(Consts.exampleCredentials));
+ if (missingField.length !== 0) {
+ throw new Error("g11n-pipeline: missing GP credentials fields: \"" +
+ missingField.join(' ') + "\" - expected: " + Consts.exampleCredentialsString + ' but got ' + JSON.stringify(this._options.credentials));
+ }
}
// instanceId optional
@@ -106,16 +118,24 @@ class Client {
const schemaUrl = this._schemaUrl = this._options.credentials.url + '/swagger.json';
// if (debugREST) /*istanbul ignore next*/ console.log('.. fetching ' + schemaUrl);
- const gphmac = new GpHmac("gp-hmac", this._options.credentials.userId, this._options.credentials.password);
- if(this._options.basicAuth) {
- // ignore basicAuth.
- // throw Error('basicAuth is not supported'); // TODO: support this- maybe?
+ if (this._options.credentials.apikey) {
+ // IAM
+ const gpiam = new GpIAM(this._options.credentials);
+ const clientPromise = new SwaggerClient({
+ url: schemaUrl,
+ requestInterceptor: (req) => gpiam.apply(req)
+ });
+ return clientPromise;
+ } else {
+ // assume GP credentials
+ const gphmac = new GpHmac("gp-hmac", this._options.credentials.userId, this._options.credentials.password);
+ const clientPromise = new SwaggerClient({
+ url: schemaUrl,
+ requestInterceptor: (req) => gphmac.apply(req) // TODO: change if we are using Basic
+ });
+ return clientPromise;
}
- const clientPromise = new SwaggerClient({
- url: schemaUrl,
- requestInterceptor: (req) => gphmac.apply(req) // TODO: change if we are using Basic
- });
- return clientPromise;
+ // Not supported: this._options.basicAuth
}
diff --git a/lib/consts.js b/lib/consts.js
index d6977c4..a23c548 100644
--- a/lib/consts.js
+++ b/lib/consts.js
@@ -35,12 +35,30 @@ exports.exampleCredentials = {
password: "secretpassword",
instanceId: "your Instance ID"
};
+
+/**
+ * Example IAM credentials such as for documentation.
+ * @property exampleUamCredentials
+ */
+exports.exampleIamCredentials = {
+ url: "Globalization Pipeline URL",
+ apikey: "your IAM apikey", // if we see apikey, we assume this is IAM
+ iam_endpoint: "your IAM endpoint URL",
+ instanceId: "your Instance ID"
+};
+
/**
* Example credentials string
* @property exampleCredentialsString
*/
exports.exampleCredentialsString = "credentials: " + JSON.stringify(exports.exampleCredentials);
+/**
+ * Example IAM credentials string
+ * @property exampleIamCredentialsString
+ */
+exports.exampleIamCredentialsString = "credentials: " + JSON.stringify(exports.exampleIamCredentials);
+
/**
* Current version
*/
diff --git a/lib/gp-iam.js b/lib/gp-iam.js
new file mode 100644
index 0000000..02a8bd9
--- /dev/null
+++ b/lib/gp-iam.js
@@ -0,0 +1,52 @@
+/*
+ * Copyright IBM Corp. 2015-2019
+ *
+ * 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.
+ */
+
+/* eslint no-console: "off" */
+
+/**
+ * Manage use of IAM API Keys and Tokens
+ * Docs: https://cloud.ibm.com/docs/iam?topic=iam-iamtoken_from_apikey&locale=en#iamtoken_from_apikey
+ *
+ * @author Steven R. Loomis
+ * @ignore
+ */
+
+const GpIAM = function GpIAM(credentials) {
+ this.credentials = credentials;
+ if(!this.credentials || !this.credentials.apikey || !this.credentials.iam_endpoint) {
+ throw new Error('GpIAM: params need to be "apikey, iam_endpoint"');
+ }
+};
+
+GpIAM.prototype.API_KEY = "API-KEY"; // GP SPECIFIC header
+
+GpIAM.prototype.VERBOSE = process.env.GP_VERBOSE || false;
+GpIAM.prototype.GP_USE_APIKEY = process.env.GP_USE_APIKEY || true; // if false: use token manager
+
+/**
+ * Generate HTTP Authorization header.
+ */
+GpIAM.prototype.apply = function(obj) {
+ if(this.VERBOSE) console.dir(obj, {color: true, depth: null});
+ if(obj.url.indexOf("/swagger.json") !== -1) return obj; // skip for swagger.json
+
+ const authHeader = this.API_KEY + ' ' + this.credentials.apikey;
+ if(this.VERBOSE) console.log('hmacHeader = ' + authHeader);
+ obj.headers.Authorization = authHeader;
+ return obj;
+};
+
+module.exports = GpIAM;
diff --git a/lib/gpcli.js b/lib/gpcli.js
index cac2f8f..9e3f2bc 100644
--- a/lib/gpcli.js
+++ b/lib/gpcli.js
@@ -44,6 +44,8 @@ class Cli {
instanceId: 'i',
user: 'u',
password: 'p',
+ apikey: 'a',
+ iam_endpoint: 'A',
jsonCreds: 'j',
bundle: 'b',
outputFormat: 'F',
@@ -138,12 +140,14 @@ class Cli {
if(credentials.credentials) return credentials.credentials;
return credentials;
} else {
- const {GP_URL, GP_INSTANCE_ID, GP_USER_ID, GP_PASSWORD} = process.env;
+ const {GP_URL, GP_INSTANCE_ID, GP_USER_ID, GP_PASSWORD, GP_IAM_API_KEY, GP_IAM_ENDPOINT} = process.env;
const credentials = {
url: this.argv.serviceUrl || GP_URL,
userId: this.argv.user || GP_USER_ID,
password: this.argv.password || GP_PASSWORD,
- instanceId: this.argv.instanceId || GP_INSTANCE_ID
+ instanceId: this.argv.instanceId || GP_INSTANCE_ID,
+ apikey: this.argv.apikey || GP_IAM_API_KEY,
+ iam_endpoint: this.argv.iam_endpoint || GP_IAM_ENDPOINT
};
// TODO: validate
return credentials;
diff --git a/lib/main.js b/lib/main.js
index 2ad330f..47f2c7d 100644
--- a/lib/main.js
+++ b/lib/main.js
@@ -25,12 +25,15 @@ const utils = require('./utils.js');
/**
* Construct a g11n-pipeline client.
* params.credentials is required unless params.appEnv is supplied.
+ * Required either: (userId & password) or (apikey & iam_endpoint)
* @param {Object} params - configuration params
* @param {Object} params.appEnv - pass the result of cfEnv.getAppEnv(). Ignored if params.credentials is supplied.
* @param {Object.