samlesa 2.12.9 → 2.12.11
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/.idea/deployment.xml +14 -0
- package/build/src/binding-post.js +26 -21
- package/build/src/binding-post.js.map +1 -1
- package/build/src/binding-redirect.js +12 -5
- package/build/src/binding-redirect.js.map +1 -1
- package/build/src/binding-simplesign.js +18 -11
- package/build/src/binding-simplesign.js.map +1 -1
- package/build/src/entity-idp.js +21 -26
- package/build/src/entity-idp.js.map +1 -1
- package/build/src/extractor.js +1 -1
- package/build/src/extractor.js.map +1 -1
- package/build/src/libsaml.js +149 -104
- package/build/src/libsaml.js.map +1 -1
- package/build/src/validator.js.map +1 -1
- package/package.json +70 -70
- package/src/binding-post.ts +31 -22
- package/src/binding-redirect.ts +12 -6
- package/src/binding-simplesign.ts +18 -11
- package/src/entity-idp.ts +9 -7
- package/src/extractor.ts +1 -1
- package/src/libsaml.ts +272 -208
- package/src/validator.ts +2 -7
- package/types/src/binding-post.d.ts +9 -8
- package/types/src/binding-redirect.d.ts +2 -1
- package/types/src/binding-simplesign.d.ts +9 -8
- package/types/src/entity-idp.d.ts +2 -0
- package/types/src/libsaml.d.ts +56 -47
- package/.idea/inspectionProfiles/Project_Default.xml +0 -6
- package/src/.idea/modules.xml +0 -8
- package/src/.idea/src.iml +0 -12
- package/src/.idea/vcs.xml +0 -6
package/src/binding-post.ts
CHANGED
|
@@ -72,14 +72,15 @@ function base64LoginRequest(referenceTagXPath: string, entity: any, customTagRep
|
|
|
72
72
|
throw new Error('ERR_GENERATE_POST_LOGIN_REQUEST_MISSING_METADATA');
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
|
-
* @desc Generate a base64 encoded login response
|
|
76
|
-
* @param {object} requestInfo corresponding request, used to obtain the id
|
|
77
|
-
* @param {object} entity object includes both idp and sp
|
|
78
|
-
* @param {object} user current logged user (e.g. req.user)
|
|
79
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
80
|
-
* @param {boolean} encryptThenSign whether or not to encrypt then sign first (if signing). Defaults to sign-then-encrypt
|
|
81
|
-
|
|
82
|
-
|
|
75
|
+
* @desc Generate a base64 encoded login response
|
|
76
|
+
* @param {object} requestInfo corresponding request, used to obtain the id
|
|
77
|
+
* @param {object} entity object includes both idp and sp
|
|
78
|
+
* @param {object} user current logged user (e.g. req.user)
|
|
79
|
+
* @param {function} customTagReplacement used when developers have their own login response template
|
|
80
|
+
* @param {boolean} encryptThenSign whether or not to encrypt then sign first (if signing). Defaults to sign-then-encrypt
|
|
81
|
+
* @param AttributeStatement
|
|
82
|
+
*/
|
|
83
|
+
async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any = {}, customTagReplacement?: (template: string) => BindingContext, encryptThenSign: boolean = false , AttributeStatement=[]): Promise<BindingContext> {
|
|
83
84
|
const idpSetting = entity.idp.entitySetting;
|
|
84
85
|
const spSetting = entity.sp.entitySetting;
|
|
85
86
|
const id = idpSetting.generateID();
|
|
@@ -89,16 +90,24 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any
|
|
|
89
90
|
};
|
|
90
91
|
const nameIDFormat = idpSetting.nameIDFormat;
|
|
91
92
|
const selectedNameIDFormat = Array.isArray(nameIDFormat) ? nameIDFormat[0] : nameIDFormat;
|
|
93
|
+
|
|
94
|
+
|
|
92
95
|
if (metadata && metadata.idp && metadata.sp) {
|
|
93
96
|
const base = metadata.sp.getAssertionConsumerService(binding.post);
|
|
94
|
-
let rawSamlResponse
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const
|
|
97
|
+
let rawSamlResponse;
|
|
98
|
+
let nowTime = new Date();
|
|
99
|
+
let spEntityID = metadata.sp.getEntityID();
|
|
100
|
+
let oneMinutesLaterTime = new Date(nowTime.getTime());
|
|
101
|
+
oneMinutesLaterTime.setMinutes(oneMinutesLaterTime.getMinutes() + 5);
|
|
102
|
+
const OneMinutesLater = oneMinutesLaterTime.toISOString();
|
|
100
103
|
const now = nowTime.toISOString();
|
|
104
|
+
console.log(`现在是北京时间:${nowTime.toLocaleString()}`)
|
|
105
|
+
console.log(`现在是两分钟时间:${oneMinutesLaterTime.toLocaleString()}`)
|
|
101
106
|
const acl = metadata.sp.getAssertionConsumerService(binding.post);
|
|
107
|
+
const sessionIndex = 'session'+idpSetting.generateID(); // 这个是当前系统的会话索引,用于单点注销
|
|
108
|
+
const tenHoursLaterTime = new Date(nowTime.getTime());
|
|
109
|
+
tenHoursLaterTime.setHours(tenHoursLaterTime.getHours() + 10);
|
|
110
|
+
const tenHoursLater = tenHoursLaterTime.toISOString();
|
|
102
111
|
const tvalue: any = {
|
|
103
112
|
ID: id,
|
|
104
113
|
AssertionID: idpSetting.generateID(),
|
|
@@ -112,20 +121,20 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any
|
|
|
112
121
|
StatusCode: StatusCode.Success,
|
|
113
122
|
// can be customized
|
|
114
123
|
ConditionsNotBefore: now,
|
|
115
|
-
ConditionsNotOnOrAfter:
|
|
116
|
-
SubjectConfirmationDataNotOnOrAfter:
|
|
124
|
+
ConditionsNotOnOrAfter: OneMinutesLater,
|
|
125
|
+
SubjectConfirmationDataNotOnOrAfter: OneMinutesLater,
|
|
117
126
|
NameIDFormat: selectedNameIDFormat,
|
|
118
|
-
NameID: user
|
|
127
|
+
NameID: user?.NameID || '',
|
|
119
128
|
InResponseTo: get(requestInfo, 'extract.request.id', ''),
|
|
120
|
-
AuthnStatement:
|
|
121
|
-
AttributeStatement:
|
|
129
|
+
AuthnStatement: `<saml:AuthnStatement AuthnInstant="${now}" SessionNotOnOrAfter="${tenHoursLater}" SessionIndex="${sessionIndex}"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement>`,
|
|
130
|
+
AttributeStatement: libsaml.attributeStatementBuilder(AttributeStatement),
|
|
122
131
|
};
|
|
123
132
|
if (idpSetting.loginResponseTemplate && customTagReplacement) {
|
|
124
133
|
const template = customTagReplacement(idpSetting.loginResponseTemplate.context);
|
|
125
134
|
rawSamlResponse = get(template, 'context', null);
|
|
126
135
|
} else {
|
|
127
136
|
if (requestInfo !== null) {
|
|
128
|
-
tvalue.InResponseTo = requestInfo
|
|
137
|
+
tvalue.InResponseTo = requestInfo?.extract?.request?.id ?? '';
|
|
129
138
|
}
|
|
130
139
|
rawSamlResponse = libsaml.replaceTagsByValue(libsaml.defaultLoginResponseTemplate.context, tvalue);
|
|
131
140
|
}
|
|
@@ -167,8 +176,6 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any
|
|
|
167
176
|
location: { reference: "/*[local-name(.)='Response']/*[local-name(.)='Issuer']", action: 'after' },
|
|
168
177
|
},
|
|
169
178
|
});
|
|
170
|
-
console.log(rawSamlResponse);
|
|
171
|
-
console.log('这他妈是什么------------------')
|
|
172
179
|
}
|
|
173
180
|
|
|
174
181
|
// console.debug('after message signed', rawSamlResponse);
|
|
@@ -204,6 +211,8 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any
|
|
|
204
211
|
});
|
|
205
212
|
|
|
206
213
|
}
|
|
214
|
+
|
|
215
|
+
|
|
207
216
|
throw new Error('ERR_GENERATE_POST_LOGIN_RESPONSE_MISSING_METADATA');
|
|
208
217
|
}
|
|
209
218
|
/**
|
package/src/binding-redirect.ts
CHANGED
|
@@ -144,8 +144,9 @@ function loginRequestRedirectURL(entity: {
|
|
|
144
144
|
* @param {object} user current logged user (e.g. req.user)
|
|
145
145
|
* @param {String} relayState the relaystate sent by sp corresponding request
|
|
146
146
|
* @param {function} customTagReplacement used when developers have their own login response template
|
|
147
|
+
* @param AttributeStatement
|
|
147
148
|
*/
|
|
148
|
-
function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {}, relayState?: string, customTagReplacement?: (template: string) => BindingContext): BindingContext {
|
|
149
|
+
function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {}, relayState?: string, customTagReplacement?: (template: string) => BindingContext,AttributeStatement =[]): BindingContext {
|
|
149
150
|
const idpSetting = entity.idp.entitySetting;
|
|
150
151
|
const spSetting = entity.sp.entitySetting;
|
|
151
152
|
const metadata = {
|
|
@@ -159,7 +160,6 @@ function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {},
|
|
|
159
160
|
if(!base){
|
|
160
161
|
throw new Error('dont have a base url');
|
|
161
162
|
}
|
|
162
|
-
|
|
163
163
|
let rawSamlResponse: string;
|
|
164
164
|
//
|
|
165
165
|
const nameIDFormat = idpSetting.nameIDFormat;
|
|
@@ -167,6 +167,12 @@ function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {},
|
|
|
167
167
|
const nowTime = new Date();
|
|
168
168
|
// Five minutes later : nowtime + 5 * 60 * 1000 (in milliseconds)
|
|
169
169
|
const fiveMinutesLaterTime = new Date(nowTime.getTime() + 300_000);
|
|
170
|
+
const now = nowTime.toISOString();
|
|
171
|
+
console.log(`现在是北京时间:${nowTime.toLocaleString()}`)
|
|
172
|
+
const sessionIndex = 'session'+idpSetting.generateID(); // 这个是当前系统的会话索引,用于单点注销
|
|
173
|
+
const tenHoursLaterTime = new Date(nowTime.getTime());
|
|
174
|
+
tenHoursLaterTime.setHours(tenHoursLaterTime.getHours() + 10);
|
|
175
|
+
const tenHoursLater = tenHoursLaterTime.toISOString();
|
|
170
176
|
const tvalue: any = {
|
|
171
177
|
ID: id,
|
|
172
178
|
AssertionID: idpSetting.generateID(),
|
|
@@ -185,8 +191,8 @@ function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {},
|
|
|
185
191
|
NameIDFormat: selectedNameIDFormat,
|
|
186
192
|
NameID: user.NameID || '',
|
|
187
193
|
InResponseTo: get(requestInfo, 'extract.request.id', ''),
|
|
188
|
-
AuthnStatement:
|
|
189
|
-
AttributeStatement:
|
|
194
|
+
AuthnStatement: `<saml:AuthnStatement AuthnInstant="${now}" SessionNotOnOrAfter="${tenHoursLater}" SessionIndex="${sessionIndex}"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement>`,
|
|
195
|
+
AttributeStatement: libsaml.attributeStatementBuilder(AttributeStatement),
|
|
190
196
|
};
|
|
191
197
|
|
|
192
198
|
if (idpSetting.loginResponseTemplate && customTagReplacement) {
|
|
@@ -196,7 +202,7 @@ function loginResponseRedirectURL(requestInfo: any, entity: any, user: any = {},
|
|
|
196
202
|
} else {
|
|
197
203
|
|
|
198
204
|
if (requestInfo !== null) {
|
|
199
|
-
tvalue.InResponseTo = requestInfo
|
|
205
|
+
tvalue.InResponseTo = requestInfo?.extract?.request?.id;
|
|
200
206
|
}
|
|
201
207
|
rawSamlResponse = libsaml.replaceTagsByValue(libsaml.defaultLoginResponseTemplate.context, tvalue);
|
|
202
208
|
}
|
|
@@ -321,7 +327,7 @@ function logoutResponseRedirectURL(requestInfo: any, entity: any, relayState?: s
|
|
|
321
327
|
StatusCode: namespace.statusCode.success,
|
|
322
328
|
};
|
|
323
329
|
if (requestInfo && requestInfo.extract && requestInfo.extract.request) {
|
|
324
|
-
tvalue.InResponseTo = requestInfo
|
|
330
|
+
tvalue.InResponseTo = requestInfo?.extract?.request?.id;
|
|
325
331
|
}
|
|
326
332
|
rawSamlResponse = libsaml.replaceTagsByValue(libsaml.defaultLogoutResponseTemplate.context, tvalue);
|
|
327
333
|
}
|
|
@@ -127,14 +127,15 @@ function base64LoginRequest(entity: any, customTagReplacement?: (template: strin
|
|
|
127
127
|
throw new Error('ERR_GENERATE_POST_SIMPLESIGN_LOGIN_REQUEST_MISSING_METADATA');
|
|
128
128
|
}
|
|
129
129
|
/**
|
|
130
|
-
* @desc Generate a base64 encoded 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 relay state
|
|
135
|
-
* @param {function} customTagReplacement used when developers have their own login response template
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
* @desc Generate a base64 encoded 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 relay state
|
|
135
|
+
* @param {function} customTagReplacement used when developers have their own login response template
|
|
136
|
+
* @param AttributeStatement
|
|
137
|
+
*/
|
|
138
|
+
async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any = {}, relayState?: string, customTagReplacement?: (template: string) => BindingContext, AttributeStatement:[] = []): Promise<BindingSimpleSignContext> {
|
|
138
139
|
const idpSetting = entity.idp.entitySetting;
|
|
139
140
|
const spSetting = entity.sp.entitySetting;
|
|
140
141
|
const id = idpSetting.generateID();
|
|
@@ -150,6 +151,12 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any
|
|
|
150
151
|
const nowTime = new Date();
|
|
151
152
|
// Five minutes later : nowtime + 5 * 60 * 1000 (in milliseconds)
|
|
152
153
|
const fiveMinutesLaterTime = new Date(nowTime.getTime() + 300_000 );
|
|
154
|
+
const now = nowTime.toISOString();
|
|
155
|
+
console.log(`现在是北京时间:${nowTime.toLocaleString()}`)
|
|
156
|
+
const sessionIndex = 'session'+idpSetting.generateID(); // 这个是当前系统的会话索引,用于单点注销
|
|
157
|
+
const tenHoursLaterTime = new Date(nowTime.getTime());
|
|
158
|
+
tenHoursLaterTime.setHours(tenHoursLaterTime.getHours() + 10);
|
|
159
|
+
const tenHoursLater = tenHoursLaterTime.toISOString();
|
|
153
160
|
const tvalue: any = {
|
|
154
161
|
ID: id,
|
|
155
162
|
AssertionID: idpSetting.generateID(),
|
|
@@ -168,15 +175,15 @@ async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any
|
|
|
168
175
|
NameIDFormat: selectedNameIDFormat,
|
|
169
176
|
NameID: user.NameID || '',
|
|
170
177
|
InResponseTo: get(requestInfo, 'extract.request.id', ''),
|
|
171
|
-
AuthnStatement:
|
|
172
|
-
AttributeStatement:
|
|
178
|
+
AuthnStatement: `<saml:AuthnStatement AuthnInstant="${now}" SessionNotOnOrAfter="${tenHoursLater}" SessionIndex="${sessionIndex}"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement>`,
|
|
179
|
+
AttributeStatement: libsaml.attributeStatementBuilder(AttributeStatement),
|
|
173
180
|
};
|
|
174
181
|
if (idpSetting.loginResponseTemplate && customTagReplacement) {
|
|
175
182
|
const template = customTagReplacement(idpSetting.loginResponseTemplate.context);
|
|
176
183
|
rawSamlResponse = get(template, 'context', null);
|
|
177
184
|
} else {
|
|
178
185
|
if (requestInfo !== null) {
|
|
179
|
-
tvalue.InResponseTo = requestInfo
|
|
186
|
+
tvalue.InResponseTo = requestInfo?.extract?.request?.id;
|
|
180
187
|
}
|
|
181
188
|
rawSamlResponse = libsaml.replaceTagsByValue(libsaml.defaultLoginResponseTemplate.context, tvalue);
|
|
182
189
|
}
|
package/src/entity-idp.ts
CHANGED
|
@@ -49,7 +49,7 @@ export class IdentityProvider extends Entity {
|
|
|
49
49
|
};
|
|
50
50
|
const entitySetting = Object.assign(defaultIdpEntitySetting, idpSetting);
|
|
51
51
|
// build attribute part
|
|
52
|
-
if (idpSetting.loginResponseTemplate) {
|
|
52
|
+
/* if (idpSetting.loginResponseTemplate) {
|
|
53
53
|
if (isString(idpSetting.loginResponseTemplate.context) && Array.isArray(idpSetting.loginResponseTemplate.attributes)) {
|
|
54
54
|
let attributeStatementTemplate;
|
|
55
55
|
let attributeTemplate;
|
|
@@ -73,7 +73,7 @@ export class IdentityProvider extends Entity {
|
|
|
73
73
|
} else {
|
|
74
74
|
console.warn('Invalid login response template');
|
|
75
75
|
}
|
|
76
|
-
}
|
|
76
|
+
}*/
|
|
77
77
|
super(entitySetting, 'idp');
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -89,9 +89,11 @@ export class IdentityProvider extends Entity {
|
|
|
89
89
|
customTagReplacement?: (template: string) => BindingContext,
|
|
90
90
|
encryptThenSign?: boolean,
|
|
91
91
|
relayState?: string,
|
|
92
|
+
context: Record<string, any>,
|
|
93
|
+
AttributeStatement:[]
|
|
92
94
|
}) {
|
|
93
95
|
const bindType = params?.binding ?? 'post';
|
|
94
|
-
const { sp,requestInfo ={}, user = {},customTagReplacement,encryptThenSign = false ,relayState=''} = params
|
|
96
|
+
const { sp,requestInfo ={}, user = {},customTagReplacement,encryptThenSign = false ,relayState='',AttributeStatement= [] } = params
|
|
95
97
|
const protocol = namespace.binding[bindType];
|
|
96
98
|
// can support post, redirect and post simple sign bindings for login response
|
|
97
99
|
let context: any = null;
|
|
@@ -100,25 +102,25 @@ const bindType = params?.binding ?? 'post';
|
|
|
100
102
|
context = await postBinding.base64LoginResponse(requestInfo, {
|
|
101
103
|
idp: this,
|
|
102
104
|
sp,
|
|
103
|
-
}, user, customTagReplacement, encryptThenSign);
|
|
105
|
+
}, user, customTagReplacement, encryptThenSign,AttributeStatement);
|
|
104
106
|
break;
|
|
105
107
|
|
|
106
108
|
case namespace.binding.simpleSign:
|
|
107
109
|
context = await simpleSignBinding.base64LoginResponse( requestInfo, {
|
|
108
110
|
idp: this, sp,
|
|
109
|
-
}, user, relayState, customTagReplacement);
|
|
111
|
+
}, user, relayState, customTagReplacement,AttributeStatement);
|
|
110
112
|
break;
|
|
111
113
|
|
|
112
114
|
case namespace.binding.redirect:
|
|
113
115
|
return redirectBinding.loginResponseRedirectURL(requestInfo, {
|
|
114
116
|
idp: this,
|
|
115
117
|
sp,
|
|
116
|
-
}, user, relayState, customTagReplacement);
|
|
118
|
+
}, user, relayState, customTagReplacement,AttributeStatement);
|
|
117
119
|
default:
|
|
118
120
|
context = await postBinding.base64LoginResponse(requestInfo, {
|
|
119
121
|
idp: this,
|
|
120
122
|
sp,
|
|
121
|
-
}, user, customTagReplacement, encryptThenSign);
|
|
123
|
+
}, user, customTagReplacement, encryptThenSign,AttributeStatement);
|
|
122
124
|
/* throw new Error('ERR_CREATE_RESPONSE_UNDEFINED_BINDING');*/
|
|
123
125
|
}
|
|
124
126
|
|
package/src/extractor.ts
CHANGED
|
@@ -44,7 +44,7 @@ export const loginRequestFields: ExtractorFields = [
|
|
|
44
44
|
{
|
|
45
45
|
key: 'request',
|
|
46
46
|
localPath: ['AuthnRequest'],
|
|
47
|
-
attributes: ['ID', 'IssueInstant', 'Destination', 'AssertionConsumerServiceURL']
|
|
47
|
+
attributes: ['ID', 'IssueInstant', 'Destination', 'AssertionConsumerServiceURL','ProtocolBinding','ForceAuthn','IsPassive','AssertionConsumerServiceIndex','AttributeConsumingServiceIndex']
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
key: 'issuer',
|