@webex/webex-core 2.59.3-next.1 → 2.59.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +6 -6
- package/README.md +79 -79
- package/babel.config.js +3 -3
- package/dist/config.js +24 -24
- package/dist/config.js.map +1 -1
- package/dist/credentials-config.js +56 -56
- package/dist/credentials-config.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interceptors/auth.js +28 -28
- package/dist/interceptors/auth.js.map +1 -1
- package/dist/interceptors/default-options.js +24 -24
- package/dist/interceptors/default-options.js.map +1 -1
- package/dist/interceptors/embargo.js +9 -9
- package/dist/interceptors/embargo.js.map +1 -1
- package/dist/interceptors/network-timing.js +19 -19
- package/dist/interceptors/network-timing.js.map +1 -1
- package/dist/interceptors/payload-transformer.js +19 -19
- package/dist/interceptors/payload-transformer.js.map +1 -1
- package/dist/interceptors/rate-limit.js +40 -40
- package/dist/interceptors/rate-limit.js.map +1 -1
- package/dist/interceptors/redirect.js +13 -13
- package/dist/interceptors/redirect.js.map +1 -1
- package/dist/interceptors/request-event.js +23 -23
- package/dist/interceptors/request-event.js.map +1 -1
- package/dist/interceptors/request-logger.js +13 -13
- package/dist/interceptors/request-logger.js.map +1 -1
- package/dist/interceptors/request-timing.js +23 -23
- package/dist/interceptors/request-timing.js.map +1 -1
- package/dist/interceptors/response-logger.js +19 -19
- package/dist/interceptors/response-logger.js.map +1 -1
- package/dist/interceptors/user-agent.js +29 -29
- package/dist/interceptors/user-agent.js.map +1 -1
- package/dist/interceptors/webex-tracking-id.js +15 -15
- package/dist/interceptors/webex-tracking-id.js.map +1 -1
- package/dist/interceptors/webex-user-agent.js +13 -13
- package/dist/interceptors/webex-user-agent.js.map +1 -1
- package/dist/lib/batcher.js +83 -83
- package/dist/lib/batcher.js.map +1 -1
- package/dist/lib/credentials/credentials.js +103 -103
- package/dist/lib/credentials/credentials.js.map +1 -1
- package/dist/lib/credentials/grant-errors.js +17 -17
- package/dist/lib/credentials/grant-errors.js.map +1 -1
- package/dist/lib/credentials/index.js +2 -2
- package/dist/lib/credentials/index.js.map +1 -1
- package/dist/lib/credentials/scope.js +11 -11
- package/dist/lib/credentials/scope.js.map +1 -1
- package/dist/lib/credentials/token-collection.js +2 -2
- package/dist/lib/credentials/token-collection.js.map +1 -1
- package/dist/lib/credentials/token.js +145 -145
- package/dist/lib/credentials/token.js.map +1 -1
- package/dist/lib/page.js +49 -49
- package/dist/lib/page.js.map +1 -1
- package/dist/lib/services/constants.js.map +1 -1
- package/dist/lib/services/index.js +2 -2
- package/dist/lib/services/index.js.map +1 -1
- package/dist/lib/services/interceptors/server-error.js +9 -9
- package/dist/lib/services/interceptors/server-error.js.map +1 -1
- package/dist/lib/services/interceptors/service.js +24 -24
- package/dist/lib/services/interceptors/service.js.map +1 -1
- package/dist/lib/services/metrics.js.map +1 -1
- package/dist/lib/services/service-catalog.js +104 -104
- package/dist/lib/services/service-catalog.js.map +1 -1
- package/dist/lib/services/service-fed-ramp.js.map +1 -1
- package/dist/lib/services/service-host.js +134 -134
- package/dist/lib/services/service-host.js.map +1 -1
- package/dist/lib/services/service-registry.js +175 -175
- package/dist/lib/services/service-registry.js.map +1 -1
- package/dist/lib/services/service-state.js +38 -38
- package/dist/lib/services/service-state.js.map +1 -1
- package/dist/lib/services/service-url.js +31 -31
- package/dist/lib/services/service-url.js.map +1 -1
- package/dist/lib/services/services.js +245 -245
- package/dist/lib/services/services.js.map +1 -1
- package/dist/lib/stateless-webex-plugin.js +28 -28
- package/dist/lib/stateless-webex-plugin.js.map +1 -1
- package/dist/lib/storage/decorators.js +27 -27
- package/dist/lib/storage/decorators.js.map +1 -1
- package/dist/lib/storage/errors.js +4 -4
- package/dist/lib/storage/errors.js.map +1 -1
- package/dist/lib/storage/index.js.map +1 -1
- package/dist/lib/storage/make-webex-plugin-store.js +44 -44
- package/dist/lib/storage/make-webex-plugin-store.js.map +1 -1
- package/dist/lib/storage/make-webex-store.js +40 -40
- package/dist/lib/storage/make-webex-store.js.map +1 -1
- package/dist/lib/storage/memory-store-adapter.js +9 -9
- package/dist/lib/storage/memory-store-adapter.js.map +1 -1
- package/dist/lib/webex-core-plugin-mixin.js +13 -13
- package/dist/lib/webex-core-plugin-mixin.js.map +1 -1
- package/dist/lib/webex-http-error.js +9 -9
- package/dist/lib/webex-http-error.js.map +1 -1
- package/dist/lib/webex-internal-core-plugin-mixin.js +13 -13
- package/dist/lib/webex-internal-core-plugin-mixin.js.map +1 -1
- package/dist/lib/webex-plugin.js +36 -36
- package/dist/lib/webex-plugin.js.map +1 -1
- package/dist/plugins/logger.js +9 -9
- package/dist/plugins/logger.js.map +1 -1
- package/dist/webex-core.js +104 -104
- package/dist/webex-core.js.map +1 -1
- package/dist/webex-internal-core.js +12 -12
- package/dist/webex-internal-core.js.map +1 -1
- package/jest.config.js +3 -3
- package/package.json +19 -20
- package/process +1 -1
- package/src/config.js +90 -90
- package/src/credentials-config.js +212 -212
- package/src/index.js +62 -62
- package/src/interceptors/auth.js +186 -186
- package/src/interceptors/default-options.js +55 -55
- package/src/interceptors/embargo.js +43 -43
- package/src/interceptors/network-timing.js +54 -54
- package/src/interceptors/payload-transformer.js +55 -55
- package/src/interceptors/rate-limit.js +169 -169
- package/src/interceptors/redirect.js +106 -106
- package/src/interceptors/request-event.js +93 -93
- package/src/interceptors/request-logger.js +78 -78
- package/src/interceptors/request-timing.js +65 -65
- package/src/interceptors/response-logger.js +98 -98
- package/src/interceptors/user-agent.js +77 -77
- package/src/interceptors/webex-tracking-id.js +73 -73
- package/src/interceptors/webex-user-agent.js +79 -79
- package/src/lib/batcher.js +307 -307
- package/src/lib/credentials/credentials.js +552 -552
- package/src/lib/credentials/grant-errors.js +92 -92
- package/src/lib/credentials/index.js +16 -16
- package/src/lib/credentials/scope.js +34 -34
- package/src/lib/credentials/token-collection.js +17 -17
- package/src/lib/credentials/token.js +559 -559
- package/src/lib/page.js +159 -159
- package/src/lib/services/constants.js +9 -9
- package/src/lib/services/index.js +26 -26
- package/src/lib/services/interceptors/server-error.js +48 -48
- package/src/lib/services/interceptors/service.js +101 -101
- package/src/lib/services/metrics.js +4 -4
- package/src/lib/services/service-catalog.js +435 -435
- package/src/lib/services/service-fed-ramp.js +4 -4
- package/src/lib/services/service-host.js +267 -267
- package/src/lib/services/service-registry.js +465 -465
- package/src/lib/services/service-state.js +78 -78
- package/src/lib/services/service-url.js +124 -124
- package/src/lib/services/services.js +1018 -1018
- package/src/lib/stateless-webex-plugin.js +98 -98
- package/src/lib/storage/decorators.js +220 -220
- package/src/lib/storage/errors.js +15 -15
- package/src/lib/storage/index.js +10 -10
- package/src/lib/storage/make-webex-plugin-store.js +211 -211
- package/src/lib/storage/make-webex-store.js +140 -140
- package/src/lib/storage/memory-store-adapter.js +79 -79
- package/src/lib/webex-core-plugin-mixin.js +114 -114
- package/src/lib/webex-http-error.js +61 -61
- package/src/lib/webex-internal-core-plugin-mixin.js +107 -107
- package/src/lib/webex-plugin.js +222 -222
- package/src/plugins/logger.js +60 -60
- package/src/webex-core.js +745 -745
- package/src/webex-internal-core.js +46 -46
- package/test/integration/spec/credentials/credentials.js +139 -139
- package/test/integration/spec/credentials/token.js +102 -102
- package/test/integration/spec/services/service-catalog.js +838 -838
- package/test/integration/spec/services/services.js +1221 -1221
- package/test/integration/spec/webex-core.js +178 -178
- package/test/unit/spec/_setup.js +44 -44
- package/test/unit/spec/credentials/credentials.js +1017 -1017
- package/test/unit/spec/credentials/token.js +441 -441
- package/test/unit/spec/interceptors/auth.js +521 -521
- package/test/unit/spec/interceptors/default-options.js +84 -84
- package/test/unit/spec/interceptors/embargo.js +144 -144
- package/test/unit/spec/interceptors/network-timing.js +49 -49
- package/test/unit/spec/interceptors/payload-transformer.js +155 -155
- package/test/unit/spec/interceptors/rate-limit.js +302 -302
- package/test/unit/spec/interceptors/redirect.js +102 -102
- package/test/unit/spec/interceptors/request-timing.js +92 -92
- package/test/unit/spec/interceptors/user-agent.js +76 -76
- package/test/unit/spec/interceptors/webex-tracking-id.js +76 -76
- package/test/unit/spec/interceptors/webex-user-agent.js +159 -159
- package/test/unit/spec/lib/batcher.js +330 -330
- package/test/unit/spec/lib/page.js +148 -148
- package/test/unit/spec/lib/webex-plugin.js +48 -48
- package/test/unit/spec/services/interceptors/server-error.js +204 -204
- package/test/unit/spec/services/interceptors/service.js +188 -188
- package/test/unit/spec/services/service-catalog.js +194 -194
- package/test/unit/spec/services/service-host.js +260 -260
- package/test/unit/spec/services/service-registry.js +747 -747
- package/test/unit/spec/services/service-state.js +60 -60
- package/test/unit/spec/services/service-url.js +258 -258
- package/test/unit/spec/services/services.js +348 -348
- package/test/unit/spec/storage/persist.js +50 -50
- package/test/unit/spec/storage/storage-adapter.js +12 -12
- package/test/unit/spec/storage/wait-for-value.js +81 -81
- package/test/unit/spec/webex-core.js +253 -253
- package/test/unit/spec/webex-internal-core.js +91 -91
|
@@ -1,521 +1,521 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/* eslint-disable camelcase */
|
|
6
|
-
|
|
7
|
-
import chai from 'chai';
|
|
8
|
-
import chaiAsPromised from 'chai-as-promised';
|
|
9
|
-
import sinon from 'sinon';
|
|
10
|
-
import {browserOnly, nodeOnly} from '@webex/test-helper-mocha';
|
|
11
|
-
import Logger from '@webex/plugin-logger';
|
|
12
|
-
import MockWebex from '@webex/test-helper-mock-webex';
|
|
13
|
-
import {AuthInterceptor, config, Credentials, WebexHttpError, Token} from '@webex/webex-core';
|
|
14
|
-
import {cloneDeep, merge} from 'lodash';
|
|
15
|
-
|
|
16
|
-
const {assert} = chai;
|
|
17
|
-
|
|
18
|
-
chai.use(chaiAsPromised);
|
|
19
|
-
sinon.assert.expose(chai.assert, {prefix: ''});
|
|
20
|
-
|
|
21
|
-
describe('webex-core', () => {
|
|
22
|
-
describe('Interceptors', () => {
|
|
23
|
-
describe('AuthInterceptor', () => {
|
|
24
|
-
let interceptor, webex;
|
|
25
|
-
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
webex = new MockWebex({
|
|
28
|
-
children: {
|
|
29
|
-
credentials: Credentials,
|
|
30
|
-
logger: Logger,
|
|
31
|
-
},
|
|
32
|
-
config: merge(cloneDeep(config), {credentials: {client_secret: 'fake'}}),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
webex.credentials.supertoken = new Token(
|
|
36
|
-
{
|
|
37
|
-
access_token: 'ST1',
|
|
38
|
-
token_type: 'Bearer',
|
|
39
|
-
},
|
|
40
|
-
{parent: webex}
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
interceptor = Reflect.apply(AuthInterceptor.create, webex, []);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe('#onRequest()', () => {
|
|
47
|
-
it('does not replace the auth header if one has been provided', () =>
|
|
48
|
-
interceptor
|
|
49
|
-
.onRequest({
|
|
50
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
51
|
-
headers: {
|
|
52
|
-
authorization: 'Bearer Alternate',
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
.then((result) =>
|
|
56
|
-
assert.deepEqual(result, {
|
|
57
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
58
|
-
headers: {
|
|
59
|
-
authorization: 'Bearer Alternate',
|
|
60
|
-
},
|
|
61
|
-
})
|
|
62
|
-
));
|
|
63
|
-
|
|
64
|
-
[undefined, null, false].forEach((falsey) => {
|
|
65
|
-
it(`does not add an auth header if ${falsey} has been provided`, () =>
|
|
66
|
-
interceptor
|
|
67
|
-
.onRequest({
|
|
68
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
69
|
-
headers: {
|
|
70
|
-
authorization: falsey,
|
|
71
|
-
},
|
|
72
|
-
})
|
|
73
|
-
.then((result) =>
|
|
74
|
-
assert.deepEqual(result, {
|
|
75
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
76
|
-
headers: {},
|
|
77
|
-
})
|
|
78
|
-
));
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// There should never be a case in which the services plugin is not
|
|
82
|
-
// loaded. But testing for legacy support.
|
|
83
|
-
describe('when the services plugin has not been loaded', () => {
|
|
84
|
-
it('does not add the auth header to hydra requests', () =>
|
|
85
|
-
interceptor
|
|
86
|
-
.onRequest({
|
|
87
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
88
|
-
})
|
|
89
|
-
.then((result) =>
|
|
90
|
-
assert.deepEqual(result, {
|
|
91
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
92
|
-
headers: {},
|
|
93
|
-
})
|
|
94
|
-
));
|
|
95
|
-
|
|
96
|
-
it('does not add the auth header to u2c requests', () =>
|
|
97
|
-
interceptor
|
|
98
|
-
.onRequest({
|
|
99
|
-
uri: `${config.services.discovery.u2c}/ping`,
|
|
100
|
-
})
|
|
101
|
-
.then((result) =>
|
|
102
|
-
assert.deepEqual(result, {
|
|
103
|
-
uri: `${config.services.discovery.u2c}/ping`,
|
|
104
|
-
headers: {},
|
|
105
|
-
})
|
|
106
|
-
));
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('when the services plugin has been loaded', () => {
|
|
110
|
-
let services;
|
|
111
|
-
|
|
112
|
-
beforeEach(() => {
|
|
113
|
-
services = {
|
|
114
|
-
hydra: 'https://hydra-a.wbx.com',
|
|
115
|
-
example: 'https://service.example.com',
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
webex.internal.services = {
|
|
119
|
-
hasService: (service) => Object.keys(services).includes(service),
|
|
120
|
-
hasAllowedDomains: () => true,
|
|
121
|
-
isAllowedDomainUrl: (uri) =>
|
|
122
|
-
!!config.services.allowedDomains.find((host) => uri.includes(host)),
|
|
123
|
-
getServiceFromUrl: (uri) => {
|
|
124
|
-
let targetKey;
|
|
125
|
-
|
|
126
|
-
Object.keys(services).forEach((key) => {
|
|
127
|
-
if (uri.includes(services[key])) {
|
|
128
|
-
targetKey = key;
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
return targetKey ? {name: targetKey} : undefined;
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
webex.internal.services.waitForService = (pto) =>
|
|
137
|
-
Promise.resolve(services[pto.name] || pto.url);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('adds the header to hydra requests', () =>
|
|
141
|
-
Promise.all([
|
|
142
|
-
interceptor.onRequest({uri: `${services.hydra}/ping`}).then((result) =>
|
|
143
|
-
assert.deepEqual(result, {
|
|
144
|
-
uri: `${services.hydra}/ping`,
|
|
145
|
-
headers: {
|
|
146
|
-
authorization: 'Bearer ST1',
|
|
147
|
-
},
|
|
148
|
-
})
|
|
149
|
-
),
|
|
150
|
-
interceptor
|
|
151
|
-
.onRequest({
|
|
152
|
-
service: 'hydra',
|
|
153
|
-
resource: 'ping',
|
|
154
|
-
})
|
|
155
|
-
.then((result) =>
|
|
156
|
-
assert.deepEqual(result, {
|
|
157
|
-
service: 'hydra',
|
|
158
|
-
resource: 'ping',
|
|
159
|
-
headers: {
|
|
160
|
-
authorization: 'Bearer ST1',
|
|
161
|
-
},
|
|
162
|
-
})
|
|
163
|
-
),
|
|
164
|
-
]));
|
|
165
|
-
|
|
166
|
-
it('adds an auth header to uris that are in the service catalog', () =>
|
|
167
|
-
interceptor
|
|
168
|
-
.onRequest({
|
|
169
|
-
uri: `${services.example}/ping`,
|
|
170
|
-
})
|
|
171
|
-
.then((result) =>
|
|
172
|
-
assert.deepEqual(result, {
|
|
173
|
-
uri: `${services.example}/ping`,
|
|
174
|
-
headers: {
|
|
175
|
-
authorization: 'Bearer ST1',
|
|
176
|
-
},
|
|
177
|
-
})
|
|
178
|
-
));
|
|
179
|
-
|
|
180
|
-
it('adds an auth header to services that are in the service catalog', () =>
|
|
181
|
-
interceptor
|
|
182
|
-
.onRequest({
|
|
183
|
-
service: 'example',
|
|
184
|
-
resource: 'some-resource',
|
|
185
|
-
})
|
|
186
|
-
.then((result) =>
|
|
187
|
-
assert.deepEqual(result, {
|
|
188
|
-
service: 'example',
|
|
189
|
-
resource: 'some-resource',
|
|
190
|
-
headers: {
|
|
191
|
-
authorization: 'Bearer ST1',
|
|
192
|
-
},
|
|
193
|
-
})
|
|
194
|
-
));
|
|
195
|
-
|
|
196
|
-
it('does not add an auth header to uris not in the service catalog', () =>
|
|
197
|
-
interceptor
|
|
198
|
-
.onRequest({
|
|
199
|
-
uri: 'https://not-a-service.com/ping',
|
|
200
|
-
})
|
|
201
|
-
.then((result) =>
|
|
202
|
-
assert.deepEqual(result, {
|
|
203
|
-
headers: {},
|
|
204
|
-
uri: 'https://not-a-service.com/ping',
|
|
205
|
-
})
|
|
206
|
-
));
|
|
207
|
-
|
|
208
|
-
it('does not add an auth header to non-existant services', () =>
|
|
209
|
-
interceptor
|
|
210
|
-
.onRequest({
|
|
211
|
-
service: 'non-existant',
|
|
212
|
-
resource: 'no-resource',
|
|
213
|
-
})
|
|
214
|
-
.then((result) =>
|
|
215
|
-
assert.deepEqual(result, {
|
|
216
|
-
headers: {},
|
|
217
|
-
service: 'non-existant',
|
|
218
|
-
resource: 'no-resource',
|
|
219
|
-
})
|
|
220
|
-
));
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
describe('#requiresCredentials()', () => {
|
|
225
|
-
let services;
|
|
226
|
-
|
|
227
|
-
beforeEach(() => {
|
|
228
|
-
services = {
|
|
229
|
-
hydra: 'https://hydra-a.wbx.com',
|
|
230
|
-
u2c: 'https://u2c.wbx2.com/u2c/api/v1',
|
|
231
|
-
example: 'https://service.example.com',
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
webex.internal.services = {
|
|
235
|
-
getServiceFromUrl: (uri) => {
|
|
236
|
-
let targetKey;
|
|
237
|
-
|
|
238
|
-
Object.keys(services).forEach((key) => {
|
|
239
|
-
if (uri.includes(services[key])) {
|
|
240
|
-
targetKey = key;
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
return targetKey ? {name: targetKey} : undefined;
|
|
245
|
-
},
|
|
246
|
-
hasService: (service) => Object.keys(services).includes(service),
|
|
247
|
-
hasAllowedDomains: () => true,
|
|
248
|
-
isAllowedDomainUrl: (uri) =>
|
|
249
|
-
!!config.services.allowedDomains.find((host) => uri.includes(host)),
|
|
250
|
-
validateDomains: true,
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
webex.internal.services.waitForService = (pto) =>
|
|
254
|
-
Promise.resolve(services[pto.name] || pto.url);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
afterEach(() => {
|
|
258
|
-
if (webex.internal.services) {
|
|
259
|
-
delete webex.internal.services;
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
it('resolves to false when services plugin does not exist', () => {
|
|
264
|
-
delete webex.internal.services;
|
|
265
|
-
|
|
266
|
-
return interceptor
|
|
267
|
-
.requiresCredentials({
|
|
268
|
-
uri: `${services.hydra}/ping`,
|
|
269
|
-
})
|
|
270
|
-
.then((response) => assert.isFalse(response));
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
it('resolves to true when the u2c service is specified via service', () => {
|
|
274
|
-
services = {};
|
|
275
|
-
|
|
276
|
-
return interceptor
|
|
277
|
-
.requiresCredentials({
|
|
278
|
-
service: 'u2c',
|
|
279
|
-
resource: 'something',
|
|
280
|
-
})
|
|
281
|
-
.then((response) => assert.isTrue(response));
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it('resolves to false when the u2c limited service is used via uri', () =>
|
|
285
|
-
interceptor
|
|
286
|
-
.requiresCredentials({
|
|
287
|
-
uri: `${services.u2c}/limited`,
|
|
288
|
-
})
|
|
289
|
-
.then((response) => assert.isFalse(response)));
|
|
290
|
-
|
|
291
|
-
it('resolves to true if the service exists in catalog via service', () =>
|
|
292
|
-
interceptor
|
|
293
|
-
.requiresCredentials({service: 'hydra'})
|
|
294
|
-
.then((response) => assert.isTrue(response)));
|
|
295
|
-
|
|
296
|
-
it('resolves to true if the service exists in catalog via uri', () =>
|
|
297
|
-
interceptor
|
|
298
|
-
.requiresCredentials({uri: services.hydra})
|
|
299
|
-
.then((response) => assert.isTrue(response)));
|
|
300
|
-
|
|
301
|
-
it('resolves to false if that `addAuthHeader` is set to false', () =>
|
|
302
|
-
interceptor
|
|
303
|
-
.requiresCredentials({
|
|
304
|
-
addAuthHeader: false,
|
|
305
|
-
service: 'unknown',
|
|
306
|
-
resource: 'ping',
|
|
307
|
-
})
|
|
308
|
-
.then((response) => assert.isFalse(response)));
|
|
309
|
-
|
|
310
|
-
it('resolves to false if `validateDomains` is set to false', () => {
|
|
311
|
-
webex.internal.services.validateDomains = false;
|
|
312
|
-
|
|
313
|
-
return interceptor
|
|
314
|
-
.requiresCredentials({
|
|
315
|
-
uri: 'https://allowed-uri.com/resource',
|
|
316
|
-
})
|
|
317
|
-
.then((response) => assert.isFalse(response));
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it('resolves to true with an allowed domain uri', () =>
|
|
321
|
-
interceptor
|
|
322
|
-
.requiresCredentials({
|
|
323
|
-
uri: `https://${config.services.allowedDomains[0]}/resource`,
|
|
324
|
-
})
|
|
325
|
-
.then((response) => assert.isTrue(response)));
|
|
326
|
-
|
|
327
|
-
it('resolves to false with a non-allowed uri', () =>
|
|
328
|
-
interceptor
|
|
329
|
-
.requiresCredentials({
|
|
330
|
-
uri: 'https://not-allowed/resource',
|
|
331
|
-
})
|
|
332
|
-
.then((response) => assert.isFalse(response)));
|
|
333
|
-
|
|
334
|
-
it('should return true if domain exists using isAllowedDomainUrl()', () => {
|
|
335
|
-
webex.internal.services.waitForService = sinon.stub();
|
|
336
|
-
const {isAllowedDomainUrl} = webex.internal.services;
|
|
337
|
-
|
|
338
|
-
const result = isAllowedDomainUrl(
|
|
339
|
-
`https://${config.services.allowedDomains[0]}/resource`
|
|
340
|
-
);
|
|
341
|
-
|
|
342
|
-
assert.equal(result, true);
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
it('should return true when called `requiresCredentials` with valid url', () => {
|
|
346
|
-
webex.internal.services.waitForService = sinon.stub();
|
|
347
|
-
|
|
348
|
-
return interceptor
|
|
349
|
-
.requiresCredentials({
|
|
350
|
-
uri: `https://${config.services.allowedDomains[0]}/resource`,
|
|
351
|
-
})
|
|
352
|
-
.then((res) => {
|
|
353
|
-
assert.equal(res, true);
|
|
354
|
-
});
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
it('should call waitForService()', () => {
|
|
358
|
-
webex.internal.services.waitForService = sinon.stub();
|
|
359
|
-
const {waitForService} = webex.internal.services;
|
|
360
|
-
|
|
361
|
-
waitForService.resolves(`https://${config.services.allowedDomains[0]}/resource`);
|
|
362
|
-
|
|
363
|
-
return interceptor
|
|
364
|
-
.requiresCredentials({
|
|
365
|
-
service: 'locus',
|
|
366
|
-
})
|
|
367
|
-
.then(() => assert.calledOnce(waitForService));
|
|
368
|
-
});
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
describe('#onResponseError()', () => {
|
|
372
|
-
describe('when the server responds with 401', () => {
|
|
373
|
-
nodeOnly(it)('refreshes the access token and replays the request', () => {
|
|
374
|
-
webex.request.onCall(0).returns(
|
|
375
|
-
Promise.resolve({
|
|
376
|
-
body: {
|
|
377
|
-
access_token: 'ST2',
|
|
378
|
-
},
|
|
379
|
-
})
|
|
380
|
-
);
|
|
381
|
-
webex.credentials.supertoken = new Token(
|
|
382
|
-
{
|
|
383
|
-
access_token: 'ST1',
|
|
384
|
-
refresh_token: 'RT1',
|
|
385
|
-
},
|
|
386
|
-
{parent: webex}
|
|
387
|
-
);
|
|
388
|
-
|
|
389
|
-
const err = new WebexHttpError.Unauthorized({
|
|
390
|
-
statusCode: 401,
|
|
391
|
-
options: {
|
|
392
|
-
headers: {
|
|
393
|
-
trackingid: 'blarg',
|
|
394
|
-
},
|
|
395
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
396
|
-
},
|
|
397
|
-
body: {
|
|
398
|
-
error: 'fake error',
|
|
399
|
-
},
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
assert.notCalled(webex.request);
|
|
403
|
-
|
|
404
|
-
return interceptor.onResponseError(err.options, err).then(() => {
|
|
405
|
-
// once for refresh, once for replay
|
|
406
|
-
assert.calledTwice(webex.request);
|
|
407
|
-
assert.equal(webex.credentials.supertoken.access_token, 'ST2');
|
|
408
|
-
assert.equal(webex.request.args[1][0].replayCount, 1);
|
|
409
|
-
});
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
browserOnly(it)('refreshes the access token and replays the request', () => {
|
|
413
|
-
webex.config.credentials.refreshCallback = sinon.stub().returns(
|
|
414
|
-
Promise.resolve({
|
|
415
|
-
access_token: 'ST2',
|
|
416
|
-
})
|
|
417
|
-
);
|
|
418
|
-
|
|
419
|
-
webex.credentials.supertoken = new Token(
|
|
420
|
-
{
|
|
421
|
-
access_token: 'ST1',
|
|
422
|
-
refresh_token: 'RT1',
|
|
423
|
-
},
|
|
424
|
-
{parent: webex}
|
|
425
|
-
);
|
|
426
|
-
|
|
427
|
-
const err = new WebexHttpError.Unauthorized({
|
|
428
|
-
statusCode: 401,
|
|
429
|
-
options: {
|
|
430
|
-
headers: {
|
|
431
|
-
trackingid: 'blarg',
|
|
432
|
-
},
|
|
433
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
434
|
-
},
|
|
435
|
-
body: {
|
|
436
|
-
error: 'fake error',
|
|
437
|
-
},
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
assert.notCalled(webex.request);
|
|
441
|
-
|
|
442
|
-
return interceptor.onResponseError(err.options, err).then(() => {
|
|
443
|
-
// once for replay
|
|
444
|
-
assert.calledOnce(webex.request);
|
|
445
|
-
assert.equal(webex.credentials.supertoken.access_token, 'ST2');
|
|
446
|
-
assert.equal(webex.request.args[0][0].replayCount, 1);
|
|
447
|
-
});
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
describe('when the access token is not refreshable', () => {
|
|
451
|
-
it('responds with the original error', () => {
|
|
452
|
-
webex.credentials.supertoken = new Token(
|
|
453
|
-
{
|
|
454
|
-
access_token: 'ST1',
|
|
455
|
-
},
|
|
456
|
-
{parent: webex}
|
|
457
|
-
);
|
|
458
|
-
|
|
459
|
-
const err = new WebexHttpError.Unauthorized({
|
|
460
|
-
statusCode: 401,
|
|
461
|
-
options: {
|
|
462
|
-
headers: {
|
|
463
|
-
trackingid: 'blarg',
|
|
464
|
-
},
|
|
465
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
466
|
-
},
|
|
467
|
-
body: {
|
|
468
|
-
error: 'fake error',
|
|
469
|
-
},
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
assert.notCalled(webex.request);
|
|
473
|
-
|
|
474
|
-
return assert
|
|
475
|
-
.isRejected(interceptor.onResponseError(err.options, err))
|
|
476
|
-
.then((err2) => {
|
|
477
|
-
assert.equal(err2, err);
|
|
478
|
-
});
|
|
479
|
-
});
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
it('does not refresh if shouldRefreshAccessToken was false', () => {
|
|
483
|
-
webex.config.credentials.refreshCallback = sinon.stub().returns(
|
|
484
|
-
Promise.resolve({
|
|
485
|
-
access_token: 'ST2',
|
|
486
|
-
})
|
|
487
|
-
);
|
|
488
|
-
|
|
489
|
-
webex.credentials.supertoken = new Token(
|
|
490
|
-
{
|
|
491
|
-
access_token: 'ST1',
|
|
492
|
-
refresh_token: 'RT1',
|
|
493
|
-
},
|
|
494
|
-
{parent: webex}
|
|
495
|
-
);
|
|
496
|
-
|
|
497
|
-
const err = new WebexHttpError.Unauthorized({
|
|
498
|
-
statusCode: 401,
|
|
499
|
-
options: {
|
|
500
|
-
headers: {
|
|
501
|
-
trackingid: 'blarg',
|
|
502
|
-
},
|
|
503
|
-
uri: `${config.services.discovery.hydra}/ping`,
|
|
504
|
-
shouldRefreshAccessToken: false,
|
|
505
|
-
},
|
|
506
|
-
body: {
|
|
507
|
-
error: 'fake error',
|
|
508
|
-
},
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
assert.notCalled(webex.request);
|
|
512
|
-
|
|
513
|
-
return assert.isRejected(interceptor.onResponseError(err.options, err)).then((err2) => {
|
|
514
|
-
assert.equal(err2, err);
|
|
515
|
-
});
|
|
516
|
-
});
|
|
517
|
-
});
|
|
518
|
-
});
|
|
519
|
-
});
|
|
520
|
-
});
|
|
521
|
-
});
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/* eslint-disable camelcase */
|
|
6
|
+
|
|
7
|
+
import chai from 'chai';
|
|
8
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
9
|
+
import sinon from 'sinon';
|
|
10
|
+
import {browserOnly, nodeOnly} from '@webex/test-helper-mocha';
|
|
11
|
+
import Logger from '@webex/plugin-logger';
|
|
12
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
13
|
+
import {AuthInterceptor, config, Credentials, WebexHttpError, Token} from '@webex/webex-core';
|
|
14
|
+
import {cloneDeep, merge} from 'lodash';
|
|
15
|
+
|
|
16
|
+
const {assert} = chai;
|
|
17
|
+
|
|
18
|
+
chai.use(chaiAsPromised);
|
|
19
|
+
sinon.assert.expose(chai.assert, {prefix: ''});
|
|
20
|
+
|
|
21
|
+
describe('webex-core', () => {
|
|
22
|
+
describe('Interceptors', () => {
|
|
23
|
+
describe('AuthInterceptor', () => {
|
|
24
|
+
let interceptor, webex;
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
webex = new MockWebex({
|
|
28
|
+
children: {
|
|
29
|
+
credentials: Credentials,
|
|
30
|
+
logger: Logger,
|
|
31
|
+
},
|
|
32
|
+
config: merge(cloneDeep(config), {credentials: {client_secret: 'fake'}}),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
webex.credentials.supertoken = new Token(
|
|
36
|
+
{
|
|
37
|
+
access_token: 'ST1',
|
|
38
|
+
token_type: 'Bearer',
|
|
39
|
+
},
|
|
40
|
+
{parent: webex}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
interceptor = Reflect.apply(AuthInterceptor.create, webex, []);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('#onRequest()', () => {
|
|
47
|
+
it('does not replace the auth header if one has been provided', () =>
|
|
48
|
+
interceptor
|
|
49
|
+
.onRequest({
|
|
50
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
51
|
+
headers: {
|
|
52
|
+
authorization: 'Bearer Alternate',
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
.then((result) =>
|
|
56
|
+
assert.deepEqual(result, {
|
|
57
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
58
|
+
headers: {
|
|
59
|
+
authorization: 'Bearer Alternate',
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
));
|
|
63
|
+
|
|
64
|
+
[undefined, null, false].forEach((falsey) => {
|
|
65
|
+
it(`does not add an auth header if ${falsey} has been provided`, () =>
|
|
66
|
+
interceptor
|
|
67
|
+
.onRequest({
|
|
68
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
69
|
+
headers: {
|
|
70
|
+
authorization: falsey,
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
.then((result) =>
|
|
74
|
+
assert.deepEqual(result, {
|
|
75
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
76
|
+
headers: {},
|
|
77
|
+
})
|
|
78
|
+
));
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// There should never be a case in which the services plugin is not
|
|
82
|
+
// loaded. But testing for legacy support.
|
|
83
|
+
describe('when the services plugin has not been loaded', () => {
|
|
84
|
+
it('does not add the auth header to hydra requests', () =>
|
|
85
|
+
interceptor
|
|
86
|
+
.onRequest({
|
|
87
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
88
|
+
})
|
|
89
|
+
.then((result) =>
|
|
90
|
+
assert.deepEqual(result, {
|
|
91
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
92
|
+
headers: {},
|
|
93
|
+
})
|
|
94
|
+
));
|
|
95
|
+
|
|
96
|
+
it('does not add the auth header to u2c requests', () =>
|
|
97
|
+
interceptor
|
|
98
|
+
.onRequest({
|
|
99
|
+
uri: `${config.services.discovery.u2c}/ping`,
|
|
100
|
+
})
|
|
101
|
+
.then((result) =>
|
|
102
|
+
assert.deepEqual(result, {
|
|
103
|
+
uri: `${config.services.discovery.u2c}/ping`,
|
|
104
|
+
headers: {},
|
|
105
|
+
})
|
|
106
|
+
));
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe('when the services plugin has been loaded', () => {
|
|
110
|
+
let services;
|
|
111
|
+
|
|
112
|
+
beforeEach(() => {
|
|
113
|
+
services = {
|
|
114
|
+
hydra: 'https://hydra-a.wbx.com',
|
|
115
|
+
example: 'https://service.example.com',
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
webex.internal.services = {
|
|
119
|
+
hasService: (service) => Object.keys(services).includes(service),
|
|
120
|
+
hasAllowedDomains: () => true,
|
|
121
|
+
isAllowedDomainUrl: (uri) =>
|
|
122
|
+
!!config.services.allowedDomains.find((host) => uri.includes(host)),
|
|
123
|
+
getServiceFromUrl: (uri) => {
|
|
124
|
+
let targetKey;
|
|
125
|
+
|
|
126
|
+
Object.keys(services).forEach((key) => {
|
|
127
|
+
if (uri.includes(services[key])) {
|
|
128
|
+
targetKey = key;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return targetKey ? {name: targetKey} : undefined;
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
webex.internal.services.waitForService = (pto) =>
|
|
137
|
+
Promise.resolve(services[pto.name] || pto.url);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('adds the header to hydra requests', () =>
|
|
141
|
+
Promise.all([
|
|
142
|
+
interceptor.onRequest({uri: `${services.hydra}/ping`}).then((result) =>
|
|
143
|
+
assert.deepEqual(result, {
|
|
144
|
+
uri: `${services.hydra}/ping`,
|
|
145
|
+
headers: {
|
|
146
|
+
authorization: 'Bearer ST1',
|
|
147
|
+
},
|
|
148
|
+
})
|
|
149
|
+
),
|
|
150
|
+
interceptor
|
|
151
|
+
.onRequest({
|
|
152
|
+
service: 'hydra',
|
|
153
|
+
resource: 'ping',
|
|
154
|
+
})
|
|
155
|
+
.then((result) =>
|
|
156
|
+
assert.deepEqual(result, {
|
|
157
|
+
service: 'hydra',
|
|
158
|
+
resource: 'ping',
|
|
159
|
+
headers: {
|
|
160
|
+
authorization: 'Bearer ST1',
|
|
161
|
+
},
|
|
162
|
+
})
|
|
163
|
+
),
|
|
164
|
+
]));
|
|
165
|
+
|
|
166
|
+
it('adds an auth header to uris that are in the service catalog', () =>
|
|
167
|
+
interceptor
|
|
168
|
+
.onRequest({
|
|
169
|
+
uri: `${services.example}/ping`,
|
|
170
|
+
})
|
|
171
|
+
.then((result) =>
|
|
172
|
+
assert.deepEqual(result, {
|
|
173
|
+
uri: `${services.example}/ping`,
|
|
174
|
+
headers: {
|
|
175
|
+
authorization: 'Bearer ST1',
|
|
176
|
+
},
|
|
177
|
+
})
|
|
178
|
+
));
|
|
179
|
+
|
|
180
|
+
it('adds an auth header to services that are in the service catalog', () =>
|
|
181
|
+
interceptor
|
|
182
|
+
.onRequest({
|
|
183
|
+
service: 'example',
|
|
184
|
+
resource: 'some-resource',
|
|
185
|
+
})
|
|
186
|
+
.then((result) =>
|
|
187
|
+
assert.deepEqual(result, {
|
|
188
|
+
service: 'example',
|
|
189
|
+
resource: 'some-resource',
|
|
190
|
+
headers: {
|
|
191
|
+
authorization: 'Bearer ST1',
|
|
192
|
+
},
|
|
193
|
+
})
|
|
194
|
+
));
|
|
195
|
+
|
|
196
|
+
it('does not add an auth header to uris not in the service catalog', () =>
|
|
197
|
+
interceptor
|
|
198
|
+
.onRequest({
|
|
199
|
+
uri: 'https://not-a-service.com/ping',
|
|
200
|
+
})
|
|
201
|
+
.then((result) =>
|
|
202
|
+
assert.deepEqual(result, {
|
|
203
|
+
headers: {},
|
|
204
|
+
uri: 'https://not-a-service.com/ping',
|
|
205
|
+
})
|
|
206
|
+
));
|
|
207
|
+
|
|
208
|
+
it('does not add an auth header to non-existant services', () =>
|
|
209
|
+
interceptor
|
|
210
|
+
.onRequest({
|
|
211
|
+
service: 'non-existant',
|
|
212
|
+
resource: 'no-resource',
|
|
213
|
+
})
|
|
214
|
+
.then((result) =>
|
|
215
|
+
assert.deepEqual(result, {
|
|
216
|
+
headers: {},
|
|
217
|
+
service: 'non-existant',
|
|
218
|
+
resource: 'no-resource',
|
|
219
|
+
})
|
|
220
|
+
));
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe('#requiresCredentials()', () => {
|
|
225
|
+
let services;
|
|
226
|
+
|
|
227
|
+
beforeEach(() => {
|
|
228
|
+
services = {
|
|
229
|
+
hydra: 'https://hydra-a.wbx.com',
|
|
230
|
+
u2c: 'https://u2c.wbx2.com/u2c/api/v1',
|
|
231
|
+
example: 'https://service.example.com',
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
webex.internal.services = {
|
|
235
|
+
getServiceFromUrl: (uri) => {
|
|
236
|
+
let targetKey;
|
|
237
|
+
|
|
238
|
+
Object.keys(services).forEach((key) => {
|
|
239
|
+
if (uri.includes(services[key])) {
|
|
240
|
+
targetKey = key;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return targetKey ? {name: targetKey} : undefined;
|
|
245
|
+
},
|
|
246
|
+
hasService: (service) => Object.keys(services).includes(service),
|
|
247
|
+
hasAllowedDomains: () => true,
|
|
248
|
+
isAllowedDomainUrl: (uri) =>
|
|
249
|
+
!!config.services.allowedDomains.find((host) => uri.includes(host)),
|
|
250
|
+
validateDomains: true,
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
webex.internal.services.waitForService = (pto) =>
|
|
254
|
+
Promise.resolve(services[pto.name] || pto.url);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
afterEach(() => {
|
|
258
|
+
if (webex.internal.services) {
|
|
259
|
+
delete webex.internal.services;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('resolves to false when services plugin does not exist', () => {
|
|
264
|
+
delete webex.internal.services;
|
|
265
|
+
|
|
266
|
+
return interceptor
|
|
267
|
+
.requiresCredentials({
|
|
268
|
+
uri: `${services.hydra}/ping`,
|
|
269
|
+
})
|
|
270
|
+
.then((response) => assert.isFalse(response));
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('resolves to true when the u2c service is specified via service', () => {
|
|
274
|
+
services = {};
|
|
275
|
+
|
|
276
|
+
return interceptor
|
|
277
|
+
.requiresCredentials({
|
|
278
|
+
service: 'u2c',
|
|
279
|
+
resource: 'something',
|
|
280
|
+
})
|
|
281
|
+
.then((response) => assert.isTrue(response));
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('resolves to false when the u2c limited service is used via uri', () =>
|
|
285
|
+
interceptor
|
|
286
|
+
.requiresCredentials({
|
|
287
|
+
uri: `${services.u2c}/limited`,
|
|
288
|
+
})
|
|
289
|
+
.then((response) => assert.isFalse(response)));
|
|
290
|
+
|
|
291
|
+
it('resolves to true if the service exists in catalog via service', () =>
|
|
292
|
+
interceptor
|
|
293
|
+
.requiresCredentials({service: 'hydra'})
|
|
294
|
+
.then((response) => assert.isTrue(response)));
|
|
295
|
+
|
|
296
|
+
it('resolves to true if the service exists in catalog via uri', () =>
|
|
297
|
+
interceptor
|
|
298
|
+
.requiresCredentials({uri: services.hydra})
|
|
299
|
+
.then((response) => assert.isTrue(response)));
|
|
300
|
+
|
|
301
|
+
it('resolves to false if that `addAuthHeader` is set to false', () =>
|
|
302
|
+
interceptor
|
|
303
|
+
.requiresCredentials({
|
|
304
|
+
addAuthHeader: false,
|
|
305
|
+
service: 'unknown',
|
|
306
|
+
resource: 'ping',
|
|
307
|
+
})
|
|
308
|
+
.then((response) => assert.isFalse(response)));
|
|
309
|
+
|
|
310
|
+
it('resolves to false if `validateDomains` is set to false', () => {
|
|
311
|
+
webex.internal.services.validateDomains = false;
|
|
312
|
+
|
|
313
|
+
return interceptor
|
|
314
|
+
.requiresCredentials({
|
|
315
|
+
uri: 'https://allowed-uri.com/resource',
|
|
316
|
+
})
|
|
317
|
+
.then((response) => assert.isFalse(response));
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('resolves to true with an allowed domain uri', () =>
|
|
321
|
+
interceptor
|
|
322
|
+
.requiresCredentials({
|
|
323
|
+
uri: `https://${config.services.allowedDomains[0]}/resource`,
|
|
324
|
+
})
|
|
325
|
+
.then((response) => assert.isTrue(response)));
|
|
326
|
+
|
|
327
|
+
it('resolves to false with a non-allowed uri', () =>
|
|
328
|
+
interceptor
|
|
329
|
+
.requiresCredentials({
|
|
330
|
+
uri: 'https://not-allowed/resource',
|
|
331
|
+
})
|
|
332
|
+
.then((response) => assert.isFalse(response)));
|
|
333
|
+
|
|
334
|
+
it('should return true if domain exists using isAllowedDomainUrl()', () => {
|
|
335
|
+
webex.internal.services.waitForService = sinon.stub();
|
|
336
|
+
const {isAllowedDomainUrl} = webex.internal.services;
|
|
337
|
+
|
|
338
|
+
const result = isAllowedDomainUrl(
|
|
339
|
+
`https://${config.services.allowedDomains[0]}/resource`
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
assert.equal(result, true);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('should return true when called `requiresCredentials` with valid url', () => {
|
|
346
|
+
webex.internal.services.waitForService = sinon.stub();
|
|
347
|
+
|
|
348
|
+
return interceptor
|
|
349
|
+
.requiresCredentials({
|
|
350
|
+
uri: `https://${config.services.allowedDomains[0]}/resource`,
|
|
351
|
+
})
|
|
352
|
+
.then((res) => {
|
|
353
|
+
assert.equal(res, true);
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('should call waitForService()', () => {
|
|
358
|
+
webex.internal.services.waitForService = sinon.stub();
|
|
359
|
+
const {waitForService} = webex.internal.services;
|
|
360
|
+
|
|
361
|
+
waitForService.resolves(`https://${config.services.allowedDomains[0]}/resource`);
|
|
362
|
+
|
|
363
|
+
return interceptor
|
|
364
|
+
.requiresCredentials({
|
|
365
|
+
service: 'locus',
|
|
366
|
+
})
|
|
367
|
+
.then(() => assert.calledOnce(waitForService));
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
describe('#onResponseError()', () => {
|
|
372
|
+
describe('when the server responds with 401', () => {
|
|
373
|
+
nodeOnly(it)('refreshes the access token and replays the request', () => {
|
|
374
|
+
webex.request.onCall(0).returns(
|
|
375
|
+
Promise.resolve({
|
|
376
|
+
body: {
|
|
377
|
+
access_token: 'ST2',
|
|
378
|
+
},
|
|
379
|
+
})
|
|
380
|
+
);
|
|
381
|
+
webex.credentials.supertoken = new Token(
|
|
382
|
+
{
|
|
383
|
+
access_token: 'ST1',
|
|
384
|
+
refresh_token: 'RT1',
|
|
385
|
+
},
|
|
386
|
+
{parent: webex}
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
const err = new WebexHttpError.Unauthorized({
|
|
390
|
+
statusCode: 401,
|
|
391
|
+
options: {
|
|
392
|
+
headers: {
|
|
393
|
+
trackingid: 'blarg',
|
|
394
|
+
},
|
|
395
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
396
|
+
},
|
|
397
|
+
body: {
|
|
398
|
+
error: 'fake error',
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
assert.notCalled(webex.request);
|
|
403
|
+
|
|
404
|
+
return interceptor.onResponseError(err.options, err).then(() => {
|
|
405
|
+
// once for refresh, once for replay
|
|
406
|
+
assert.calledTwice(webex.request);
|
|
407
|
+
assert.equal(webex.credentials.supertoken.access_token, 'ST2');
|
|
408
|
+
assert.equal(webex.request.args[1][0].replayCount, 1);
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
browserOnly(it)('refreshes the access token and replays the request', () => {
|
|
413
|
+
webex.config.credentials.refreshCallback = sinon.stub().returns(
|
|
414
|
+
Promise.resolve({
|
|
415
|
+
access_token: 'ST2',
|
|
416
|
+
})
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
webex.credentials.supertoken = new Token(
|
|
420
|
+
{
|
|
421
|
+
access_token: 'ST1',
|
|
422
|
+
refresh_token: 'RT1',
|
|
423
|
+
},
|
|
424
|
+
{parent: webex}
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
const err = new WebexHttpError.Unauthorized({
|
|
428
|
+
statusCode: 401,
|
|
429
|
+
options: {
|
|
430
|
+
headers: {
|
|
431
|
+
trackingid: 'blarg',
|
|
432
|
+
},
|
|
433
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
434
|
+
},
|
|
435
|
+
body: {
|
|
436
|
+
error: 'fake error',
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
assert.notCalled(webex.request);
|
|
441
|
+
|
|
442
|
+
return interceptor.onResponseError(err.options, err).then(() => {
|
|
443
|
+
// once for replay
|
|
444
|
+
assert.calledOnce(webex.request);
|
|
445
|
+
assert.equal(webex.credentials.supertoken.access_token, 'ST2');
|
|
446
|
+
assert.equal(webex.request.args[0][0].replayCount, 1);
|
|
447
|
+
});
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
describe('when the access token is not refreshable', () => {
|
|
451
|
+
it('responds with the original error', () => {
|
|
452
|
+
webex.credentials.supertoken = new Token(
|
|
453
|
+
{
|
|
454
|
+
access_token: 'ST1',
|
|
455
|
+
},
|
|
456
|
+
{parent: webex}
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
const err = new WebexHttpError.Unauthorized({
|
|
460
|
+
statusCode: 401,
|
|
461
|
+
options: {
|
|
462
|
+
headers: {
|
|
463
|
+
trackingid: 'blarg',
|
|
464
|
+
},
|
|
465
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
466
|
+
},
|
|
467
|
+
body: {
|
|
468
|
+
error: 'fake error',
|
|
469
|
+
},
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
assert.notCalled(webex.request);
|
|
473
|
+
|
|
474
|
+
return assert
|
|
475
|
+
.isRejected(interceptor.onResponseError(err.options, err))
|
|
476
|
+
.then((err2) => {
|
|
477
|
+
assert.equal(err2, err);
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it('does not refresh if shouldRefreshAccessToken was false', () => {
|
|
483
|
+
webex.config.credentials.refreshCallback = sinon.stub().returns(
|
|
484
|
+
Promise.resolve({
|
|
485
|
+
access_token: 'ST2',
|
|
486
|
+
})
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
webex.credentials.supertoken = new Token(
|
|
490
|
+
{
|
|
491
|
+
access_token: 'ST1',
|
|
492
|
+
refresh_token: 'RT1',
|
|
493
|
+
},
|
|
494
|
+
{parent: webex}
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
const err = new WebexHttpError.Unauthorized({
|
|
498
|
+
statusCode: 401,
|
|
499
|
+
options: {
|
|
500
|
+
headers: {
|
|
501
|
+
trackingid: 'blarg',
|
|
502
|
+
},
|
|
503
|
+
uri: `${config.services.discovery.hydra}/ping`,
|
|
504
|
+
shouldRefreshAccessToken: false,
|
|
505
|
+
},
|
|
506
|
+
body: {
|
|
507
|
+
error: 'fake error',
|
|
508
|
+
},
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
assert.notCalled(webex.request);
|
|
512
|
+
|
|
513
|
+
return assert.isRejected(interceptor.onResponseError(err.options, err)).then((err2) => {
|
|
514
|
+
assert.equal(err2, err);
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
});
|
|
521
|
+
});
|