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.

@@ -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
- async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any = {}, customTagReplacement?: (template: string) => BindingContext, encryptThenSign: boolean = false): Promise<BindingContext> {
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: string;
95
- const nowTime = new Date();
96
- const spEntityID = metadata.sp.getEntityID();
97
- const fiveMinutesLaterTime = new Date(nowTime.getTime());
98
- fiveMinutesLaterTime.setMinutes(fiveMinutesLaterTime.getMinutes() + 5);
99
- const fiveMinutesLater = fiveMinutesLaterTime.toISOString();
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: fiveMinutesLater,
116
- SubjectConfirmationDataNotOnOrAfter: fiveMinutesLater,
124
+ ConditionsNotOnOrAfter: OneMinutesLater,
125
+ SubjectConfirmationDataNotOnOrAfter: OneMinutesLater,
117
126
  NameIDFormat: selectedNameIDFormat,
118
- NameID: user.NameID || '',
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.extract.request.id ?? '';
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
  /**
@@ -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.extract.request.id;
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.extract.request.id;
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
- async function base64LoginResponse(requestInfo: any = {}, entity: any, user: any = {}, relayState?: string, customTagReplacement?: (template: string) => BindingContext): Promise<BindingSimpleSignContext> {
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.extract.request.id;
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',