samlesa 2.16.6 → 2.17.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.
- package/README.md +30 -50
- package/build/index.js +2 -1
- package/build/src/binding-artifact.js +330 -146
- package/build/src/binding-post.js +45 -31
- package/build/src/binding-redirect.js +0 -10
- package/build/src/binding-simplesign.js +0 -1
- package/build/src/entity-idp.js +1 -5
- package/build/src/entity-sp.js +21 -96
- package/build/src/extractor.js +48 -4
- package/build/src/flow.js +24 -166
- package/build/src/libsaml.js +468 -264
- package/build/src/libsamlSoap.js +115 -0
- package/build/src/schema/xml.xsd +88 -88
- package/build/src/schemaValidator.js +5 -13
- package/build/src/soap.js +123 -3
- package/build/src/utility.js +12 -7
- package/package.json +77 -81
- package/types/api.d.ts +15 -0
- package/types/api.d.ts.map +1 -0
- package/types/binding-post.d.ts +48 -0
- package/types/binding-post.d.ts.map +1 -0
- package/types/binding-redirect.d.ts +54 -0
- package/types/binding-redirect.d.ts.map +1 -0
- package/types/binding-simplesign.d.ts +41 -0
- package/types/binding-simplesign.d.ts.map +1 -0
- package/types/entity-idp.d.ts +38 -0
- package/types/entity-idp.d.ts.map +1 -0
- package/types/entity-sp.d.ts +38 -0
- package/types/entity-sp.d.ts.map +1 -0
- package/types/entity.d.ts +100 -0
- package/types/entity.d.ts.map +1 -0
- package/types/extractor.d.ts +26 -0
- package/types/extractor.d.ts.map +1 -0
- package/types/flow.d.ts +7 -0
- package/types/flow.d.ts.map +1 -0
- package/types/index.d.ts +2 -1
- package/types/index.d.ts.map +1 -1
- package/types/libsaml.d.ts +208 -0
- package/types/libsaml.d.ts.map +1 -0
- package/types/metadata-idp.d.ts +25 -0
- package/types/metadata-idp.d.ts.map +1 -0
- package/types/metadata-sp.d.ts +37 -0
- package/types/metadata-sp.d.ts.map +1 -0
- package/types/metadata.d.ts +58 -0
- package/types/metadata.d.ts.map +1 -0
- package/types/src/api.d.ts +3 -3
- package/types/src/api.d.ts.map +1 -1
- package/types/src/binding-artifact.d.ts +24 -29
- package/types/src/binding-artifact.d.ts.map +1 -1
- package/types/src/binding-post.d.ts +22 -22
- package/types/src/binding-post.d.ts.map +1 -1
- package/types/src/binding-redirect.d.ts.map +1 -1
- package/types/src/binding-simplesign.d.ts.map +1 -1
- package/types/src/entity-idp.d.ts +3 -4
- package/types/src/entity-idp.d.ts.map +1 -1
- package/types/src/entity-sp.d.ts +13 -24
- package/types/src/entity-sp.d.ts.map +1 -1
- package/types/src/entity.d.ts.map +1 -1
- package/types/src/extractor.d.ts +22 -0
- package/types/src/extractor.d.ts.map +1 -1
- package/types/src/flow.d.ts +1 -0
- package/types/src/flow.d.ts.map +1 -1
- package/types/src/libsaml.d.ts +16 -7
- package/types/src/libsaml.d.ts.map +1 -1
- package/types/src/libsamlSoap.d.ts +7 -0
- package/types/src/libsamlSoap.d.ts.map +1 -0
- package/types/src/schemaValidator.d.ts +1 -1
- package/types/src/schemaValidator.d.ts.map +1 -1
- package/types/src/soap.d.ts +33 -0
- package/types/src/soap.d.ts.map +1 -1
- package/types/src/utility.d.ts.map +1 -1
- package/types/src/validator.d.ts.map +1 -1
- package/types/types.d.ts +128 -0
- package/types/types.d.ts.map +1 -0
- package/types/urn.d.ts +195 -0
- package/types/urn.d.ts.map +1 -0
- package/types/utility.d.ts +133 -0
- package/types/utility.d.ts.map +1 -0
- package/types/validator.d.ts +4 -0
- package/types/validator.d.ts.map +1 -0
- package/build/src/schema/XMLSchema.dtd +0 -402
- package/build/src/schema/datatypes.dtd +0 -203
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file binding-post.ts
|
|
3
|
-
* @author tngan
|
|
4
|
-
* @desc Binding-level API, declare the functions using POST binding
|
|
5
|
-
*/
|
|
2
|
+
* @file binding-post.ts
|
|
3
|
+
* @author tngan
|
|
4
|
+
* @desc Binding-level API, declare the functions using POST binding
|
|
5
|
+
*/
|
|
6
6
|
import { wording, StatusCode } from './urn.js';
|
|
7
7
|
import libsaml from './libsaml.js';
|
|
8
8
|
import utility, { get } from './utility.js';
|
|
9
9
|
const binding = wording.binding;
|
|
10
10
|
/**
|
|
11
|
-
* @desc Generate a base64 encoded login request
|
|
12
|
-
* @param {string} referenceTagXPath reference uri
|
|
13
|
-
* @param {object} entity object includes both idp and sp
|
|
14
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
15
|
-
*/
|
|
11
|
+
* @desc Generate a base64 encoded login request
|
|
12
|
+
* @param {string} referenceTagXPath reference uri
|
|
13
|
+
* @param {object} entity object includes both idp and sp
|
|
14
|
+
* @param {function} customTagReplacement used when developers have their own login response template
|
|
15
|
+
*/
|
|
16
16
|
function base64LoginRequest(referenceTagXPath, entity, customTagReplacement) {
|
|
17
17
|
const metadata = { idp: entity.idp.entityMeta, sp: entity.sp.entityMeta };
|
|
18
18
|
const spSetting = entity.sp.entitySetting;
|
|
@@ -141,7 +141,6 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
|
|
|
141
141
|
};
|
|
142
142
|
// step: sign assertion ? -> encrypted ? -> sign message ?
|
|
143
143
|
if (metadata.sp.isWantAssertionsSigned()) {
|
|
144
|
-
// console.debug('sp wants assertion signed');
|
|
145
144
|
rawSamlResponse = libsaml.constructSAMLSignature({
|
|
146
145
|
...config,
|
|
147
146
|
rawSamlMessage: rawSamlResponse,
|
|
@@ -149,7 +148,10 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
|
|
|
149
148
|
referenceTagXPath: "/*[local-name(.)='Response']/*[local-name(.)='Assertion']",
|
|
150
149
|
signatureConfig: {
|
|
151
150
|
prefix: 'ds',
|
|
152
|
-
location: {
|
|
151
|
+
location: {
|
|
152
|
+
reference: "/*[local-name(.)='Response']/*[local-name(.)='Assertion']/*[local-name(.)='Issuer']",
|
|
153
|
+
action: 'after'
|
|
154
|
+
},
|
|
153
155
|
},
|
|
154
156
|
});
|
|
155
157
|
}
|
|
@@ -168,7 +170,19 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
|
|
|
168
170
|
},
|
|
169
171
|
});
|
|
170
172
|
}
|
|
171
|
-
|
|
173
|
+
/* if (spSetting.wantMessageSigned) {
|
|
174
|
+
// console.debug('sign then encrypt and sign entire message');
|
|
175
|
+
rawSamlResponse = libsaml.constructSAMLSignature({
|
|
176
|
+
...config,
|
|
177
|
+
rawSamlMessage: rawSamlResponse,
|
|
178
|
+
isMessageSigned: true,
|
|
179
|
+
transformationAlgorithms: spSetting.transformationAlgorithms,
|
|
180
|
+
signatureConfig: spSetting.signatureConfig || {
|
|
181
|
+
prefix: 'ds',
|
|
182
|
+
location: {reference: "/!*[local-name(.)='Response']/!*[local-name(.)='Issuer']", action: 'after'},
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
}*/
|
|
172
186
|
if (idpSetting.isAssertionEncrypted) {
|
|
173
187
|
// console.debug('idp is configured to do encryption');
|
|
174
188
|
const context = await libsaml.encryptAssertion(entity.idp, entity.sp, rawSamlResponse);
|
|
@@ -181,18 +195,18 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
|
|
|
181
195
|
}
|
|
182
196
|
}
|
|
183
197
|
//sign after encrypting
|
|
184
|
-
if (encryptThenSign && (spSetting.wantMessageSigned || !metadata.sp.isWantAssertionsSigned())) {
|
|
185
|
-
|
|
198
|
+
/* if (encryptThenSign && (spSetting.wantMessageSigned || !metadata.sp.isWantAssertionsSigned())) {
|
|
199
|
+
rawSamlResponse = libsaml.constructSAMLSignature({
|
|
186
200
|
...config,
|
|
187
201
|
rawSamlMessage: rawSamlResponse,
|
|
188
202
|
isMessageSigned: true,
|
|
189
203
|
transformationAlgorithms: spSetting.transformationAlgorithms,
|
|
190
204
|
signatureConfig: spSetting.signatureConfig || {
|
|
191
|
-
|
|
192
|
-
|
|
205
|
+
prefix: 'ds',
|
|
206
|
+
location: {reference: "/!*[local-name(.)='Response']/!*[local-name(.)='Issuer']", action: 'after'},
|
|
193
207
|
},
|
|
194
|
-
|
|
195
|
-
|
|
208
|
+
});
|
|
209
|
+
}*/
|
|
196
210
|
return Promise.resolve({
|
|
197
211
|
id,
|
|
198
212
|
context: utility.base64Encode(rawSamlResponse),
|
|
@@ -201,13 +215,13 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, customTa
|
|
|
201
215
|
throw new Error('ERR_GENERATE_POST_LOGIN_RESPONSE_MISSING_METADATA');
|
|
202
216
|
}
|
|
203
217
|
/**
|
|
204
|
-
* @desc Generate a base64 encoded logout request
|
|
205
|
-
* @param {object} user current logged user (e.g. req.user)
|
|
206
|
-
* @param {string} referenceTagXPath reference uri
|
|
207
|
-
* @param {object} entity object includes both idp and sp
|
|
208
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
209
|
-
* @return {string} base64 encoded request
|
|
210
|
-
*/
|
|
218
|
+
* @desc Generate a base64 encoded logout request
|
|
219
|
+
* @param {object} user current logged user (e.g. req.user)
|
|
220
|
+
* @param {string} referenceTagXPath reference uri
|
|
221
|
+
* @param {object} entity object includes both idp and sp
|
|
222
|
+
* @param {function} customTagReplacement used when developers have their own login response template
|
|
223
|
+
* @return {string} base64 encoded request
|
|
224
|
+
*/
|
|
211
225
|
function base64LogoutRequest(user, referenceTagXPath, entity, customTagReplacement) {
|
|
212
226
|
const metadata = { init: entity.init.entityMeta, target: entity.target.entityMeta };
|
|
213
227
|
const initSetting = entity.init.entitySetting;
|
|
@@ -262,12 +276,12 @@ function base64LogoutRequest(user, referenceTagXPath, entity, customTagReplaceme
|
|
|
262
276
|
throw new Error('ERR_GENERATE_POST_LOGOUT_REQUEST_MISSING_METADATA');
|
|
263
277
|
}
|
|
264
278
|
/**
|
|
265
|
-
* @desc Generate a base64 encoded logout response
|
|
266
|
-
* @param {object} requestInfo corresponding request, used to obtain the id
|
|
267
|
-
* @param {string} referenceTagXPath reference uri
|
|
268
|
-
* @param {object} entity object includes both idp and sp
|
|
269
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
270
|
-
*/
|
|
279
|
+
* @desc Generate a base64 encoded logout response
|
|
280
|
+
* @param {object} requestInfo corresponding request, used to obtain the id
|
|
281
|
+
* @param {string} referenceTagXPath reference uri
|
|
282
|
+
* @param {object} entity object includes both idp and sp
|
|
283
|
+
* @param {function} customTagReplacement used when developers have their own login response template
|
|
284
|
+
*/
|
|
271
285
|
function base64LogoutResponse(requestInfo, entity, customTagReplacement) {
|
|
272
286
|
const metadata = {
|
|
273
287
|
init: entity.init.entityMeta,
|
|
@@ -135,8 +135,6 @@ function loginRequestRedirectURLArt(entity, customTagReplacement) {
|
|
|
135
135
|
AllowCreate: spSetting.allowCreate,
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
|
-
console.log(rawSamlRequest);
|
|
139
|
-
console.log("-----------------这是原始请求模板-------------------");
|
|
140
138
|
const { privateKey, privateKeyPass, requestSignatureAlgorithm: signatureAlgorithm, transformationAlgorithms } = spSetting;
|
|
141
139
|
if (metadata.idp.isWantAuthnRequestsSigned()) {
|
|
142
140
|
let signAuthnRequest = libsaml.constructSAMLSignature({
|
|
@@ -156,8 +154,6 @@ function loginRequestRedirectURLArt(entity, customTagReplacement) {
|
|
|
156
154
|
},
|
|
157
155
|
}
|
|
158
156
|
});
|
|
159
|
-
console.log(signAuthnRequest);
|
|
160
|
-
console.log("签名后的模板");
|
|
161
157
|
rawSamlRequest = signAuthnRequest;
|
|
162
158
|
}
|
|
163
159
|
/* console.log(metadata.idp)
|
|
@@ -169,9 +165,6 @@ function loginRequestRedirectURLArt(entity, customTagReplacement) {
|
|
|
169
165
|
Issuer: metadata.sp.getEntityID(),
|
|
170
166
|
AuthnRequest: rawSamlRequest
|
|
171
167
|
});
|
|
172
|
-
console.log(soapTemplate);
|
|
173
|
-
console.log("======================最后结果========================");
|
|
174
|
-
console.log("======================开始签名根节点========================");
|
|
175
168
|
let rootSignSoap = libsaml.constructSAMLSignature({
|
|
176
169
|
isMessageSigned: true,
|
|
177
170
|
isBase64Output: false,
|
|
@@ -186,8 +179,6 @@ function loginRequestRedirectURLArt(entity, customTagReplacement) {
|
|
|
186
179
|
location: { reference: "//*[local-name()='Header']", action: 'after' },
|
|
187
180
|
}
|
|
188
181
|
});
|
|
189
|
-
console.log(rootSignSoap);
|
|
190
|
-
console.log("======================已经签名========================");
|
|
191
182
|
return {
|
|
192
183
|
authnRequest: rootSignSoap
|
|
193
184
|
};
|
|
@@ -224,7 +215,6 @@ function loginResponseRedirectURL(requestInfo, entity, user = {}, relayState, cu
|
|
|
224
215
|
// Five minutes later : nowtime + 5 * 60 * 1000 (in milliseconds)
|
|
225
216
|
const fiveMinutesLaterTime = new Date(nowTime.getTime() + 300_000);
|
|
226
217
|
const now = nowTime.toISOString();
|
|
227
|
-
console.log(`现在是北京时间:${nowTime.toLocaleString()}`);
|
|
228
218
|
const sessionIndex = 'session' + idpSetting.generateID(); // 这个是当前系统的会话索引,用于单点注销
|
|
229
219
|
const tenHoursLaterTime = new Date(nowTime.getTime());
|
|
230
220
|
tenHoursLaterTime.setHours(tenHoursLaterTime.getHours() + 10);
|
|
@@ -119,7 +119,6 @@ async function base64LoginResponse(requestInfo = {}, entity, user = {}, relaySta
|
|
|
119
119
|
// Five minutes later : nowtime + 5 * 60 * 1000 (in milliseconds)
|
|
120
120
|
const fiveMinutesLaterTime = new Date(nowTime.getTime() + 300_000);
|
|
121
121
|
const now = nowTime.toISOString();
|
|
122
|
-
console.log(`现在是北京时间:${nowTime.toLocaleString()}`);
|
|
123
122
|
const sessionIndex = 'session' + idpSetting.generateID(); // 这个是当前系统的会话索引,用于单点注销
|
|
124
123
|
const tenHoursLaterTime = new Date(nowTime.getTime());
|
|
125
124
|
tenHoursLaterTime.setHours(tenHoursLaterTime.getHours() + 10);
|
package/build/src/entity-idp.js
CHANGED
|
@@ -59,11 +59,7 @@ export class IdentityProvider extends Entity {
|
|
|
59
59
|
sp,
|
|
60
60
|
}, user, relayState, customTagReplacement, AttributeStatement);
|
|
61
61
|
default:
|
|
62
|
-
|
|
63
|
-
idp: this,
|
|
64
|
-
sp,
|
|
65
|
-
}, user, customTagReplacement, encryptThenSign, AttributeStatement);
|
|
66
|
-
/* throw new Error('ERR_CREATE_RESPONSE_UNDEFINED_BINDING');*/
|
|
62
|
+
throw new Error('ERR_CREATE_RESPONSE_UNDEFINED_BINDING');
|
|
67
63
|
}
|
|
68
64
|
return {
|
|
69
65
|
...context,
|
package/build/src/entity-sp.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @desc Declares the actions taken by service provider
|
|
5
5
|
*/
|
|
6
6
|
import Entity from './entity.js';
|
|
7
|
-
import
|
|
7
|
+
import Artifact from './binding-artifact.js';
|
|
8
8
|
import { namespace } from './urn.js';
|
|
9
9
|
import redirectBinding from './binding-redirect.js';
|
|
10
10
|
import postBinding from './binding-post.js';
|
|
@@ -61,12 +61,6 @@ export class ServiceProvider extends Entity {
|
|
|
61
61
|
// Object context = {id, context, signature, sigAlg}
|
|
62
62
|
context = simpleSignBinding.base64LoginRequest({ idp, sp: this }, customTagReplacement);
|
|
63
63
|
break;
|
|
64
|
-
case nsBinding.artifact:
|
|
65
|
-
context = artifactSignBinding.base64LoginRequest("/*[local-name(.)='AuthnRequest']", {
|
|
66
|
-
idp,
|
|
67
|
-
sp: this
|
|
68
|
-
}, customTagReplacement);
|
|
69
|
-
break;
|
|
70
64
|
default:
|
|
71
65
|
// Will support artifact in the next release
|
|
72
66
|
throw new Error('ERR_SP_LOGIN_REQUEST_UNDEFINED_BINDING');
|
|
@@ -78,39 +72,20 @@ export class ServiceProvider extends Entity {
|
|
|
78
72
|
type: 'SAMLRequest',
|
|
79
73
|
};
|
|
80
74
|
}
|
|
81
|
-
|
|
82
|
-
* @desc Generates the Art login request for developers to design their own method
|
|
83
|
-
* @param {IdentityProvider} idp object of identity provider
|
|
84
|
-
* @param {string} binding protocol binding
|
|
85
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
86
|
-
*/
|
|
87
|
-
createLoginRequestArt(idp, binding = 'redirect', customTagReplacement) {
|
|
75
|
+
async createLoginSoapRequest(idp, binding = 'artifact', config) {
|
|
88
76
|
const nsBinding = namespace.binding;
|
|
89
77
|
const protocol = nsBinding[binding];
|
|
90
78
|
if (this.entityMeta.isAuthnRequestSigned() !== idp.entityMeta.isWantAuthnRequestsSigned()) {
|
|
91
79
|
throw new Error('ERR_METADATA_CONFLICT_REQUEST_SIGNED_FLAG');
|
|
92
80
|
}
|
|
93
81
|
let context = null;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
soap: true
|
|
102
|
-
}, customTagReplacement);
|
|
103
|
-
break;
|
|
104
|
-
default:
|
|
105
|
-
// Will support artifact in the next release
|
|
106
|
-
throw new Error('ERR_SP_LOGIN_REQUEST_UNDEFINED_BINDING');
|
|
107
|
-
}
|
|
108
|
-
return {
|
|
109
|
-
...context,
|
|
110
|
-
relayState: this.entitySetting.relayState,
|
|
111
|
-
entityEndpoint: idp.entityMeta.getSingleSignOnService(binding),
|
|
112
|
-
type: 'SAMLRequest',
|
|
113
|
-
};
|
|
82
|
+
context = await artifactSignBinding.soapLoginRequest("/*[local-name(.)='AuthnRequest']", {
|
|
83
|
+
idp,
|
|
84
|
+
sp: this,
|
|
85
|
+
inResponse: config?.inResponseTo,
|
|
86
|
+
relayState: config?.relayState,
|
|
87
|
+
}, config?.customTagReplacement);
|
|
88
|
+
return context;
|
|
114
89
|
}
|
|
115
90
|
/**
|
|
116
91
|
* @desc Validation of the parsed the URL parameters
|
|
@@ -136,70 +111,20 @@ export class ServiceProvider extends Entity {
|
|
|
136
111
|
* @param {string} binding protocol binding
|
|
137
112
|
* @param {request} req request
|
|
138
113
|
*/
|
|
139
|
-
|
|
114
|
+
parseLoginRequestResolve(idp, xml) {
|
|
140
115
|
const self = this;
|
|
141
|
-
return
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
checkSignature: true, // saml response must have signature
|
|
146
|
-
parserType: 'SAMLResponse',
|
|
147
|
-
type: 'login',
|
|
148
|
-
binding: binding,
|
|
149
|
-
request: request
|
|
116
|
+
return Artifact.parseLoginRequestResolve({
|
|
117
|
+
idp: idp,
|
|
118
|
+
sp: self,
|
|
119
|
+
xml: xml
|
|
150
120
|
});
|
|
151
121
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
console.log(sourceEntityId);
|
|
160
|
-
console.log("0000000000000000000000000000000000000000");
|
|
161
|
-
// 1. 固定类型代码 (0x0004 - 2字节)
|
|
162
|
-
const typeCode = Buffer.from([0x00, 0x04]);
|
|
163
|
-
// 2. 端点索引 (2字节,大端序)
|
|
164
|
-
if (endpointIndex < 0 || endpointIndex > 65535) {
|
|
165
|
-
throw new Error('Endpoint index must be between 0 and 65535');
|
|
166
|
-
}
|
|
167
|
-
const endpointBuf = Buffer.alloc(2);
|
|
168
|
-
endpointBuf.writeUInt16BE(endpointIndex);
|
|
169
|
-
// 3. Source ID - 实体ID的SHA-1哈希 (20字节)
|
|
170
|
-
const sourceId = crypto.createHash('sha1')
|
|
171
|
-
.update(sourceEntityId)
|
|
172
|
-
.digest();
|
|
173
|
-
// 4. Message Handler - 20字节随机值
|
|
174
|
-
const messageHandler = crypto.randomBytes(20);
|
|
175
|
-
// 组合所有组件 (2+2+20+20 = 44字节)
|
|
176
|
-
const artifact = Buffer.concat([typeCode, endpointBuf, sourceId, messageHandler]);
|
|
177
|
-
// 返回Base64编码的Artifact
|
|
178
|
-
return artifact.toString('base64');
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* @desc generate Art id
|
|
182
|
-
* @param artifact
|
|
183
|
-
*/
|
|
184
|
-
parseArt(artifact) {
|
|
185
|
-
// 解码 Base64
|
|
186
|
-
const decoded = Buffer.from(artifact, 'base64');
|
|
187
|
-
// 确保长度正确(SAML 工件固定为 44 字节)
|
|
188
|
-
if (decoded.length !== 44) {
|
|
189
|
-
throw new Error(`Invalid artifact length: ${decoded.length}, expected 44 bytes`);
|
|
190
|
-
}
|
|
191
|
-
// 读取前 4 字节(TypeCode + EndpointIndex)
|
|
192
|
-
const typeCode = decoded.readUInt16BE(0);
|
|
193
|
-
const endpointIndex = decoded.readUInt16BE(2);
|
|
194
|
-
// 使用 Buffer.from() 替代 slice()
|
|
195
|
-
const sourceId = Buffer.from(decoded.buffer, // 底层 ArrayBuffer
|
|
196
|
-
decoded.byteOffset + 4, // 起始偏移量
|
|
197
|
-
20 // 长度
|
|
198
|
-
).toString('hex');
|
|
199
|
-
const messageHandle = Buffer.from(decoded.buffer, // 底层 ArrayBuffer
|
|
200
|
-
decoded.byteOffset + 24, // 起始偏移量
|
|
201
|
-
20 // 长度
|
|
202
|
-
).toString('hex');
|
|
203
|
-
return { typeCode, endpointIndex, sourceId, messageHandle };
|
|
122
|
+
parseLoginResponseResolve(idp, art, request) {
|
|
123
|
+
const self = this;
|
|
124
|
+
return Artifact.parseLoginResponseResolve({
|
|
125
|
+
idp: idp,
|
|
126
|
+
sp: self,
|
|
127
|
+
art: art
|
|
128
|
+
});
|
|
204
129
|
}
|
|
205
130
|
}
|
package/build/src/extractor.js
CHANGED
|
@@ -54,6 +54,38 @@ export const loginRequestFields = [
|
|
|
54
54
|
context: true
|
|
55
55
|
}
|
|
56
56
|
];
|
|
57
|
+
export const artifactResolveFields = [
|
|
58
|
+
{
|
|
59
|
+
key: 'request',
|
|
60
|
+
localPath: ['ArtifactResolve'],
|
|
61
|
+
attributes: ['ID', 'IssueInstant', 'Version']
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
key: 'issuer', localPath: ['ArtifactResolve', 'Issuer'], attributes: []
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
key: 'Artifact', localPath: ['ArtifactResolve', 'Artifact'], attributes: []
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
key: 'signature', localPath: ['ArtifactResolve', 'Signature'], attributes: [], context: true
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
export const artifactResponseFields = [
|
|
74
|
+
{
|
|
75
|
+
key: 'request',
|
|
76
|
+
localPath: ['Envelope', 'Body', 'ArtifactResolve'],
|
|
77
|
+
attributes: ['ID', 'IssueInstant', 'Version']
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
key: 'issuer', localPath: ['Envelope', 'Body', 'ArtifactResolve', 'Issuer'], attributes: []
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
key: 'Artifact', localPath: ['Envelope', 'Body', 'ArtifactResolve', 'Artifact'], attributes: []
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
key: 'signature', localPath: ['Envelope', 'Body', 'ArtifactResolve', 'Signature'], attributes: [], context: true
|
|
87
|
+
},
|
|
88
|
+
];
|
|
57
89
|
// support two-tiers status code
|
|
58
90
|
export const loginResponseStatusFields = [
|
|
59
91
|
{
|
|
@@ -191,7 +223,7 @@ export const logoutResponseFields = [
|
|
|
191
223
|
];
|
|
192
224
|
export function extract(context, fields) {
|
|
193
225
|
const { dom } = getContext();
|
|
194
|
-
const rootDoc = dom.parseFromString(context);
|
|
226
|
+
const rootDoc = dom.parseFromString(context, 'application/xml');
|
|
195
227
|
return fields.reduce((result, field) => {
|
|
196
228
|
// get essential fields
|
|
197
229
|
const key = field.key;
|
|
@@ -207,7 +239,7 @@ export function extract(context, fields) {
|
|
|
207
239
|
// if shortcut is used, then replace the doc
|
|
208
240
|
// it's a design for overriding the doc used during runtime
|
|
209
241
|
if (shortcut) {
|
|
210
|
-
targetDoc = dom.parseFromString(shortcut);
|
|
242
|
+
targetDoc = dom.parseFromString(shortcut, 'application/xml');
|
|
211
243
|
}
|
|
212
244
|
// special case: multiple path
|
|
213
245
|
/*
|
|
@@ -229,6 +261,7 @@ export function extract(context, fields) {
|
|
|
229
261
|
.join(' | ');
|
|
230
262
|
return {
|
|
231
263
|
...result,
|
|
264
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
232
265
|
[key]: uniq(select(multiXPaths, targetDoc).map((n) => n.nodeValue).filter(notEmpty))
|
|
233
266
|
};
|
|
234
267
|
}
|
|
@@ -249,8 +282,10 @@ export function extract(context, fields) {
|
|
|
249
282
|
// find the index in localpath
|
|
250
283
|
const indexPath = buildAttributeXPath(index);
|
|
251
284
|
const fullLocalXPath = `${baseXPath}${indexPath}`;
|
|
285
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
252
286
|
const parentNodes = select(baseXPath, targetDoc);
|
|
253
287
|
// [uid, mail, edupersonaffiliation], ready for aggregate
|
|
288
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
254
289
|
const parentAttributes = select(fullLocalXPath, targetDoc).map((n) => n.value);
|
|
255
290
|
// [attribute, attributevalue]
|
|
256
291
|
const childXPath = buildAbsoluteXPath([last(localPath)].concat(attributePath));
|
|
@@ -258,8 +293,9 @@ export function extract(context, fields) {
|
|
|
258
293
|
const fullChildXPath = `${childXPath}${childAttributeXPath}`;
|
|
259
294
|
// [ 'test', 'test@example.com', [ 'users', 'examplerole1' ] ]
|
|
260
295
|
const childAttributes = parentNodes.map(node => {
|
|
261
|
-
const nodeDoc = dom.parseFromString(node.toString());
|
|
296
|
+
const nodeDoc = dom.parseFromString(node.toString(), 'application/xml');
|
|
262
297
|
if (attributes.length === 0) {
|
|
298
|
+
// @ts-ignore
|
|
263
299
|
const childValues = select(fullChildXPath, nodeDoc).map((n) => n.nodeValue);
|
|
264
300
|
if (childValues.length === 1) {
|
|
265
301
|
return childValues[0];
|
|
@@ -267,6 +303,7 @@ export function extract(context, fields) {
|
|
|
267
303
|
return childValues;
|
|
268
304
|
}
|
|
269
305
|
if (attributes.length > 0) {
|
|
306
|
+
// @ts-ignore
|
|
270
307
|
const childValues = select(fullChildXPath, nodeDoc).map((n) => n.value);
|
|
271
308
|
if (childValues.length === 1) {
|
|
272
309
|
return childValues[0];
|
|
@@ -292,6 +329,7 @@ export function extract(context, fields) {
|
|
|
292
329
|
}
|
|
293
330
|
*/
|
|
294
331
|
if (isEntire) {
|
|
332
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
295
333
|
const node = select(baseXPath, targetDoc);
|
|
296
334
|
let value = null;
|
|
297
335
|
if (node.length === 1) {
|
|
@@ -314,10 +352,13 @@ export function extract(context, fields) {
|
|
|
314
352
|
}
|
|
315
353
|
*/
|
|
316
354
|
if (attributes.length > 1) {
|
|
355
|
+
// @ts-ignore
|
|
317
356
|
const baseNode = select(baseXPath, targetDoc).map(n => n.toString());
|
|
318
357
|
const childXPath = `${buildAbsoluteXPath([last(localPath)])}${attributeXPath}`;
|
|
319
358
|
const attributeValues = baseNode.map((node) => {
|
|
320
|
-
|
|
359
|
+
// @ts-ignore
|
|
360
|
+
const nodeDoc = dom.parseFromString(node, 'application/xml');
|
|
361
|
+
// @ts-ignore
|
|
321
362
|
const values = select(childXPath, nodeDoc).reduce((r, n) => {
|
|
322
363
|
r[camelCase(n.name, { locale: 'en-us' })] = n.value;
|
|
323
364
|
return r;
|
|
@@ -339,6 +380,7 @@ export function extract(context, fields) {
|
|
|
339
380
|
*/
|
|
340
381
|
if (attributes.length === 1) {
|
|
341
382
|
const fullPath = `${baseXPath}${attributeXPath}`;
|
|
383
|
+
// @ts-ignore
|
|
342
384
|
const attributeValues = select(fullPath, targetDoc).map((n) => n.value);
|
|
343
385
|
return {
|
|
344
386
|
...result,
|
|
@@ -355,9 +397,11 @@ export function extract(context, fields) {
|
|
|
355
397
|
*/
|
|
356
398
|
if (attributes.length === 0) {
|
|
357
399
|
let attributeValue = null;
|
|
400
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
358
401
|
const node = select(baseXPath, targetDoc);
|
|
359
402
|
if (node.length === 1) {
|
|
360
403
|
const fullPath = `string(${baseXPath}${attributeXPath})`;
|
|
404
|
+
// @ts-expect-error misssing Node properties are not needed
|
|
361
405
|
attributeValue = select(fullPath, targetDoc);
|
|
362
406
|
}
|
|
363
407
|
if (node.length > 1) {
|