samlesa 2.12.3 → 2.12.6
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/build/index.js +54 -64
- package/build/index.js.map +1 -1
- package/build/src/api.js +24 -23
- package/build/src/api.js.map +1 -1
- package/build/src/binding-post.js +358 -368
- package/build/src/binding-post.js.map +1 -1
- package/build/src/binding-redirect.js +333 -332
- package/build/src/binding-redirect.js.map +1 -1
- package/build/src/binding-simplesign.js +222 -232
- package/build/src/binding-simplesign.js.map +1 -1
- package/build/src/entity-idp.js +132 -130
- package/build/src/entity-idp.js.map +1 -1
- package/build/src/entity-sp.js +96 -96
- package/build/src/entity-sp.js.map +1 -1
- package/build/src/entity.js +225 -235
- package/build/src/entity.js.map +1 -1
- package/build/src/extractor.js +369 -369
- package/build/src/extractor.js.map +1 -1
- package/build/src/flow.js +320 -319
- package/build/src/flow.js.map +1 -1
- package/build/src/libsaml.js +660 -641
- package/build/src/libsaml.js.map +1 -1
- package/build/src/metadata-idp.js +127 -127
- package/build/src/metadata-idp.js.map +1 -1
- package/build/src/metadata-sp.js +231 -231
- package/build/src/metadata-sp.js.map +1 -1
- package/build/src/metadata.js +166 -176
- package/build/src/metadata.js.map +1 -1
- package/build/src/types.js +11 -11
- package/build/src/urn.js +212 -212
- package/build/src/urn.js.map +1 -1
- package/build/src/utility.js +292 -248
- package/build/src/utility.js.map +1 -1
- package/build/src/validator.js +27 -26
- package/build/src/validator.js.map +1 -1
- package/index.d.ts +10 -10
- package/index.js +18 -18
- package/package.json +1 -5
- package/qodana.yaml +29 -29
- package/src/binding-post.ts +1 -1
- package/src/binding-redirect.ts +83 -64
- package/src/entity-idp.ts +26 -20
- package/src/libsaml.ts +79 -48
- package/src/utility.ts +147 -76
- package/types/index.d.ts +10 -10
- package/types/src/api.d.ts +13 -13
- package/types/src/binding-post.d.ts +46 -46
- package/types/src/binding-redirect.d.ts +52 -52
- package/types/src/binding-simplesign.d.ts +39 -39
- package/types/src/entity-idp.d.ts +35 -42
- package/types/src/entity-sp.d.ts +36 -36
- package/types/src/entity.d.ts +101 -99
- package/types/src/extractor.d.ts +25 -25
- package/types/src/flow.d.ts +6 -6
- package/types/src/libsaml.d.ts +200 -210
- package/types/src/metadata-idp.d.ts +24 -24
- package/types/src/metadata-sp.d.ts +36 -36
- package/types/src/metadata.d.ts +59 -57
- package/types/src/types.d.ts +129 -127
- package/types/src/urn.d.ts +194 -194
- package/types/src/utility.d.ts +134 -134
- package/types/src/validator.d.ts +3 -3
- package/.idea/compiler.xml +0 -6
- package/.idea/deployment.xml +0 -14
- package/.idea/jsLibraryMappings.xml +0 -6
- package/build/.idea/workspace.xml +0 -58
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/validator.ts"],"names":[],"mappings":";;;AAGA,SAAS,UAAU,CACjB,YAAgC,EAChC,eAAmC,EACnC,QAAwB,CAAC,CAAC,EAAE,CAAC,CAAC;IAG9B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,IAAI,CAAC,YAAY,IAAI,CAAC,eAAe,EAAE;QACrC,kHAAkH;QAClH,OAAO,CAAC,IAAI,CAAC,2FAA2F,CAAC,CAAC;QAC1G,OAAO,IAAI,CAAC;KACb;IAED,IAAI,cAAc,GAAgB,IAAI,CAAC;IACvC,IAAI,iBAAiB,GAAgB,IAAI,CAAC;IAE1C,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,KAAK,CAAC;IAElD,IAAI,YAAY,IAAI,CAAC,eAAe,EAAE;QACpC,cAAc,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC;QACxC,OAAO,CAAC,cAAc,GAAG,cAAc,IAAI,CAAC,GAAG,CAAC;KACjD;IACD,IAAI,CAAC,YAAY,IAAI,eAAe,EAAE;QACpC,iBAAiB,GAAG,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,GAAG,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;KACtD;IAED,cAAc,GAAG,IAAI,IAAI,CAAC,YAAa,CAAC,CAAC;IACzC,iBAAiB,GAAG,IAAI,IAAI,CAAC,eAAgB,CAAC,CAAC;IAE/C,OAAO,CACL,CAAC,cAAc,GAAG,cAAc,IAAI,CAAC,GAAG;QACxC,CAAC,GAAG,GAAG,CAAC,iBAAiB,GAAG,iBAAiB,CAC9C,CAAC;AAEJ,CAAC;AAGC,gCAAU"}
|
package/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import IdentityProvider, { IdentityProvider as IdentityProviderInstance } from './src/entity-idp';
|
|
2
|
-
import ServiceProvider, { ServiceProvider as ServiceProviderInstance } from './src/entity-sp';
|
|
3
|
-
export { default as IdPMetadata } from './src/metadata-idp';
|
|
4
|
-
export { default as SPMetadata } from './src/metadata-sp';
|
|
5
|
-
export { default as Utility } from './src/utility';
|
|
6
|
-
export { default as SamlLib } from './src/libsaml';
|
|
7
|
-
import * as Constants from './src/urn';
|
|
8
|
-
import * as Extractor from './src/extractor';
|
|
9
|
-
import { setSchemaValidator, setDOMParserOptions } from './src/api';
|
|
10
|
-
export { Constants, Extractor, IdentityProvider, IdentityProviderInstance, ServiceProvider, ServiceProviderInstance, setSchemaValidator, setDOMParserOptions };
|
|
1
|
+
import IdentityProvider, { IdentityProvider as IdentityProviderInstance } from './src/entity-idp';
|
|
2
|
+
import ServiceProvider, { ServiceProvider as ServiceProviderInstance } from './src/entity-sp';
|
|
3
|
+
export { default as IdPMetadata } from './src/metadata-idp';
|
|
4
|
+
export { default as SPMetadata } from './src/metadata-sp';
|
|
5
|
+
export { default as Utility } from './src/utility';
|
|
6
|
+
export { default as SamlLib } from './src/libsaml';
|
|
7
|
+
import * as Constants from './src/urn';
|
|
8
|
+
import * as Extractor from './src/extractor';
|
|
9
|
+
import { setSchemaValidator, setDOMParserOptions } from './src/api';
|
|
10
|
+
export { Constants, Extractor, IdentityProvider, IdentityProviderInstance, ServiceProvider, ServiceProviderInstance, setSchemaValidator, setDOMParserOptions };
|
package/index.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
// version <= 1.25
|
|
2
|
-
import IdentityProvider, { IdentityProvider as IdentityProviderInstance } from './src/entity-idp';
|
|
3
|
-
import ServiceProvider, { ServiceProvider as ServiceProviderInstance } from './src/entity-sp';
|
|
4
|
-
export { default as IdPMetadata } from './src/metadata-idp';
|
|
5
|
-
export { default as SPMetadata } from './src/metadata-sp';
|
|
6
|
-
export { default as Utility } from './src/utility';
|
|
7
|
-
export { default as SamlLib } from './src/libsaml';
|
|
8
|
-
// roadmap
|
|
9
|
-
// new name convention in version >= 3.0
|
|
10
|
-
import * as Constants from './src/urn';
|
|
11
|
-
import * as Extractor from './src/extractor';
|
|
12
|
-
// exposed methods for customizing samlify
|
|
13
|
-
import { setSchemaValidator, setDOMParserOptions } from './src/api';
|
|
14
|
-
export { Constants, Extractor,
|
|
15
|
-
// temp: resolve the conflict after version >= 3.0
|
|
16
|
-
IdentityProvider, IdentityProviderInstance, ServiceProvider, ServiceProviderInstance,
|
|
17
|
-
// set context
|
|
18
|
-
setSchemaValidator, setDOMParserOptions };
|
|
1
|
+
// version <= 1.25
|
|
2
|
+
import IdentityProvider, { IdentityProvider as IdentityProviderInstance } from './src/entity-idp';
|
|
3
|
+
import ServiceProvider, { ServiceProvider as ServiceProviderInstance } from './src/entity-sp';
|
|
4
|
+
export { default as IdPMetadata } from './src/metadata-idp';
|
|
5
|
+
export { default as SPMetadata } from './src/metadata-sp';
|
|
6
|
+
export { default as Utility } from './src/utility';
|
|
7
|
+
export { default as SamlLib } from './src/libsaml';
|
|
8
|
+
// roadmap
|
|
9
|
+
// new name convention in version >= 3.0
|
|
10
|
+
import * as Constants from './src/urn';
|
|
11
|
+
import * as Extractor from './src/extractor';
|
|
12
|
+
// exposed methods for customizing samlify
|
|
13
|
+
import { setSchemaValidator, setDOMParserOptions } from './src/api';
|
|
14
|
+
export { Constants, Extractor,
|
|
15
|
+
// temp: resolve the conflict after version >= 3.0
|
|
16
|
+
IdentityProvider, IdentityProviderInstance, ServiceProvider, ServiceProviderInstance,
|
|
17
|
+
// set context
|
|
18
|
+
setSchemaValidator, setDOMParserOptions };
|
|
19
19
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "samlesa",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.6",
|
|
4
4
|
"description": "High-level API for Single Sign On (SAML 2.0) 维护分支:修复原项目samlify的一些问题 ",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -35,8 +35,6 @@
|
|
|
35
35
|
"xml-encryption": "^3.0.1",
|
|
36
36
|
"@xmldom/xmldom": "^0.8.6",
|
|
37
37
|
"camelcase": "^6.2.0",
|
|
38
|
-
"node-forge": "^1.3.0",
|
|
39
|
-
"node-rsa": "^1.1.1",
|
|
40
38
|
"pako": "^1.0.10",
|
|
41
39
|
"uuid": "^10.0.0",
|
|
42
40
|
"xml": "^1.0.1",
|
|
@@ -47,8 +45,6 @@
|
|
|
47
45
|
"devDependencies": {
|
|
48
46
|
"@ava/typescript": "^1.1.1",
|
|
49
47
|
"@types/node": "^22.15.17",
|
|
50
|
-
"@types/node-forge": "^1.0.1",
|
|
51
|
-
"@types/node-rsa": "^1.1.1",
|
|
52
48
|
"@types/pako": "^1.0.1",
|
|
53
49
|
"@types/uuid": "^10.0.0",
|
|
54
50
|
"@types/xmldom": "^0.1.31",
|
package/qodana.yaml
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
#-------------------------------------------------------------------------------#
|
|
2
|
-
# Qodana analysis is configured by qodana.yaml file #
|
|
3
|
-
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
|
|
4
|
-
#-------------------------------------------------------------------------------#
|
|
5
|
-
version: "1.0"
|
|
6
|
-
|
|
7
|
-
#Specify inspection profile for code analysis
|
|
8
|
-
profile:
|
|
9
|
-
name: qodana.starter
|
|
10
|
-
|
|
11
|
-
#Enable inspections
|
|
12
|
-
#include:
|
|
13
|
-
# - name: <SomeEnabledInspectionId>
|
|
14
|
-
|
|
15
|
-
#Disable inspections
|
|
16
|
-
#exclude:
|
|
17
|
-
# - name: <SomeDisabledInspectionId>
|
|
18
|
-
# paths:
|
|
19
|
-
# - <path/where/not/run/inspection>
|
|
20
|
-
|
|
21
|
-
#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
|
|
22
|
-
#bootstrap: sh ./prepare-qodana.sh
|
|
23
|
-
|
|
24
|
-
#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
|
|
25
|
-
#plugins:
|
|
26
|
-
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
|
|
27
|
-
|
|
28
|
-
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
|
|
29
|
-
linter: jetbrains/qodana-js:2025.1
|
|
1
|
+
#-------------------------------------------------------------------------------#
|
|
2
|
+
# Qodana analysis is configured by qodana.yaml file #
|
|
3
|
+
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
|
|
4
|
+
#-------------------------------------------------------------------------------#
|
|
5
|
+
version: "1.0"
|
|
6
|
+
|
|
7
|
+
#Specify inspection profile for code analysis
|
|
8
|
+
profile:
|
|
9
|
+
name: qodana.starter
|
|
10
|
+
|
|
11
|
+
#Enable inspections
|
|
12
|
+
#include:
|
|
13
|
+
# - name: <SomeEnabledInspectionId>
|
|
14
|
+
|
|
15
|
+
#Disable inspections
|
|
16
|
+
#exclude:
|
|
17
|
+
# - name: <SomeDisabledInspectionId>
|
|
18
|
+
# paths:
|
|
19
|
+
# - <path/where/not/run/inspection>
|
|
20
|
+
|
|
21
|
+
#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
|
|
22
|
+
#bootstrap: sh ./prepare-qodana.sh
|
|
23
|
+
|
|
24
|
+
#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
|
|
25
|
+
#plugins:
|
|
26
|
+
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
|
|
27
|
+
|
|
28
|
+
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
|
|
29
|
+
linter: jetbrains/qodana-js:2025.1
|
package/src/binding-post.ts
CHANGED
|
@@ -168,7 +168,7 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any
|
|
|
168
168
|
},
|
|
169
169
|
});
|
|
170
170
|
console.log(rawSamlResponse);
|
|
171
|
-
console.log(
|
|
171
|
+
console.log('这他妈是什么------------------')
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
// console.debug('after message signed', rawSamlResponse);
|
package/src/binding-redirect.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file binding-redirect.ts
|
|
3
|
-
* @author tngan
|
|
4
|
-
* @desc Binding-level API, declare the functions using Redirect binding
|
|
5
|
-
*/
|
|
6
|
-
import utility, {
|
|
2
|
+
* @file binding-redirect.ts
|
|
3
|
+
* @author tngan
|
|
4
|
+
* @desc Binding-level API, declare the functions using Redirect binding
|
|
5
|
+
*/
|
|
6
|
+
import utility, {get} from './utility.js';
|
|
7
7
|
import libsaml from './libsaml.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
import {
|
|
8
|
+
import {BindingContext} from './entity.js';
|
|
9
|
+
import {IdentityProvider as Idp} from './entity-idp.js';
|
|
10
|
+
import {ServiceProvider as Sp} from './entity-sp.js';
|
|
11
|
+
|
|
12
|
+
import {wording, namespace} from './urn.js';
|
|
13
13
|
|
|
14
14
|
const binding = wording.binding;
|
|
15
15
|
const urlParams = wording.urlParams;
|
|
@@ -24,25 +24,26 @@ export interface BuildRedirectConfig {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* @private
|
|
28
|
-
* @desc Helper of generating URL param/value pair
|
|
29
|
-
* @param {string} param key
|
|
30
|
-
* @param {string} value value of key
|
|
31
|
-
* @param {boolean} first determine whether the param is the starting one in order to add query header '?'
|
|
32
|
-
* @return {string}
|
|
33
|
-
*/
|
|
27
|
+
* @private
|
|
28
|
+
* @desc Helper of generating URL param/value pair
|
|
29
|
+
* @param {string} param key
|
|
30
|
+
* @param {string} value value of key
|
|
31
|
+
* @param {boolean} first determine whether the param is the starting one in order to add query header '?'
|
|
32
|
+
* @return {string}
|
|
33
|
+
*/
|
|
34
34
|
function pvPair(param: string, value: string, first?: boolean): string {
|
|
35
35
|
return (first === true ? '?' : '&') + param + '=' + value;
|
|
36
36
|
}
|
|
37
|
+
|
|
37
38
|
/**
|
|
38
|
-
* @private
|
|
39
|
-
* @desc Refractored part of URL generation for login/logout request
|
|
40
|
-
* @param {string} type
|
|
41
|
-
* @param {boolean} isSigned
|
|
42
|
-
* @param {string} rawSamlRequest
|
|
43
|
-
* @param {object} entitySetting
|
|
44
|
-
* @return {string}
|
|
45
|
-
*/
|
|
39
|
+
* @private
|
|
40
|
+
* @desc Refractored part of URL generation for login/logout request
|
|
41
|
+
* @param {string} type
|
|
42
|
+
* @param {boolean} isSigned
|
|
43
|
+
* @param {string} rawSamlRequest
|
|
44
|
+
* @param {object} entitySetting
|
|
45
|
+
* @return {string}
|
|
46
|
+
*/
|
|
46
47
|
function buildRedirectURL(opts: BuildRedirectConfig) {
|
|
47
48
|
const {
|
|
48
49
|
baseUrl,
|
|
@@ -51,8 +52,14 @@ function buildRedirectURL(opts: BuildRedirectConfig) {
|
|
|
51
52
|
context,
|
|
52
53
|
entitySetting,
|
|
53
54
|
} = opts;
|
|
54
|
-
let {
|
|
55
|
-
|
|
55
|
+
let {relayState = ''} = opts;
|
|
56
|
+
let noParams = true
|
|
57
|
+
try {
|
|
58
|
+
noParams = new URL(baseUrl)?.searchParams?.size === 0
|
|
59
|
+
} catch {
|
|
60
|
+
noParams = true
|
|
61
|
+
}
|
|
62
|
+
|
|
56
63
|
const queryParam = libsaml.getQueryParamByType(type);
|
|
57
64
|
// In general, this xmlstring is required to do deflate -> base64 -> urlencode
|
|
58
65
|
const samlRequest = encodeURIComponent(utility.base64Encode(utility.deflateString(context)));
|
|
@@ -65,27 +72,31 @@ function buildRedirectURL(opts: BuildRedirectConfig) {
|
|
|
65
72
|
return baseUrl
|
|
66
73
|
+ pvPair(queryParam, octetString, noParams)
|
|
67
74
|
+ pvPair(urlParams.signature, encodeURIComponent(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
libsaml.constructMessageSignature(
|
|
76
|
+
queryParam + '=' + octetString,
|
|
77
|
+
entitySetting.privateKey,
|
|
78
|
+
entitySetting.privateKeyPass,
|
|
79
|
+
undefined,
|
|
80
|
+
entitySetting.requestSignatureAlgorithm
|
|
81
|
+
).toString()
|
|
82
|
+
)
|
|
76
83
|
);
|
|
77
84
|
}
|
|
78
85
|
return baseUrl + pvPair(queryParam, samlRequest + relayState, noParams);
|
|
79
86
|
}
|
|
87
|
+
|
|
80
88
|
/**
|
|
81
|
-
* @desc Redirect URL for login request
|
|
82
|
-
* @param {object} entity object includes both idp and sp
|
|
83
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
84
|
-
* @return {string} redirect URL
|
|
85
|
-
*/
|
|
86
|
-
function loginRequestRedirectURL(entity: {
|
|
89
|
+
* @desc Redirect URL for login request
|
|
90
|
+
* @param {object} entity object includes both idp and sp
|
|
91
|
+
* @param {function} customTagReplacement used when developers have their own login response template
|
|
92
|
+
* @return {string} redirect URL
|
|
93
|
+
*/
|
|
94
|
+
function loginRequestRedirectURL(entity: {
|
|
95
|
+
idp: Idp,
|
|
96
|
+
sp: Sp
|
|
97
|
+
}, customTagReplacement?: (template: string) => BindingContext): BindingContext {
|
|
87
98
|
|
|
88
|
-
const metadata: any = {
|
|
99
|
+
const metadata: any = {idp: entity.idp.entityMeta, sp: entity.sp.entityMeta};
|
|
89
100
|
const spSetting: any = entity.sp.entitySetting;
|
|
90
101
|
let id: string = '';
|
|
91
102
|
|
|
@@ -127,13 +138,13 @@ function loginRequestRedirectURL(entity: { idp: Idp, sp: Sp }, customTagReplacem
|
|
|
127
138
|
}
|
|
128
139
|
|
|
129
140
|
/**
|
|
130
|
-
* @desc Redirect URL for login response
|
|
131
|
-
* @param {object} requestInfo corresponding request, used to obtain the id
|
|
132
|
-
* @param {object} entity object includes both idp and sp
|
|
133
|
-
* @param {object} user current logged user (e.g. req.user)
|
|
134
|
-
* @param {String} relayState the relaystate sent by sp corresponding request
|
|
135
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
136
|
-
*/
|
|
141
|
+
* @desc Redirect URL for login response
|
|
142
|
+
* @param {object} requestInfo corresponding request, used to obtain the id
|
|
143
|
+
* @param {object} entity object includes both idp and sp
|
|
144
|
+
* @param {object} user current logged user (e.g. req.user)
|
|
145
|
+
* @param {String} relayState the relaystate sent by sp corresponding request
|
|
146
|
+
* @param {function} customTagReplacement used when developers have their own login response template
|
|
147
|
+
*/
|
|
137
148
|
function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {}, relayState?: string, customTagReplacement?: (template: string) => BindingContext): BindingContext {
|
|
138
149
|
const idpSetting = entity.idp.entitySetting;
|
|
139
150
|
const spSetting = entity.sp.entitySetting;
|
|
@@ -144,7 +155,11 @@ function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {},
|
|
|
144
155
|
|
|
145
156
|
let id: string = idpSetting.generateID();
|
|
146
157
|
if (metadata && metadata.idp && metadata.sp) {
|
|
147
|
-
const base = metadata.sp.getAssertionConsumerService(binding.redirect);
|
|
158
|
+
const base = metadata.sp.getAssertionConsumerService(binding.redirect) ?? 'https://signin.volcengine.com/saml/sso';
|
|
159
|
+
if(!base){
|
|
160
|
+
throw new Error('dont have a base url');
|
|
161
|
+
}
|
|
162
|
+
|
|
148
163
|
let rawSamlResponse: string;
|
|
149
164
|
//
|
|
150
165
|
const nameIDFormat = idpSetting.nameIDFormat;
|
|
@@ -186,7 +201,7 @@ function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {},
|
|
|
186
201
|
rawSamlResponse = libsaml.replaceTagsByValue(libsaml.defaultLoginResponseTemplate.context, tvalue);
|
|
187
202
|
}
|
|
188
203
|
|
|
189
|
-
const {
|
|
204
|
+
const {privateKey, privateKeyPass, requestSignatureAlgorithm: signatureAlgorithm} = idpSetting;
|
|
190
205
|
const config = {
|
|
191
206
|
privateKey,
|
|
192
207
|
privateKeyPass,
|
|
@@ -203,7 +218,10 @@ function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {},
|
|
|
203
218
|
referenceTagXPath: "/*[local-name(.)='Response']/*[local-name(.)='Assertion']",
|
|
204
219
|
signatureConfig: {
|
|
205
220
|
prefix: 'ds',
|
|
206
|
-
location: {
|
|
221
|
+
location: {
|
|
222
|
+
reference: "/*[local-name(.)='Response']/*[local-name(.)='Assertion']/*[local-name(.)='Issuer']",
|
|
223
|
+
action: 'after'
|
|
224
|
+
},
|
|
207
225
|
},
|
|
208
226
|
});
|
|
209
227
|
}
|
|
@@ -225,14 +243,14 @@ function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {},
|
|
|
225
243
|
}
|
|
226
244
|
|
|
227
245
|
/**
|
|
228
|
-
* @desc Redirect URL for logout request
|
|
229
|
-
* @param {object} user current logged user (e.g. req.user)
|
|
230
|
-
* @param {object} entity object includes both idp and sp
|
|
231
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
232
|
-
* @return {string} redirect URL
|
|
233
|
-
*/
|
|
246
|
+
* @desc Redirect URL for logout request
|
|
247
|
+
* @param {object} user current logged user (e.g. req.user)
|
|
248
|
+
* @param {object} entity object includes both idp and sp
|
|
249
|
+
* @param {function} customTagReplacement used when developers have their own login response template
|
|
250
|
+
* @return {string} redirect URL
|
|
251
|
+
*/
|
|
234
252
|
function logoutRequestRedirectURL(user, entity, relayState?: string, customTagReplacement?: (template: string, tags: object) => BindingContext): BindingContext {
|
|
235
|
-
const metadata = {
|
|
253
|
+
const metadata = {init: entity.init.entityMeta, target: entity.target.entityMeta};
|
|
236
254
|
const initSetting = entity.init.entitySetting;
|
|
237
255
|
let id: string = initSetting.generateID();
|
|
238
256
|
const nameIDFormat = initSetting.nameIDFormat;
|
|
@@ -272,12 +290,13 @@ function logoutRequestRedirectURL(user, entity, relayState?: string, customTagRe
|
|
|
272
290
|
}
|
|
273
291
|
throw new Error('ERR_GENERATE_REDIRECT_LOGOUT_REQUEST_MISSING_METADATA');
|
|
274
292
|
}
|
|
293
|
+
|
|
275
294
|
/**
|
|
276
|
-
* @desc Redirect URL for logout response
|
|
277
|
-
* @param {object} requescorresponding request, used to obtain the id
|
|
278
|
-
* @param {object} entity object includes both idp and sp
|
|
279
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
280
|
-
*/
|
|
295
|
+
* @desc Redirect URL for logout response
|
|
296
|
+
* @param {object} requescorresponding request, used to obtain the id
|
|
297
|
+
* @param {object} entity object includes both idp and sp
|
|
298
|
+
* @param {function} customTagReplacement used when developers have their own login response template
|
|
299
|
+
*/
|
|
281
300
|
function logoutResponseRedirectURL(requestInfo: any, entity: any, relayState?: string, customTagReplacement?: (template: string) => BindingContext): BindingContext {
|
|
282
301
|
const metadata = {
|
|
283
302
|
init: entity.init.entityMeta,
|
package/src/entity-idp.ts
CHANGED
|
@@ -3,12 +3,19 @@
|
|
|
3
3
|
* @author tngan
|
|
4
4
|
* @desc Declares the actions taken by identity provider
|
|
5
5
|
*/
|
|
6
|
+
import {
|
|
7
|
+
wording,
|
|
8
|
+
} from './urn.js';
|
|
9
|
+
const binding = wording.binding
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
import Entity, { ESamlHttpRequest } from './entity.js';
|
|
7
14
|
import {
|
|
8
15
|
ServiceProviderConstructor as ServiceProvider,
|
|
9
16
|
ServiceProviderMetadata,
|
|
10
17
|
IdentityProviderMetadata,
|
|
11
|
-
IdentityProviderSettings
|
|
18
|
+
IdentityProviderSettings
|
|
12
19
|
} from './types.js';
|
|
13
20
|
import libsaml from './libsaml.js';
|
|
14
21
|
import { namespace } from './urn.js';
|
|
@@ -71,25 +78,21 @@ export class IdentityProvider extends Entity {
|
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
/**
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
*/
|
|
83
|
-
public async createLoginResponse(
|
|
84
|
-
sp: ServiceProvider,
|
|
85
|
-
requestInfo: { [key: string]: any },
|
|
86
|
-
binding: string,
|
|
87
|
-
user: { [key: string]: any },
|
|
81
|
+
* @desc Generates the login response for developers to design their own method
|
|
82
|
+
* @param params
|
|
83
|
+
*/
|
|
84
|
+
public async createLoginResponse(params:{
|
|
85
|
+
sp: ServiceProvider;
|
|
86
|
+
requestInfo: Record<string, any>;
|
|
87
|
+
binding?: string; // 可选参数,带默认值
|
|
88
|
+
user: Record<string, any>;
|
|
88
89
|
customTagReplacement?: (template: string) => BindingContext,
|
|
89
90
|
encryptThenSign?: boolean,
|
|
90
91
|
relayState?: string,
|
|
91
|
-
) {
|
|
92
|
-
|
|
92
|
+
}) {
|
|
93
|
+
const bindType = params?.binding ?? 'post';
|
|
94
|
+
const { sp,requestInfo ={}, user = {},customTagReplacement,encryptThenSign = false ,relayState=''} = params
|
|
95
|
+
const protocol = namespace.binding[bindType];
|
|
93
96
|
// can support post, redirect and post simple sign bindings for login response
|
|
94
97
|
let context: any = null;
|
|
95
98
|
switch (protocol) {
|
|
@@ -111,15 +114,18 @@ export class IdentityProvider extends Entity {
|
|
|
111
114
|
idp: this,
|
|
112
115
|
sp,
|
|
113
116
|
}, user, relayState, customTagReplacement);
|
|
114
|
-
|
|
115
117
|
default:
|
|
116
|
-
|
|
118
|
+
context = await postBinding.base64LoginResponse(requestInfo, {
|
|
119
|
+
idp: this,
|
|
120
|
+
sp,
|
|
121
|
+
}, user, customTagReplacement, encryptThenSign);
|
|
122
|
+
/* throw new Error('ERR_CREATE_RESPONSE_UNDEFINED_BINDING');*/
|
|
117
123
|
}
|
|
118
124
|
|
|
119
125
|
return {
|
|
120
126
|
...context,
|
|
121
127
|
relayState,
|
|
122
|
-
entityEndpoint: (sp.entityMeta as ServiceProviderMetadata).getAssertionConsumerService(
|
|
128
|
+
entityEndpoint: (sp.entityMeta as ServiceProviderMetadata).getAssertionConsumerService(bindType ?? 'post') as string,
|
|
123
129
|
type: 'SAMLResponse'
|
|
124
130
|
};
|
|
125
131
|
}
|
package/src/libsaml.ts
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
* @author tngan
|
|
4
4
|
* @desc A simple library including some common functions
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
import { createSign, createPrivateKey,createVerify } from 'node:crypto';
|
|
7
7
|
import utility, { flattenDeep, isString } from './utility.js';
|
|
8
8
|
import { algorithms, wording, namespace } from './urn.js';
|
|
9
9
|
import { select } from 'xpath';
|
|
10
10
|
import { MetadataInterface } from './metadata.js';
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
import { SignedXml } from 'xml-crypto';
|
|
13
13
|
import * as xmlenc from 'xml-encryption';
|
|
14
14
|
import { extract } from './extractor.js';
|
|
@@ -22,7 +22,22 @@ const signatureAlgorithms = algorithms.signature;
|
|
|
22
22
|
const digestAlgorithms = algorithms.digest;
|
|
23
23
|
const certUse = wording.certUse;
|
|
24
24
|
const urlParams = wording.urlParams;
|
|
25
|
+
/**
|
|
26
|
+
* 算法名称映射表 (兼容 X.509 和 SAML 规范)
|
|
27
|
+
*/
|
|
28
|
+
function mapSignAlgorithm(algorithm: string): string {
|
|
29
|
+
const algorithmMap = {
|
|
30
|
+
'rsa-sha1': 'RSA-SHA1',
|
|
31
|
+
'rsa-sha256': 'RSA-SHA256',
|
|
32
|
+
'rsa-sha384': 'RSA-SHA384',
|
|
33
|
+
'rsa-sha512': 'RSA-SHA512',
|
|
34
|
+
'ecdsa-sha256': 'ECDSA-SHA256',
|
|
35
|
+
'ecdsa-sha384': 'ECDSA-SHA384',
|
|
36
|
+
'ecdsa-sha512': 'ECDSA-SHA512'
|
|
37
|
+
};
|
|
25
38
|
|
|
39
|
+
return algorithmMap[algorithm.toLowerCase()] || algorithm;
|
|
40
|
+
}
|
|
26
41
|
export interface SignatureConstructor {
|
|
27
42
|
rawSamlMessage: string;
|
|
28
43
|
referenceTagXPath?: string;
|
|
@@ -139,6 +154,11 @@ const libSaml = () => {
|
|
|
139
154
|
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256': 'pkcs1-sha256',
|
|
140
155
|
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512': 'pkcs1-sha512',
|
|
141
156
|
};
|
|
157
|
+
const nrsaAliasMappingForNode = {
|
|
158
|
+
'http://www.w3.org/2000/09/xmldsig#rsa-sha1': 'RSA-SHA1',
|
|
159
|
+
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256': 'RSA-SHA256',
|
|
160
|
+
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512': 'RSA-SHA512',
|
|
161
|
+
};
|
|
142
162
|
/**
|
|
143
163
|
* @desc Default login request template
|
|
144
164
|
* @type {LoginRequestTemplate}
|
|
@@ -189,20 +209,15 @@ const libSaml = () => {
|
|
|
189
209
|
const defaultLogoutResponseTemplate = {
|
|
190
210
|
context: '<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="{ID}" Version="2.0" IssueInstant="{IssueInstant}" Destination="{Destination}" InResponseTo="{InResponseTo}"><saml:Issuer>{Issuer}</saml:Issuer><samlp:Status><samlp:StatusCode Value="{StatusCode}"/></samlp:Status></samlp:LogoutResponse>',
|
|
191
211
|
};
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
* @desc Get the signing scheme alias by signature algorithms, used by the node-rsa module
|
|
195
|
-
* @param {string} sigAlg signature algorithm
|
|
196
|
-
* @return {string/null} signing algorithm short-hand for the module node-rsa
|
|
197
|
-
*/
|
|
198
|
-
function getSigningScheme(sigAlg?: string): SigningSchemeHash {
|
|
212
|
+
|
|
213
|
+
function getSigningSchemeForNode(sigAlg?: string){
|
|
199
214
|
if (sigAlg) {
|
|
200
|
-
const algAlias =
|
|
215
|
+
const algAlias = nrsaAliasMappingForNode[sigAlg];
|
|
201
216
|
if (!(algAlias === undefined)) {
|
|
202
217
|
return algAlias;
|
|
203
218
|
}
|
|
204
219
|
}
|
|
205
|
-
return
|
|
220
|
+
return nrsaAliasMappingForNode[signatureAlgorithms.RSA_SHA256];
|
|
206
221
|
}
|
|
207
222
|
/**
|
|
208
223
|
* @private
|
|
@@ -587,42 +602,51 @@ const libSaml = () => {
|
|
|
587
602
|
}],
|
|
588
603
|
};
|
|
589
604
|
},
|
|
605
|
+
|
|
590
606
|
/**
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
607
|
+
* SAML 消息签名 (符合 SAML V2.0 绑定规范)
|
|
608
|
+
* @param octetString - 要签名的原始数据 (OCTET STRING)
|
|
609
|
+
* @param key - PEM 格式私钥
|
|
610
|
+
* @param passphrase - 私钥密码 (如果有加密)
|
|
611
|
+
* @param isBase64 - 是否返回 base64 编码 (默认 true)
|
|
612
|
+
* @param signingAlgorithm - 签名算法 (默认 'rsa-sha256')
|
|
613
|
+
* @returns 消息签名
|
|
614
|
+
*/
|
|
615
|
+
|
|
598
616
|
constructMessageSignature(
|
|
599
|
-
octetString: string,
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
//
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
617
|
+
octetString: string | Buffer,
|
|
618
|
+
key: string | Buffer,
|
|
619
|
+
passphrase?: string,
|
|
620
|
+
isBase64: boolean = true,
|
|
621
|
+
signingAlgorithm: string = nrsaAliasMappingForNode[signatureAlgorithms.RSA_SHA256]
|
|
622
|
+
): string | Buffer {
|
|
623
|
+
try {
|
|
624
|
+
// 1. 标准化输入数据
|
|
625
|
+
const inputData = Buffer.isBuffer(octetString)
|
|
626
|
+
? octetString
|
|
627
|
+
: Buffer.from(octetString, 'utf8');
|
|
628
|
+
// 2. 创建签名器并设置算
|
|
629
|
+
const signingAlgorithmValue = getSigningSchemeForNode(signingAlgorithm)
|
|
630
|
+
const signer = createSign(signingAlgorithmValue)
|
|
631
|
+
|
|
632
|
+
// 3. 加载私钥
|
|
633
|
+
const privateKey = createPrivateKey({
|
|
634
|
+
key: key,
|
|
635
|
+
format: 'pem',
|
|
636
|
+
passphrase: passphrase,
|
|
637
|
+
encoding: 'utf8'
|
|
638
|
+
});
|
|
639
|
+
signer.write(octetString);
|
|
640
|
+
signer.end();
|
|
641
|
+
const signature = signer.sign(privateKey, 'base64');
|
|
642
|
+
console.log(signature.toString());
|
|
643
|
+
console.log('dayingyixia')
|
|
644
|
+
// 5. 处理编码输出
|
|
645
|
+
return isBase64 ? signature.toString() : signature;
|
|
646
|
+
} catch (error) {
|
|
647
|
+
throw new Error(`SAML 签名失败: ${error.message}`);
|
|
648
|
+
}
|
|
649
|
+
},
|
|
626
650
|
verifyMessageSignature(
|
|
627
651
|
metadata,
|
|
628
652
|
octetString: string,
|
|
@@ -630,10 +654,17 @@ const libSaml = () => {
|
|
|
630
654
|
verifyAlgorithm?: string
|
|
631
655
|
) {
|
|
632
656
|
const signCert = metadata.getX509Certificate(certUse.signing);
|
|
633
|
-
const signingScheme =
|
|
634
|
-
const
|
|
635
|
-
|
|
657
|
+
const signingScheme = getSigningSchemeForNode(verifyAlgorithm);
|
|
658
|
+
const verifier = createVerify(signingScheme);
|
|
659
|
+
verifier.update(octetString);
|
|
660
|
+
const isValid = verifier.verify(utility.getPublicKeyPemFromCertificate(signCert), Buffer.isBuffer(signature) ? signature : Buffer.from(signature, 'base64'));
|
|
661
|
+
console.log(isValid);
|
|
662
|
+
console.log('验证结果-------------')
|
|
663
|
+
return isValid
|
|
664
|
+
|
|
636
665
|
},
|
|
666
|
+
|
|
667
|
+
|
|
637
668
|
/**
|
|
638
669
|
* @desc Get the public key in string format
|
|
639
670
|
* @param {string} x509Certificate certificate
|