1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | 'use strict';
|
15 |
|
16 | const debug = require('debug')('cloudant:plugins:iamauth');
|
17 | const request = require('request');
|
18 | const u = require('url');
|
19 |
|
20 | const BasePlugin = require('./base.js');
|
21 | const IAMTokenManager = require('../lib/tokens/IamTokenManager');
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | class IAMPlugin extends BasePlugin {
|
27 | constructor(client, cfg) {
|
28 | if (typeof cfg.iamApiKey === 'undefined') {
|
29 | throw new Error('Missing IAM API key from configuration');
|
30 | }
|
31 |
|
32 | cfg = Object.assign({
|
33 | autoRenew: true,
|
34 | iamTokenUrl: 'https://iam.cloud.ibm.com/identity/token',
|
35 | retryDelayMsecs: 1000
|
36 | }, cfg);
|
37 |
|
38 | super(client, cfg);
|
39 |
|
40 | let sessionUrl = new u.URL(cfg.serverUrl);
|
41 | sessionUrl.pathname = '/_iam_session';
|
42 |
|
43 | this._jar = request.jar();
|
44 |
|
45 | this._tokenManager = new IAMTokenManager(
|
46 | client,
|
47 | this._jar,
|
48 | u.format(sessionUrl, {auth: false}),
|
49 | cfg.iamTokenUrl,
|
50 | cfg.iamApiKey,
|
51 | cfg.iamClientId,
|
52 | cfg.iamClientSecret
|
53 | );
|
54 |
|
55 | if (cfg.autoRenew) {
|
56 | this._tokenManager.startAutoRenew();
|
57 | }
|
58 | }
|
59 |
|
60 | onRequest(state, req, callback) {
|
61 | var self = this;
|
62 |
|
63 | req.jar = self._jar;
|
64 |
|
65 | req.uri = req.uri || req.url;
|
66 | delete req.url;
|
67 | req.uri = u.format(new u.URL(req.uri), {auth: false});
|
68 |
|
69 | self._tokenManager.renewIfRequired().then(() => {
|
70 | callback(state);
|
71 | }).catch((error) => {
|
72 | debug(error);
|
73 | if (state.attempt < state.maxAttempt) {
|
74 | state.retry = true;
|
75 | let iamResponse = error.response;
|
76 | let retryAfterSecs;
|
77 | if (iamResponse && iamResponse.headers) {
|
78 | retryAfterSecs = iamResponse.headers['Retry-After'];
|
79 | }
|
80 | if (retryAfterSecs) {
|
81 | state.retryDelayMsecs = retryAfterSecs * 1000;
|
82 | } else {
|
83 | state.retryDelayMsecs = self._cfg.retryDelayMsecs;
|
84 | }
|
85 | } else {
|
86 | state.abortWithResponse = [ error ];
|
87 | }
|
88 | callback(state);
|
89 | });
|
90 | }
|
91 |
|
92 | onResponse(state, response, callback) {
|
93 | if (response.statusCode === 401) {
|
94 | debug('Received 401 response. Asking for request retry.');
|
95 | state.retry = true;
|
96 | this._tokenManager.attemptTokenRenewal = true;
|
97 | }
|
98 | callback(state);
|
99 | }
|
100 |
|
101 | setIamApiKey(newIamApiKey) {
|
102 | this._tokenManager.setIamApiKey(newIamApiKey);
|
103 | }
|
104 | }
|
105 |
|
106 | IAMPlugin.id = 'iamauth';
|
107 |
|
108 | module.exports = IAMPlugin;
|