samlesa 4.3.4 → 4.4.0
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/README.md +19 -16
- package/build/src/artifact.js +55 -0
- package/build/src/binding-artifact.js +477 -363
- package/build/src/binding-post.js +7 -3
- package/build/src/entity-idp.js +51 -3
- package/build/src/entity-sp.js +35 -30
- package/build/src/extractor.js +21 -4
- package/build/src/libsamlSoap.js +88 -96
- package/build/src/metadata.js +0 -1
- package/build/src/soap.js +34 -105
- package/package.json +87 -87
- package/types/src/artifact.d.ts +14 -0
- package/types/src/artifact.d.ts.map +1 -0
- package/types/src/binding-artifact.d.ts +92 -58
- package/types/src/binding-artifact.d.ts.map +1 -1
- package/types/src/binding-post.d.ts +1 -1
- package/types/src/binding-post.d.ts.map +1 -1
- package/types/src/entity-idp.d.ts +42 -2
- package/types/src/entity-idp.d.ts.map +1 -1
- package/types/src/entity-sp.d.ts +16 -17
- package/types/src/entity-sp.d.ts.map +1 -1
- package/types/src/extractor.d.ts.map +1 -1
- package/types/src/flow.d.ts.map +1 -1
- package/types/src/libsamlSoap.d.ts +9 -2
- package/types/src/libsamlSoap.d.ts.map +1 -1
- package/types/src/metadata.d.ts.map +1 -1
- package/types/src/soap.d.ts +5 -25
- package/types/src/soap.d.ts.map +1 -1
- package/types/src/types.d.ts +1 -0
- package/types/src/types.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -154,22 +154,25 @@ const { context: samlResponse } = await idp.createLoginResponse({
|
|
|
154
154
|
});
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
### Artifact Binding Support
|
|
158
|
-
|
|
159
|
-
```typescript
|
|
160
|
-
import { ServiceProvider, IdentityProvider } from 'samlesa';
|
|
161
|
-
|
|
162
|
-
// Create
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
157
|
+
### Artifact Binding Support
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { ServiceProvider, IdentityProvider } from 'samlesa';
|
|
161
|
+
|
|
162
|
+
// Create front-channel artifact login request
|
|
163
|
+
const loginRequest = sp.createLoginRequest(idp, 'artifact');
|
|
164
|
+
|
|
165
|
+
// Parse ArtifactResolve request on the SP artifact resolution endpoint
|
|
166
|
+
const artifactResolve = await sp.parseArtifactResolveRequest(idp, soapXml);
|
|
167
|
+
|
|
168
|
+
// Create ArtifactResponse with the resolved SAML message
|
|
169
|
+
const artifactResponse = await sp.createArtifactResolveResponse(idp, {
|
|
170
|
+
inResponseTo: artifactResolve.extract.request.id,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Parse artifact-based login response from the ACS endpoint
|
|
174
|
+
const responseResult = await sp.parseLoginResponse(idp, 'artifact', request);
|
|
175
|
+
```
|
|
173
176
|
|
|
174
177
|
---
|
|
175
178
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
export const SAML2_ARTIFACT_TYPE_CODE = 0x0004;
|
|
3
|
+
export const SAML2_ARTIFACT_LENGTH = 44;
|
|
4
|
+
export function computeArtifactSourceId(entityId) {
|
|
5
|
+
return crypto.createHash('sha1').update(entityId).digest().subarray(0, 20);
|
|
6
|
+
}
|
|
7
|
+
export function generateArtifactId(entityId, endpointIndex = 0) {
|
|
8
|
+
if (!entityId || typeof entityId !== 'string') {
|
|
9
|
+
throw new Error('ERR_INVALID_ARTIFACT_ENTITY_ID');
|
|
10
|
+
}
|
|
11
|
+
if (!Number.isInteger(endpointIndex) || endpointIndex < 0 || endpointIndex > 0xffff) {
|
|
12
|
+
throw new Error('ERR_INVALID_ARTIFACT_ENDPOINT_INDEX');
|
|
13
|
+
}
|
|
14
|
+
const typeCode = Buffer.alloc(2);
|
|
15
|
+
typeCode.writeUInt16BE(SAML2_ARTIFACT_TYPE_CODE, 0);
|
|
16
|
+
const endpointIndexBuffer = Buffer.alloc(2);
|
|
17
|
+
endpointIndexBuffer.writeUInt16BE(endpointIndex, 0);
|
|
18
|
+
const artifact = Buffer.concat([
|
|
19
|
+
typeCode,
|
|
20
|
+
endpointIndexBuffer,
|
|
21
|
+
computeArtifactSourceId(entityId),
|
|
22
|
+
crypto.randomBytes(20),
|
|
23
|
+
]);
|
|
24
|
+
return artifact.toString('base64');
|
|
25
|
+
}
|
|
26
|
+
export function parseArtifact(artifact) {
|
|
27
|
+
if (typeof artifact !== 'string' || artifact.trim() === '') {
|
|
28
|
+
throw new Error('ERR_INVALID_ARTIFACT');
|
|
29
|
+
}
|
|
30
|
+
const decoded = Buffer.from(artifact, 'base64');
|
|
31
|
+
if (decoded.length !== SAML2_ARTIFACT_LENGTH) {
|
|
32
|
+
throw new Error('ERR_INVALID_ARTIFACT_LENGTH');
|
|
33
|
+
}
|
|
34
|
+
const typeCode = decoded.readUInt16BE(0);
|
|
35
|
+
if (typeCode !== SAML2_ARTIFACT_TYPE_CODE) {
|
|
36
|
+
throw new Error('ERR_UNSUPPORTED_ARTIFACT_TYPE');
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
artifact,
|
|
40
|
+
typeCode,
|
|
41
|
+
endpointIndex: decoded.readUInt16BE(2),
|
|
42
|
+
sourceId: decoded.subarray(4, 24).toString('hex'),
|
|
43
|
+
messageHandle: decoded.subarray(24, 44).toString('hex'),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function validateArtifact(artifact, expectedEntityId) {
|
|
47
|
+
const parsed = parseArtifact(artifact);
|
|
48
|
+
if (expectedEntityId) {
|
|
49
|
+
const expectedSourceId = computeArtifactSourceId(expectedEntityId).toString('hex');
|
|
50
|
+
if (parsed.sourceId !== expectedSourceId) {
|
|
51
|
+
throw new Error('ERR_UNMATCH_ARTIFACT_SOURCE');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return parsed;
|
|
55
|
+
}
|