samlesa 2.13.0 → 2.14.1

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.

Potentially problematic release.


This version of samlesa might be problematic. Click here for more details.

Files changed (149) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +36 -65
  3. package/build/.idea/deployment.xml +14 -0
  4. package/{src → build}/.idea/modules.xml +1 -1
  5. package/build/.idea/workspace.xml +57 -0
  6. package/build/index.js +18 -54
  7. package/build/index.js.map +1 -1
  8. package/build/src/api.js +18 -24
  9. package/build/src/api.js.map +1 -1
  10. package/build/src/binding-post.js +337 -365
  11. package/build/src/binding-post.js.map +1 -1
  12. package/build/src/binding-redirect.js +312 -340
  13. package/build/src/binding-redirect.js.map +1 -1
  14. package/build/src/binding-simplesign.js +201 -229
  15. package/build/src/binding-simplesign.js.map +1 -1
  16. package/build/src/entity-idp.js +119 -127
  17. package/build/src/entity-idp.js.map +1 -1
  18. package/build/src/entity-sp.js +88 -96
  19. package/build/src/entity-sp.js.map +1 -1
  20. package/build/src/entity.js +193 -225
  21. package/build/src/entity.js.map +1 -1
  22. package/build/src/extractor.js +361 -369
  23. package/build/src/extractor.js.map +1 -1
  24. package/build/src/flow.js +313 -320
  25. package/build/src/flow.js.map +1 -1
  26. package/build/src/libsaml.js +693 -721
  27. package/build/src/libsaml.js.map +1 -1
  28. package/build/src/metadata-idp.js +119 -127
  29. package/build/src/metadata-idp.js.map +1 -1
  30. package/build/src/metadata-sp.js +223 -231
  31. package/build/src/metadata-sp.js.map +1 -1
  32. package/build/src/metadata.js +138 -166
  33. package/build/src/metadata.js.map +1 -1
  34. package/build/src/types.js +4 -11
  35. package/build/src/types.js.map +1 -1
  36. package/build/src/urn.js +204 -212
  37. package/build/src/urn.js.map +1 -1
  38. package/build/src/utility.js +277 -292
  39. package/build/src/utility.js.map +1 -1
  40. package/build/src/validator.js +24 -27
  41. package/build/src/validator.js.map +1 -1
  42. package/package.json +19 -14
  43. package/types/api.d.ts +15 -0
  44. package/types/api.d.ts.map +1 -0
  45. package/types/binding-post.d.ts +48 -0
  46. package/types/binding-post.d.ts.map +1 -0
  47. package/types/binding-redirect.d.ts +54 -0
  48. package/types/binding-redirect.d.ts.map +1 -0
  49. package/types/binding-simplesign.d.ts +41 -0
  50. package/types/binding-simplesign.d.ts.map +1 -0
  51. package/types/entity-idp.d.ts +38 -0
  52. package/types/entity-idp.d.ts.map +1 -0
  53. package/types/entity-sp.d.ts +38 -0
  54. package/types/entity-sp.d.ts.map +1 -0
  55. package/types/entity.d.ts +100 -0
  56. package/types/entity.d.ts.map +1 -0
  57. package/types/extractor.d.ts +26 -0
  58. package/types/extractor.d.ts.map +1 -0
  59. package/types/flow.d.ts +7 -0
  60. package/types/flow.d.ts.map +1 -0
  61. package/types/index.d.ts +11 -10
  62. package/types/index.d.ts.map +1 -0
  63. package/types/libsaml.d.ts +208 -0
  64. package/types/libsaml.d.ts.map +1 -0
  65. package/types/metadata-idp.d.ts +25 -0
  66. package/types/metadata-idp.d.ts.map +1 -0
  67. package/types/metadata-sp.d.ts +37 -0
  68. package/types/metadata-sp.d.ts.map +1 -0
  69. package/types/metadata.d.ts +58 -0
  70. package/types/metadata.d.ts.map +1 -0
  71. package/types/src/api.d.ts +15 -13
  72. package/types/src/api.d.ts.map +1 -0
  73. package/types/src/binding-post.d.ts +48 -47
  74. package/types/src/binding-post.d.ts.map +1 -0
  75. package/types/src/binding-redirect.d.ts +54 -53
  76. package/types/src/binding-redirect.d.ts.map +1 -0
  77. package/types/src/binding-simplesign.d.ts +41 -40
  78. package/types/src/binding-simplesign.d.ts.map +1 -0
  79. package/types/src/entity-idp.d.ts +38 -37
  80. package/types/src/entity-idp.d.ts.map +1 -0
  81. package/types/src/entity-sp.d.ts +38 -36
  82. package/types/src/entity-sp.d.ts.map +1 -0
  83. package/types/src/entity.d.ts +100 -101
  84. package/types/src/entity.d.ts.map +1 -0
  85. package/types/src/extractor.d.ts +26 -25
  86. package/types/src/extractor.d.ts.map +1 -0
  87. package/types/src/flow.d.ts +7 -6
  88. package/types/src/flow.d.ts.map +1 -0
  89. package/types/src/libsaml.d.ts +208 -209
  90. package/types/src/libsaml.d.ts.map +1 -0
  91. package/types/src/metadata-idp.d.ts +25 -24
  92. package/types/src/metadata-idp.d.ts.map +1 -0
  93. package/types/src/metadata-sp.d.ts +37 -36
  94. package/types/src/metadata-sp.d.ts.map +1 -0
  95. package/types/src/metadata.d.ts +58 -59
  96. package/types/src/metadata.d.ts.map +1 -0
  97. package/types/src/types.d.ts +128 -129
  98. package/types/src/types.d.ts.map +1 -0
  99. package/types/src/urn.d.ts +195 -194
  100. package/types/src/urn.d.ts.map +1 -0
  101. package/types/src/utility.d.ts +133 -134
  102. package/types/src/utility.d.ts.map +1 -0
  103. package/types/src/validator.d.ts +4 -3
  104. package/types/src/validator.d.ts.map +1 -0
  105. package/types/types.d.ts +128 -0
  106. package/types/types.d.ts.map +1 -0
  107. package/types/urn.d.ts +195 -0
  108. package/types/urn.d.ts.map +1 -0
  109. package/types/utility.d.ts +133 -0
  110. package/types/utility.d.ts.map +1 -0
  111. package/types/validator.d.ts +4 -0
  112. package/types/validator.d.ts.map +1 -0
  113. package/.editorconfig +0 -19
  114. package/.github/FUNDING.yml +0 -1
  115. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  116. package/.idea/modules.xml +0 -8
  117. package/.idea/vcs.xml +0 -6
  118. package/.pre-commit.sh +0 -15
  119. package/.snyk +0 -8
  120. package/.travis.yml +0 -29
  121. package/Makefile +0 -25
  122. package/index.d.ts +0 -10
  123. package/index.js +0 -19
  124. package/index.js.map +0 -1
  125. package/index.ts +0 -28
  126. package/qodana.yaml +0 -29
  127. package/src/.idea/src.iml +0 -12
  128. package/src/.idea/vcs.xml +0 -6
  129. package/src/api.ts +0 -36
  130. package/src/binding-post.ts +0 -348
  131. package/src/binding-redirect.ts +0 -356
  132. package/src/binding-simplesign.ts +0 -238
  133. package/src/entity-idp.ts +0 -153
  134. package/src/entity-sp.ts +0 -114
  135. package/src/entity.ts +0 -243
  136. package/src/extractor.ts +0 -392
  137. package/src/flow.ts +0 -467
  138. package/src/libsaml.ts +0 -895
  139. package/src/metadata-idp.ts +0 -146
  140. package/src/metadata-sp.ts +0 -268
  141. package/src/metadata.ts +0 -166
  142. package/src/types.ts +0 -153
  143. package/src/urn.ts +0 -211
  144. package/src/utility.ts +0 -319
  145. package/src/validator.ts +0 -39
  146. package/tsconfig.json +0 -38
  147. package/tslint.json +0 -35
  148. package/types.d.ts +0 -2
  149. /package/{.idea/samlify.iml → build/.idea/build.iml} +0 -0
@@ -1,370 +1,362 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.extract = exports.logoutResponseFields = exports.logoutRequestFields = exports.loginResponseFields = exports.logoutResponseStatusFields = exports.loginResponseStatusFields = exports.loginRequestFields = void 0;
7
- const xpath_1 = require("xpath");
8
- const utility_js_1 = require("./utility.js");
9
- const api_js_1 = require("./api.js");
10
- const camelcase_1 = __importDefault(require("camelcase"));
11
- function buildAbsoluteXPath(paths) {
12
- return paths.reduce((currentPath, name) => {
13
- let appendedPath = currentPath;
14
- const isWildcard = name.startsWith('~');
15
- if (isWildcard) {
16
- const pathName = name.replace('~', '');
17
- appendedPath = currentPath + `/*[contains(local-name(), '${pathName}')]`;
18
- }
19
- if (!isWildcard) {
20
- appendedPath = currentPath + `/*[local-name(.)='${name}']`;
21
- }
22
- return appendedPath;
23
- }, '');
24
- }
25
- function buildAttributeXPath(attributes) {
26
- if (attributes.length === 0) {
27
- return '/text()';
28
- }
29
- if (attributes.length === 1) {
30
- return `/@${attributes[0]}`;
31
- }
32
- const filters = attributes.map(attribute => `name()='${attribute}'`).join(' or ');
33
- return `/@*[${filters}]`;
34
- }
35
- exports.loginRequestFields = [
36
- {
37
- key: 'request',
38
- localPath: ['AuthnRequest'],
39
- attributes: ['ID', 'IssueInstant', 'Destination', 'AssertionConsumerServiceURL', 'ProtocolBinding', 'ForceAuthn', 'IsPassive', 'AssertionConsumerServiceIndex', 'AttributeConsumingServiceIndex']
40
- },
41
- {
42
- key: 'issuer',
43
- localPath: ['AuthnRequest', 'Issuer'],
44
- attributes: []
45
- },
46
- {
47
- key: 'nameIDPolicy',
48
- localPath: ['AuthnRequest', 'NameIDPolicy'],
49
- attributes: ['Format', 'AllowCreate']
50
- },
51
- {
52
- key: 'authnContextClassRef',
53
- localPath: ['AuthnRequest', 'AuthnContextClassRef'],
54
- attributes: []
55
- },
56
- {
57
- key: 'signature',
58
- localPath: ['AuthnRequest', 'Signature'],
59
- attributes: [],
60
- context: true
61
- }
62
- ];
63
- // support two-tiers status code
64
- exports.loginResponseStatusFields = [
65
- {
66
- key: 'top',
67
- localPath: ['Response', 'Status', 'StatusCode'],
68
- attributes: ['Value'],
69
- },
70
- {
71
- key: 'second',
72
- localPath: ['Response', 'Status', 'StatusCode', 'StatusCode'],
73
- attributes: ['Value'],
74
- }
75
- ];
76
- // support two-tiers status code
77
- exports.logoutResponseStatusFields = [
78
- {
79
- key: 'top',
80
- localPath: ['LogoutResponse', 'Status', 'StatusCode'],
81
- attributes: ['Value']
82
- },
83
- {
84
- key: 'second',
85
- localPath: ['LogoutResponse', 'Status', 'StatusCode', 'StatusCode'],
86
- attributes: ['Value'],
87
- }
88
- ];
89
- const loginResponseFields = assertion => [
90
- {
91
- key: 'conditions',
92
- localPath: ['Assertion', 'Conditions'],
93
- attributes: ['NotBefore', 'NotOnOrAfter'],
94
- shortcut: assertion
95
- },
96
- {
97
- key: 'response',
98
- localPath: ['Response'],
99
- attributes: ['ID', 'IssueInstant', 'Destination', 'InResponseTo'],
100
- },
101
- {
102
- key: 'audience',
103
- localPath: ['Assertion', 'Conditions', 'AudienceRestriction', 'Audience'],
104
- attributes: [],
105
- shortcut: assertion
106
- },
107
- // {
108
- // key: 'issuer',
109
- // localPath: ['Response', 'Issuer'],
110
- // attributes: []
111
- // },
112
- {
113
- key: 'issuer',
114
- localPath: ['Assertion', 'Issuer'],
115
- attributes: [],
116
- shortcut: assertion
117
- },
118
- {
119
- key: 'nameID',
120
- localPath: ['Assertion', 'Subject', 'NameID'],
121
- attributes: [],
122
- shortcut: assertion
123
- },
124
- {
125
- key: 'sessionIndex',
126
- localPath: ['Assertion', 'AuthnStatement'],
127
- attributes: ['AuthnInstant', 'SessionNotOnOrAfter', 'SessionIndex'],
128
- shortcut: assertion
129
- },
130
- {
131
- key: 'attributes',
132
- localPath: ['Assertion', 'AttributeStatement', 'Attribute'],
133
- index: ['Name'],
134
- attributePath: ['AttributeValue'],
135
- attributes: [],
136
- shortcut: assertion
137
- }
138
- ];
139
- exports.loginResponseFields = loginResponseFields;
140
- exports.logoutRequestFields = [
141
- {
142
- key: 'request',
143
- localPath: ['LogoutRequest'],
144
- attributes: ['ID', 'IssueInstant', 'Destination']
145
- },
146
- {
147
- key: 'issuer',
148
- localPath: ['LogoutRequest', 'Issuer'],
149
- attributes: []
150
- },
151
- {
152
- key: 'nameID',
153
- localPath: ['LogoutRequest', 'NameID'],
154
- attributes: []
155
- },
156
- {
157
- key: 'sessionIndex',
158
- localPath: ['LogoutRequest', 'SessionIndex'],
159
- attributes: []
160
- },
161
- {
162
- key: 'signature',
163
- localPath: ['LogoutRequest', 'Signature'],
164
- attributes: [],
165
- context: true
166
- }
167
- ];
168
- exports.logoutResponseFields = [
169
- {
170
- key: 'response',
171
- localPath: ['LogoutResponse'],
172
- attributes: ['ID', 'Destination', 'InResponseTo']
173
- },
174
- {
175
- key: 'issuer',
176
- localPath: ['LogoutResponse', 'Issuer'],
177
- attributes: []
178
- },
179
- {
180
- key: 'signature',
181
- localPath: ['LogoutResponse', 'Signature'],
182
- attributes: [],
183
- context: true
184
- }
185
- ];
186
- function extract(context, fields) {
187
- const { dom } = (0, api_js_1.getContext)();
188
- const rootDoc = dom.parseFromString(context);
189
- return fields.reduce((result, field) => {
190
- // get essential fields
191
- const key = field.key;
192
- const localPath = field.localPath;
193
- const attributes = field.attributes;
194
- const isEntire = field.context;
195
- const shortcut = field.shortcut;
196
- // get optional fields
197
- const index = field.index;
198
- const attributePath = field.attributePath;
199
- // set allowing overriding if there is a shortcut injected
200
- let targetDoc = rootDoc;
201
- // if shortcut is used, then replace the doc
202
- // it's a design for overriding the doc used during runtime
203
- if (shortcut) {
204
- targetDoc = dom.parseFromString(shortcut);
205
- }
206
- // special case: multiple path
207
- /*
208
- {
209
- key: 'issuer',
210
- localPath: [
211
- ['Response', 'Issuer'],
212
- ['Response', 'Assertion', 'Issuer']
213
- ],
214
- attributes: []
215
- }
216
- */
217
- if (localPath.every(path => Array.isArray(path))) {
218
- const multiXPaths = localPath
219
- .map(path => {
220
- // not support attribute yet, so ignore it
221
- return `${buildAbsoluteXPath(path)}/text()`;
222
- })
223
- .join(' | ');
224
- return {
225
- ...result,
226
- [key]: (0, utility_js_1.uniq)((0, xpath_1.select)(multiXPaths, targetDoc).map((n) => n.nodeValue).filter(utility_js_1.notEmpty))
227
- };
228
- }
229
- // eo special case: multiple path
230
- const baseXPath = buildAbsoluteXPath(localPath);
231
- const attributeXPath = buildAttributeXPath(attributes);
232
- // special case: get attributes where some are in child, some are in parent
233
- /*
234
- {
235
- key: 'attributes',
236
- localPath: ['Response', 'Assertion', 'AttributeStatement', 'Attribute'],
237
- index: ['Name'],
238
- attributePath: ['AttributeValue'],
239
- attributes: []
240
- }
241
- */
242
- if (index && attributePath) {
243
- // find the index in localpath
244
- const indexPath = buildAttributeXPath(index);
245
- const fullLocalXPath = `${baseXPath}${indexPath}`;
246
- const parentNodes = (0, xpath_1.select)(baseXPath, targetDoc);
247
- // [uid, mail, edupersonaffiliation], ready for aggregate
248
- const parentAttributes = (0, xpath_1.select)(fullLocalXPath, targetDoc).map((n) => n.value);
249
- // [attribute, attributevalue]
250
- const childXPath = buildAbsoluteXPath([(0, utility_js_1.last)(localPath)].concat(attributePath));
251
- const childAttributeXPath = buildAttributeXPath(attributes);
252
- const fullChildXPath = `${childXPath}${childAttributeXPath}`;
253
- // [ 'test', 'test@example.com', [ 'users', 'examplerole1' ] ]
254
- const childAttributes = parentNodes.map(node => {
255
- const nodeDoc = dom.parseFromString(node.toString());
256
- if (attributes.length === 0) {
257
- const childValues = (0, xpath_1.select)(fullChildXPath, nodeDoc).map((n) => n.nodeValue);
258
- if (childValues.length === 1) {
259
- return childValues[0];
260
- }
261
- return childValues;
262
- }
263
- if (attributes.length > 0) {
264
- const childValues = (0, xpath_1.select)(fullChildXPath, nodeDoc).map((n) => n.value);
265
- if (childValues.length === 1) {
266
- return childValues[0];
267
- }
268
- return childValues;
269
- }
270
- return null;
271
- });
272
- // aggregation
273
- const obj = (0, utility_js_1.zipObject)(parentAttributes, childAttributes, false);
274
- return {
275
- ...result,
276
- [key]: obj
277
- };
278
- }
279
- // case: fetch entire content, only allow one existence
280
- /*
281
- {
282
- key: 'signature',
283
- localPath: ['AuthnRequest', 'Signature'],
284
- attributes: [],
285
- context: true
286
- }
287
- */
288
- if (isEntire) {
289
- const node = (0, xpath_1.select)(baseXPath, targetDoc);
290
- let value = null;
291
- if (node.length === 1) {
292
- value = node[0].toString();
293
- }
294
- if (node.length > 1) {
295
- value = node.map(n => n.toString());
296
- }
297
- return {
298
- ...result,
299
- [key]: value
300
- };
301
- }
302
- // case: multiple attribute
303
- /*
304
- {
305
- key: 'nameIDPolicy',
306
- localPath: ['AuthnRequest', 'NameIDPolicy'],
307
- attributes: ['Format', 'AllowCreate']
308
- }
309
- */
310
- if (attributes.length > 1) {
311
- const baseNode = (0, xpath_1.select)(baseXPath, targetDoc).map(n => n.toString());
312
- const childXPath = `${buildAbsoluteXPath([(0, utility_js_1.last)(localPath)])}${attributeXPath}`;
313
- const attributeValues = baseNode.map((node) => {
314
- const nodeDoc = dom.parseFromString(node);
315
- const values = (0, xpath_1.select)(childXPath, nodeDoc).reduce((r, n) => {
316
- r[(0, camelcase_1.default)(n.name, { locale: 'en-us' })] = n.value;
317
- return r;
318
- }, {});
319
- return values;
320
- });
321
- return {
322
- ...result,
323
- [key]: attributeValues.length === 1 ? attributeValues[0] : attributeValues
324
- };
325
- }
326
- // case: single attribute
327
- /*
328
- {
329
- key: 'statusCode',
330
- localPath: ['Response', 'Status', 'StatusCode'],
331
- attributes: ['Value'],
332
- }
333
- */
334
- if (attributes.length === 1) {
335
- const fullPath = `${baseXPath}${attributeXPath}`;
336
- const attributeValues = (0, xpath_1.select)(fullPath, targetDoc).map((n) => n.value);
337
- return {
338
- ...result,
339
- [key]: attributeValues[0]
340
- };
341
- }
342
- // case: zero attribute
343
- /*
344
- {
345
- key: 'issuer',
346
- localPath: ['AuthnRequest', 'Issuer'],
347
- attributes: []
348
- }
349
- */
350
- if (attributes.length === 0) {
351
- let attributeValue = null;
352
- const node = (0, xpath_1.select)(baseXPath, targetDoc);
353
- if (node.length === 1) {
354
- const fullPath = `string(${baseXPath}${attributeXPath})`;
355
- attributeValue = (0, xpath_1.select)(fullPath, targetDoc);
356
- }
357
- if (node.length > 1) {
358
- attributeValue = node.filter((n) => n.firstChild)
359
- .map((n) => n.firstChild.nodeValue);
360
- }
361
- return {
362
- ...result,
363
- [key]: attributeValue
364
- };
365
- }
366
- return result;
367
- }, {});
368
- }
369
- exports.extract = extract;
1
+ import { select } from 'xpath';
2
+ import { uniq, last, zipObject, notEmpty } from './utility.js';
3
+ import { getContext } from './api.js';
4
+ import camelCase from 'camelcase';
5
+ function buildAbsoluteXPath(paths) {
6
+ return paths.reduce((currentPath, name) => {
7
+ let appendedPath = currentPath;
8
+ const isWildcard = name.startsWith('~');
9
+ if (isWildcard) {
10
+ const pathName = name.replace('~', '');
11
+ appendedPath = currentPath + `/*[contains(local-name(), '${pathName}')]`;
12
+ }
13
+ if (!isWildcard) {
14
+ appendedPath = currentPath + `/*[local-name(.)='${name}']`;
15
+ }
16
+ return appendedPath;
17
+ }, '');
18
+ }
19
+ function buildAttributeXPath(attributes) {
20
+ if (attributes.length === 0) {
21
+ return '/text()';
22
+ }
23
+ if (attributes.length === 1) {
24
+ return `/@${attributes[0]}`;
25
+ }
26
+ const filters = attributes.map(attribute => `name()='${attribute}'`).join(' or ');
27
+ return `/@*[${filters}]`;
28
+ }
29
+ export const loginRequestFields = [
30
+ {
31
+ key: 'request',
32
+ localPath: ['AuthnRequest'],
33
+ attributes: ['ID', 'IssueInstant', 'Destination', 'AssertionConsumerServiceURL', 'ProtocolBinding', 'ForceAuthn', 'IsPassive', 'AssertionConsumerServiceIndex', 'AttributeConsumingServiceIndex']
34
+ },
35
+ {
36
+ key: 'issuer',
37
+ localPath: ['AuthnRequest', 'Issuer'],
38
+ attributes: []
39
+ },
40
+ {
41
+ key: 'nameIDPolicy',
42
+ localPath: ['AuthnRequest', 'NameIDPolicy'],
43
+ attributes: ['Format', 'AllowCreate']
44
+ },
45
+ {
46
+ key: 'authnContextClassRef',
47
+ localPath: ['AuthnRequest', 'AuthnContextClassRef'],
48
+ attributes: []
49
+ },
50
+ {
51
+ key: 'signature',
52
+ localPath: ['AuthnRequest', 'Signature'],
53
+ attributes: [],
54
+ context: true
55
+ }
56
+ ];
57
+ // support two-tiers status code
58
+ export const loginResponseStatusFields = [
59
+ {
60
+ key: 'top',
61
+ localPath: ['Response', 'Status', 'StatusCode'],
62
+ attributes: ['Value'],
63
+ },
64
+ {
65
+ key: 'second',
66
+ localPath: ['Response', 'Status', 'StatusCode', 'StatusCode'],
67
+ attributes: ['Value'],
68
+ }
69
+ ];
70
+ // support two-tiers status code
71
+ export const logoutResponseStatusFields = [
72
+ {
73
+ key: 'top',
74
+ localPath: ['LogoutResponse', 'Status', 'StatusCode'],
75
+ attributes: ['Value']
76
+ },
77
+ {
78
+ key: 'second',
79
+ localPath: ['LogoutResponse', 'Status', 'StatusCode', 'StatusCode'],
80
+ attributes: ['Value'],
81
+ }
82
+ ];
83
+ export const loginResponseFields = assertion => [
84
+ {
85
+ key: 'conditions',
86
+ localPath: ['Assertion', 'Conditions'],
87
+ attributes: ['NotBefore', 'NotOnOrAfter'],
88
+ shortcut: assertion
89
+ },
90
+ {
91
+ key: 'response',
92
+ localPath: ['Response'],
93
+ attributes: ['ID', 'IssueInstant', 'Destination', 'InResponseTo'],
94
+ },
95
+ {
96
+ key: 'audience',
97
+ localPath: ['Assertion', 'Conditions', 'AudienceRestriction', 'Audience'],
98
+ attributes: [],
99
+ shortcut: assertion
100
+ },
101
+ // {
102
+ // key: 'issuer',
103
+ // localPath: ['Response', 'Issuer'],
104
+ // attributes: []
105
+ // },
106
+ {
107
+ key: 'issuer',
108
+ localPath: ['Assertion', 'Issuer'],
109
+ attributes: [],
110
+ shortcut: assertion
111
+ },
112
+ {
113
+ key: 'nameID',
114
+ localPath: ['Assertion', 'Subject', 'NameID'],
115
+ attributes: [],
116
+ shortcut: assertion
117
+ },
118
+ {
119
+ key: 'sessionIndex',
120
+ localPath: ['Assertion', 'AuthnStatement'],
121
+ attributes: ['AuthnInstant', 'SessionNotOnOrAfter', 'SessionIndex'],
122
+ shortcut: assertion
123
+ },
124
+ {
125
+ key: 'attributes',
126
+ localPath: ['Assertion', 'AttributeStatement', 'Attribute'],
127
+ index: ['Name'],
128
+ attributePath: ['AttributeValue'],
129
+ attributes: [],
130
+ shortcut: assertion
131
+ }
132
+ ];
133
+ export const logoutRequestFields = [
134
+ {
135
+ key: 'request',
136
+ localPath: ['LogoutRequest'],
137
+ attributes: ['ID', 'IssueInstant', 'Destination']
138
+ },
139
+ {
140
+ key: 'issuer',
141
+ localPath: ['LogoutRequest', 'Issuer'],
142
+ attributes: []
143
+ },
144
+ {
145
+ key: 'nameID',
146
+ localPath: ['LogoutRequest', 'NameID'],
147
+ attributes: []
148
+ },
149
+ {
150
+ key: 'sessionIndex',
151
+ localPath: ['LogoutRequest', 'SessionIndex'],
152
+ attributes: []
153
+ },
154
+ {
155
+ key: 'signature',
156
+ localPath: ['LogoutRequest', 'Signature'],
157
+ attributes: [],
158
+ context: true
159
+ }
160
+ ];
161
+ export const logoutResponseFields = [
162
+ {
163
+ key: 'response',
164
+ localPath: ['LogoutResponse'],
165
+ attributes: ['ID', 'Destination', 'InResponseTo']
166
+ },
167
+ {
168
+ key: 'issuer',
169
+ localPath: ['LogoutResponse', 'Issuer'],
170
+ attributes: []
171
+ },
172
+ {
173
+ key: 'signature',
174
+ localPath: ['LogoutResponse', 'Signature'],
175
+ attributes: [],
176
+ context: true
177
+ }
178
+ ];
179
+ export function extract(context, fields) {
180
+ const { dom } = getContext();
181
+ const rootDoc = dom.parseFromString(context);
182
+ return fields.reduce((result, field) => {
183
+ // get essential fields
184
+ const key = field.key;
185
+ const localPath = field.localPath;
186
+ const attributes = field.attributes;
187
+ const isEntire = field.context;
188
+ const shortcut = field.shortcut;
189
+ // get optional fields
190
+ const index = field.index;
191
+ const attributePath = field.attributePath;
192
+ // set allowing overriding if there is a shortcut injected
193
+ let targetDoc = rootDoc;
194
+ // if shortcut is used, then replace the doc
195
+ // it's a design for overriding the doc used during runtime
196
+ if (shortcut) {
197
+ targetDoc = dom.parseFromString(shortcut);
198
+ }
199
+ // special case: multiple path
200
+ /*
201
+ {
202
+ key: 'issuer',
203
+ localPath: [
204
+ ['Response', 'Issuer'],
205
+ ['Response', 'Assertion', 'Issuer']
206
+ ],
207
+ attributes: []
208
+ }
209
+ */
210
+ if (localPath.every(path => Array.isArray(path))) {
211
+ const multiXPaths = localPath
212
+ .map(path => {
213
+ // not support attribute yet, so ignore it
214
+ return `${buildAbsoluteXPath(path)}/text()`;
215
+ })
216
+ .join(' | ');
217
+ return {
218
+ ...result,
219
+ [key]: uniq(select(multiXPaths, targetDoc).map((n) => n.nodeValue).filter(notEmpty))
220
+ };
221
+ }
222
+ // eo special case: multiple path
223
+ const baseXPath = buildAbsoluteXPath(localPath);
224
+ const attributeXPath = buildAttributeXPath(attributes);
225
+ // special case: get attributes where some are in child, some are in parent
226
+ /*
227
+ {
228
+ key: 'attributes',
229
+ localPath: ['Response', 'Assertion', 'AttributeStatement', 'Attribute'],
230
+ index: ['Name'],
231
+ attributePath: ['AttributeValue'],
232
+ attributes: []
233
+ }
234
+ */
235
+ if (index && attributePath) {
236
+ // find the index in localpath
237
+ const indexPath = buildAttributeXPath(index);
238
+ const fullLocalXPath = `${baseXPath}${indexPath}`;
239
+ const parentNodes = select(baseXPath, targetDoc);
240
+ // [uid, mail, edupersonaffiliation], ready for aggregate
241
+ const parentAttributes = select(fullLocalXPath, targetDoc).map((n) => n.value);
242
+ // [attribute, attributevalue]
243
+ const childXPath = buildAbsoluteXPath([last(localPath)].concat(attributePath));
244
+ const childAttributeXPath = buildAttributeXPath(attributes);
245
+ const fullChildXPath = `${childXPath}${childAttributeXPath}`;
246
+ // [ 'test', 'test@example.com', [ 'users', 'examplerole1' ] ]
247
+ const childAttributes = parentNodes.map(node => {
248
+ const nodeDoc = dom.parseFromString(node.toString());
249
+ if (attributes.length === 0) {
250
+ const childValues = select(fullChildXPath, nodeDoc).map((n) => n.nodeValue);
251
+ if (childValues.length === 1) {
252
+ return childValues[0];
253
+ }
254
+ return childValues;
255
+ }
256
+ if (attributes.length > 0) {
257
+ const childValues = select(fullChildXPath, nodeDoc).map((n) => n.value);
258
+ if (childValues.length === 1) {
259
+ return childValues[0];
260
+ }
261
+ return childValues;
262
+ }
263
+ return null;
264
+ });
265
+ // aggregation
266
+ const obj = zipObject(parentAttributes, childAttributes, false);
267
+ return {
268
+ ...result,
269
+ [key]: obj
270
+ };
271
+ }
272
+ // case: fetch entire content, only allow one existence
273
+ /*
274
+ {
275
+ key: 'signature',
276
+ localPath: ['AuthnRequest', 'Signature'],
277
+ attributes: [],
278
+ context: true
279
+ }
280
+ */
281
+ if (isEntire) {
282
+ const node = select(baseXPath, targetDoc);
283
+ let value = null;
284
+ if (node.length === 1) {
285
+ value = node[0].toString();
286
+ }
287
+ if (node.length > 1) {
288
+ value = node.map(n => n.toString());
289
+ }
290
+ return {
291
+ ...result,
292
+ [key]: value
293
+ };
294
+ }
295
+ // case: multiple attribute
296
+ /*
297
+ {
298
+ key: 'nameIDPolicy',
299
+ localPath: ['AuthnRequest', 'NameIDPolicy'],
300
+ attributes: ['Format', 'AllowCreate']
301
+ }
302
+ */
303
+ if (attributes.length > 1) {
304
+ const baseNode = select(baseXPath, targetDoc).map(n => n.toString());
305
+ const childXPath = `${buildAbsoluteXPath([last(localPath)])}${attributeXPath}`;
306
+ const attributeValues = baseNode.map((node) => {
307
+ const nodeDoc = dom.parseFromString(node);
308
+ const values = select(childXPath, nodeDoc).reduce((r, n) => {
309
+ r[camelCase(n.name, { locale: 'en-us' })] = n.value;
310
+ return r;
311
+ }, {});
312
+ return values;
313
+ });
314
+ return {
315
+ ...result,
316
+ [key]: attributeValues.length === 1 ? attributeValues[0] : attributeValues
317
+ };
318
+ }
319
+ // case: single attribute
320
+ /*
321
+ {
322
+ key: 'statusCode',
323
+ localPath: ['Response', 'Status', 'StatusCode'],
324
+ attributes: ['Value'],
325
+ }
326
+ */
327
+ if (attributes.length === 1) {
328
+ const fullPath = `${baseXPath}${attributeXPath}`;
329
+ const attributeValues = select(fullPath, targetDoc).map((n) => n.value);
330
+ return {
331
+ ...result,
332
+ [key]: attributeValues[0]
333
+ };
334
+ }
335
+ // case: zero attribute
336
+ /*
337
+ {
338
+ key: 'issuer',
339
+ localPath: ['AuthnRequest', 'Issuer'],
340
+ attributes: []
341
+ }
342
+ */
343
+ if (attributes.length === 0) {
344
+ let attributeValue = null;
345
+ const node = select(baseXPath, targetDoc);
346
+ if (node.length === 1) {
347
+ const fullPath = `string(${baseXPath}${attributeXPath})`;
348
+ attributeValue = select(fullPath, targetDoc);
349
+ }
350
+ if (node.length > 1) {
351
+ attributeValue = node.filter((n) => n.firstChild)
352
+ .map((n) => n.firstChild.nodeValue);
353
+ }
354
+ return {
355
+ ...result,
356
+ [key]: attributeValue
357
+ };
358
+ }
359
+ return result;
360
+ }, {});
361
+ }
370
362
  //# sourceMappingURL=extractor.js.map