@steedos/accounts 2.5.3-beta.13 → 2.5.3-beta.15

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.
@@ -1,684 +0,0 @@
1
- /**
2
- * Module dependencies.
3
- */
4
- var tslib_1 = require("tslib");
5
- var chalk = require('chalk'), express = require('express'), os = require('os'), fs = require('fs'), http = require('http'), https = require('https'), path = require('path'), extend = require('extend'), hbs = require('hbs'), logger = require('morgan'), bodyParser = require('body-parser'), session = require('express-session'), yargs = require('yargs/yargs'), xmlFormat = require('xml-formatter'), samlp = require('samlp'), Parser = require('xmldom').DOMParser, SessionParticipants = require('samlp/lib/sessionParticipants'), SimpleProfileMapper = require('./simpleProfileMapper.js');
6
- /**
7
- * Globals
8
- */
9
- var IDP_PATHS = {
10
- SSO: '/idp/sso',
11
- SLO: '/idp/slo',
12
- METADATA: '/metadata',
13
- SIGN_IN: '/signin',
14
- SIGN_OUT: '/signout',
15
- SETTINGS: '/settings'
16
- };
17
- var CERT_OPTIONS = [
18
- 'cert',
19
- 'key',
20
- 'encryptionCert',
21
- 'encryptionPublicKey',
22
- 'httpsPrivateKey',
23
- 'httpsCert',
24
- ];
25
- var WILDCARD_ADDRESSES = ['0.0.0.0', '::'];
26
- var UNDEFINED_VALUE = 'None';
27
- var CRYPT_TYPES = {
28
- certificate: /-----BEGIN CERTIFICATE-----[^-]*-----END CERTIFICATE-----/,
29
- 'RSA private key': /-----BEGIN RSA PRIVATE KEY-----\n[^-]*\n-----END RSA PRIVATE KEY-----/,
30
- 'public key': /-----BEGIN PUBLIC KEY-----\n[^-]*\n-----END PUBLIC KEY-----/,
31
- };
32
- var KEY_CERT_HELP_TEXT = dedent(chalk(tslib_1.__makeTemplateObject(["\n To generate a key/cert pair for the IdP, run the following command:\n\n {gray openssl req -x509 -new -newkey rsa:2048 -nodes -subj '/C=US/ST=California/L=San Francisco/O=JankyCo/CN=Test Identity Provider' -keyout idp-private-key.pem -out idp-public-cert.pem -days 7300}"], ["\n To generate a key/cert pair for the IdP, run the following command:\n\n {gray openssl req -x509 -new -newkey rsa:2048 -nodes \\\n -subj '/C=US/ST=California/L=San Francisco/O=JankyCo/CN=Test Identity Provider' \\\n -keyout idp-private-key.pem \\\n -out idp-public-cert.pem -days 7300}"])));
33
- function matchesCertType(value, type) {
34
- return CRYPT_TYPES[type] && CRYPT_TYPES[type].test(value);
35
- }
36
- function resolveFilePath(filePath) {
37
- if (filePath.startsWith('saml-idp/')) {
38
- // Allows file path options to files included in this package, like config.js
39
- var resolvedPath = require.resolve(filePath.replace(/^saml\-idp\//, "".concat(__dirname, "/")));
40
- return fs.existsSync(resolvedPath) && resolvedPath;
41
- }
42
- var possiblePath;
43
- if (fs.existsSync(filePath)) {
44
- return filePath;
45
- }
46
- if (filePath.startsWith('~/')) {
47
- possiblePath = path.resolve(process.env.HOME, filePath.slice(2));
48
- if (fs.existsSync(possiblePath)) {
49
- return possiblePath;
50
- }
51
- else {
52
- // for ~/ paths, don't try to resolve further
53
- return filePath;
54
- }
55
- }
56
- return ['.', __dirname]
57
- .map(function (base) { return path.resolve(base, filePath); })
58
- .find(function (possiblePath) { return fs.existsSync(possiblePath); });
59
- }
60
- function makeCertFileCoercer(type, description, helpText) {
61
- return function certFileCoercer(value) {
62
- if (matchesCertType(value, type)) {
63
- return value;
64
- }
65
- var filePath = resolveFilePath(value);
66
- if (filePath) {
67
- return fs.readFileSync(filePath);
68
- }
69
- throw new Error(chalk(tslib_1.__makeTemplateObject(["{red Invalid / missing {bold ", "}} - {yellow not a valid crypt key/cert or file path}", ""], ["{red Invalid / missing {bold ", "}} - {yellow not a valid crypt key/cert or file path}", ""]), description, helpText ? '\n' + helpText : ''));
70
- };
71
- }
72
- function getHashCode(str) {
73
- var hash = 0;
74
- if (str.length == 0)
75
- return hash;
76
- for (i = 0; i < str.length; i++) {
77
- char = str.charCodeAt(i);
78
- hash = ((hash << 5) - hash) + char;
79
- hash = hash & hash; // Convert to 32bit integer
80
- }
81
- return hash;
82
- }
83
- function dedent(str) {
84
- // Reduce the indentation of all lines by the indentation of the first line
85
- var match = str.match(/^\n?( +)/);
86
- if (!match) {
87
- return str;
88
- }
89
- var indentRe = new RegExp("\n".concat(match[1]), 'g');
90
- return str.replace(indentRe, '\n').replace(/^\n/, '');
91
- }
92
- function formatOptionValue(key, value) {
93
- if (typeof value === 'string') {
94
- return value;
95
- }
96
- if (CERT_OPTIONS.includes(key)) {
97
- return chalk(tslib_1.__makeTemplateObject(["", "{white \u2026}"], ["", "{white \u2026}"]), value.toString()
98
- .replace(/-----.+?-----|\n/g, '')
99
- .substring(0, 80));
100
- }
101
- if (!value && value !== false) {
102
- return UNDEFINED_VALUE;
103
- }
104
- if (typeof value === 'function') {
105
- var lines = "".concat(value).split('\n');
106
- return lines[0].slice(0, -2);
107
- }
108
- return "".concat(JSON.stringify(value));
109
- }
110
- function prettyPrintXml(xml, indent) {
111
- // This works well, because we format the xml before applying the replacements
112
- var prettyXml = xmlFormat(xml, { indentation: ' ' })
113
- // Matches `<{prefix}:{name} .*?>`
114
- .replace(/<(\/)?((?:[\w]+)(?::))?([\w]+)(.*?)>/g, chalk(tslib_1.__makeTemplateObject(["<{green $1$2{bold $3}}$4>"], ["<{green $1$2{bold $3}}$4>"])))
115
- // Matches ` {attribute}="{value}"
116
- .replace(/ ([\w:]+)="(.+?)"/g, chalk(tslib_1.__makeTemplateObject([" {white $1}={cyan \"$2\"}"], [" {white $1}={cyan \"$2\"}"])));
117
- if (indent) {
118
- return prettyXml.replace(/(^|\n)/g, "$1".concat(' '.repeat(indent)));
119
- }
120
- return prettyXml;
121
- }
122
- /**
123
- * Arguments
124
- */
125
- function processArgs(args, options) {
126
- var baseArgv;
127
- if (options) {
128
- baseArgv = yargs(args).config(options);
129
- }
130
- else {
131
- baseArgv = yargs(args);
132
- }
133
- return baseArgv
134
- .usage('\nSimple IdP for SAML 2.0 WebSSO & SLO Profile\n\n' +
135
- 'Launches an IdP web server that mints SAML assertions or logout responses for a Service Provider (SP)\n\n' +
136
- 'Usage:\n\t$0 --acsUrl {url} --audience {uri}')
137
- .alias({ h: 'help' })
138
- .options({
139
- host: {
140
- description: 'IdP Web Server Listener Host',
141
- required: false,
142
- default: 'localhost'
143
- },
144
- port: {
145
- description: 'IdP Web Server Listener Port',
146
- required: true,
147
- alias: 'p',
148
- default: 7000
149
- },
150
- cert: {
151
- description: 'IdP Signature PublicKey Certificate',
152
- required: true,
153
- default: './idp-public-cert.pem',
154
- coerce: makeCertFileCoercer('certificate', 'IdP Signature PublicKey Certificate', KEY_CERT_HELP_TEXT)
155
- },
156
- key: {
157
- description: 'IdP Signature PrivateKey Certificate',
158
- required: true,
159
- default: './idp-private-key.pem',
160
- coerce: makeCertFileCoercer('RSA private key', 'IdP Signature PrivateKey Certificate', KEY_CERT_HELP_TEXT)
161
- },
162
- issuer: {
163
- description: 'IdP Issuer URI',
164
- required: true,
165
- alias: 'iss',
166
- default: 'urn:example:idp'
167
- },
168
- acsUrl: {
169
- description: 'SP Assertion Consumer URL',
170
- required: true,
171
- alias: 'acs'
172
- },
173
- sloUrl: {
174
- description: 'SP Single Logout URL',
175
- required: false,
176
- alias: 'slo'
177
- },
178
- audience: {
179
- description: 'SP Audience URI',
180
- required: true,
181
- alias: 'aud'
182
- },
183
- serviceProviderId: {
184
- description: 'SP Issuer/Entity URI',
185
- required: false,
186
- alias: 'spId',
187
- string: true
188
- },
189
- relayState: {
190
- description: 'Default SAML RelayState for SAMLResponse',
191
- required: false,
192
- alias: 'rs'
193
- },
194
- disableRequestAcsUrl: {
195
- description: 'Disables ability for SP AuthnRequest to specify Assertion Consumer URL',
196
- required: false,
197
- boolean: true,
198
- alias: 'static',
199
- default: false
200
- },
201
- encryptAssertion: {
202
- description: 'Encrypts assertion with SP Public Key',
203
- required: false,
204
- boolean: true,
205
- alias: 'enc',
206
- default: false
207
- },
208
- encryptionCert: {
209
- description: 'SP Certificate (pem) for Assertion Encryption',
210
- required: false,
211
- string: true,
212
- alias: 'encCert',
213
- coerce: makeCertFileCoercer('certificate', 'Encryption cert')
214
- },
215
- encryptionPublicKey: {
216
- description: 'SP RSA Public Key (pem) for Assertion Encryption ' +
217
- '(e.g. openssl x509 -pubkey -noout -in sp-cert.pem)',
218
- required: false,
219
- string: true,
220
- alias: 'encKey',
221
- coerce: makeCertFileCoercer('public key', 'Encryption public key')
222
- },
223
- httpsPrivateKey: {
224
- description: 'Web Server TLS/SSL Private Key (pem)',
225
- required: false,
226
- string: true,
227
- coerce: makeCertFileCoercer('RSA private key')
228
- },
229
- httpsCert: {
230
- description: 'Web Server TLS/SSL Certificate (pem)',
231
- required: false,
232
- string: true,
233
- coerce: makeCertFileCoercer('certificate')
234
- },
235
- https: {
236
- description: 'Enables HTTPS Listener (requires httpsPrivateKey and httpsCert)',
237
- required: true,
238
- boolean: true,
239
- default: false
240
- },
241
- signResponse: {
242
- description: 'Enables signing of responses',
243
- required: false,
244
- boolean: true,
245
- default: true,
246
- alias: 'signResponse'
247
- },
248
- configFile: {
249
- description: 'Path to a SAML attribute config file',
250
- required: true,
251
- default: 'saml-idp/config.js',
252
- alias: 'conf'
253
- },
254
- rollSession: {
255
- description: 'Create a new session for every authn request instead of reusing an existing session',
256
- required: false,
257
- boolean: true,
258
- default: false
259
- },
260
- authnContextClassRef: {
261
- description: 'Authentication Context Class Reference',
262
- required: false,
263
- string: true,
264
- default: 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport',
265
- alias: 'acr'
266
- },
267
- authnContextDecl: {
268
- description: 'Authentication Context Declaration (XML FilePath)',
269
- required: false,
270
- string: true,
271
- alias: 'acd',
272
- coerce: function (value) {
273
- var filePath = resolveFilePath(value);
274
- if (filePath) {
275
- return fs.readFileSync(filePath, 'utf8');
276
- }
277
- }
278
- }
279
- })
280
- .example('$0 --acsUrl http://acme.okta.com/auth/saml20/exampleidp --audience https://www.okta.com/saml2/service-provider/spf5aFRRXFGIMAYXQPNV', '')
281
- .check(function (argv, aliases) {
282
- if (argv.encryptAssertion) {
283
- if (argv.encryptionPublicKey === undefined) {
284
- return 'encryptionPublicKey argument is also required for assertion encryption';
285
- }
286
- if (argv.encryptionCert === undefined) {
287
- return 'encryptionCert argument is also required for assertion encryption';
288
- }
289
- }
290
- return true;
291
- })
292
- .check(function (argv, aliases) {
293
- if (argv.config) {
294
- return true;
295
- }
296
- var configFilePath = resolveFilePath(argv.configFile);
297
- if (!configFilePath) {
298
- return 'SAML attribute config file path "' + argv.configFile + '" is not a valid path.\n';
299
- }
300
- try {
301
- argv.config = require(configFilePath);
302
- }
303
- catch (error) {
304
- return 'Encountered an exception while loading SAML attribute config file "' + configFilePath + '".\n' + error;
305
- }
306
- return true;
307
- })
308
- .wrap(baseArgv.terminalWidth());
309
- }
310
- var app = express.Router();
311
- function _runServer(argv) {
312
- var blocks = {};
313
- console.log(dedent(chalk(tslib_1.__makeTemplateObject(["\n Listener Port:\n {cyan ", ":", "}\n HTTPS Enabled:\n {cyan ", "}\n\n {bold [{yellow Identity Provider}]}\n\n Issuer URI:\n {cyan ", "}\n Sign Response Message:\n {cyan ", "}\n Encrypt Assertion:\n {cyan ", "}\n Authentication Context Class Reference:\n {cyan ", "}\n Authentication Context Declaration:\n {cyan ", "}\n Default RelayState:\n {cyan ", "}\n\n {bold [{yellow Service Provider}]}\n\n serviceProviderId URI:\n {cyan ", "}\n Audience URI:\n {cyan ", "}\n ACS URL:\n {cyan ", "}\n SLO URL:\n {cyan ", "}\n Trust ACS URL in Request:\n {cyan ", "}\n "], ["\n Listener Port:\n {cyan ", ":", "}\n HTTPS Enabled:\n {cyan ", "}\n\n {bold [{yellow Identity Provider}]}\n\n Issuer URI:\n {cyan ", "}\n Sign Response Message:\n {cyan ", "}\n Encrypt Assertion:\n {cyan ", "}\n Authentication Context Class Reference:\n {cyan ", "}\n Authentication Context Declaration:\n {cyan ", "}\n Default RelayState:\n {cyan ", "}\n\n {bold [{yellow Service Provider}]}\n\n serviceProviderId URI:\n {cyan ", "}\n Audience URI:\n {cyan ", "}\n ACS URL:\n {cyan ", "}\n SLO URL:\n {cyan ", "}\n Trust ACS URL in Request:\n {cyan ", "}\n "]), argv.host, argv.port, argv.https, argv.issuer, argv.signResponse, argv.encryptAssertion, argv.authnContextClassRef || UNDEFINED_VALUE, argv.authnContextDecl || UNDEFINED_VALUE, argv.relayState || UNDEFINED_VALUE, argv.serviceProviderId || UNDEFINED_VALUE, argv.audience || UNDEFINED_VALUE, argv.acsUrl || UNDEFINED_VALUE, argv.sloUrl || UNDEFINED_VALUE, !argv.disableRequestAcsUrl)));
314
- /**
315
- * IdP Configuration
316
- */
317
- var idpOptions = {
318
- issuer: argv.issuer,
319
- serviceProviderId: argv.serviceProviderId || argv.audience,
320
- cert: argv.cert,
321
- key: argv.key,
322
- audience: argv.audience,
323
- recipient: argv.acsUrl,
324
- destination: argv.acsUrl,
325
- acsUrl: argv.acsUrl,
326
- sloUrl: argv.sloUrl,
327
- RelayState: argv.relayState,
328
- allowRequestAcsUrl: !argv.disableRequestAcsUrl,
329
- digestAlgorithm: 'sha256',
330
- signatureAlgorithm: 'rsa-sha256',
331
- signResponse: argv.signResponse,
332
- encryptAssertion: argv.encryptAssertion,
333
- encryptionCert: argv.encryptionCert,
334
- encryptionPublicKey: argv.encryptionPublicKey,
335
- encryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#aes256-cbc',
336
- keyEncryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p',
337
- lifetimeInSeconds: 3600,
338
- authnContextClassRef: argv.authnContextClassRef,
339
- authnContextDecl: argv.authnContextDecl,
340
- includeAttributeNameFormat: true,
341
- profileMapper: SimpleProfileMapper.fromMetadata(argv.config.metadata),
342
- postEndpointPath: IDP_PATHS.SSO,
343
- redirectEndpointPath: IDP_PATHS.SSO,
344
- logoutEndpointPaths: argv.sloUrl ?
345
- {
346
- redirect: IDP_PATHS.SLO,
347
- post: IDP_PATHS.SLO
348
- } : {},
349
- getUserFromRequest: function (req) { return req.user; },
350
- getPostURL: function (audience, authnRequestDom, req, callback) {
351
- return callback(null, (req.authnRequest && req.authnRequest.acsUrl) ?
352
- req.authnRequest.acsUrl :
353
- argv.acsUrl);
354
- },
355
- transformAssertion: function (assertionDom) {
356
- if (argv.authnContextDecl) {
357
- var declDoc;
358
- try {
359
- declDoc = new Parser().parseFromString(argv.authnContextDecl);
360
- }
361
- catch (err) {
362
- console.log('Unable to parse Authentication Context Declaration XML', err);
363
- }
364
- if (declDoc) {
365
- var authnContextDeclEl = assertionDom.createElementNS('urn:oasis:names:tc:SAML:2.0:assertion', 'saml:AuthnContextDecl');
366
- authnContextDeclEl.appendChild(declDoc.documentElement);
367
- var authnContextEl = assertionDom.getElementsByTagName('saml:AuthnContext')[0];
368
- authnContextEl.appendChild(authnContextDeclEl);
369
- }
370
- }
371
- },
372
- responseHandler: function (response, opts, req, res, next) {
373
- console.log(dedent(chalk(tslib_1.__makeTemplateObject(["\n Sending SAML Response to {cyan ", "} =>\n {bold RelayState} =>\n {cyan ", "}\n {bold SAMLResponse} =>"], ["\n Sending SAML Response to {cyan ", "} =>\n {bold RelayState} =>\n {cyan ", "}\n {bold SAMLResponse} =>"]), opts.postUrl, opts.RelayState || UNDEFINED_VALUE)));
374
- console.log(prettyPrintXml(response.toString(), 4));
375
- res.render('samlresponse', {
376
- AcsUrl: opts.postUrl,
377
- SAMLResponse: response.toString('base64'),
378
- RelayState: opts.RelayState
379
- });
380
- }
381
- };
382
- /**
383
- * App Environment
384
- */
385
- // app.set('host', process.env.HOST || argv.host);
386
- // app.set('port', process.env.PORT || argv.port);
387
- // app.set('views', path.join(__dirname, 'views'));
388
- /**
389
- * View Engine
390
- */
391
- // app.set('view engine', 'hbs');
392
- // app.set('view options', { layout: 'layout' })
393
- // app.engine('handlebars', hbs.__express);
394
- // Register Helpers
395
- hbs.registerHelper('extend', function (name, context) {
396
- var block = blocks[name];
397
- if (!block) {
398
- block = blocks[name] = [];
399
- }
400
- block.push(context.fn(this));
401
- });
402
- hbs.registerHelper('block', function (name) {
403
- var val = (blocks[name] || []).join('\n');
404
- // clear the block
405
- blocks[name] = [];
406
- return val;
407
- });
408
- hbs.registerHelper('select', function (selected, options) {
409
- return options.fn(this).replace(new RegExp(' value=\"' + selected + '\"'), '$& selected="selected"');
410
- });
411
- hbs.registerHelper('getProperty', function (attribute, context) {
412
- return context[attribute];
413
- });
414
- hbs.registerHelper('serialize', function (context) {
415
- return new Buffer(JSON.stringify(context)).toString('base64');
416
- });
417
- /**
418
- * Middleware
419
- */
420
- app.use(logger(':date> :method :url - {:referrer} => :status (:response-time ms)', {
421
- skip: function (req, res) {
422
- return req.path.startsWith('/bower_components') || req.path.startsWith('/css');
423
- }
424
- }));
425
- app.use(bodyParser.urlencoded({ extended: true }));
426
- app.use(express.static(path.join(__dirname, 'public')));
427
- app.use(session({
428
- secret: 'The universe works on a math equation that never even ever really ends in the end',
429
- resave: false,
430
- saveUninitialized: true,
431
- name: 'idp_sid',
432
- cookie: { maxAge: 60 * 60 * 1000 }
433
- }));
434
- /**
435
- * View Handlers
436
- */
437
- var showUser = function (req, res, next) {
438
- res.render('user', {
439
- user: req.user,
440
- participant: req.participant,
441
- metadata: req.metadata,
442
- authnRequest: req.authnRequest,
443
- idp: req.idp.options,
444
- paths: IDP_PATHS
445
- });
446
- };
447
- /**
448
- * Shared Handlers
449
- */
450
- var parseSamlRequest = function (req, res, next) {
451
- samlp.parseRequest(req, function (err, data) {
452
- if (err) {
453
- return res.render('error', {
454
- message: 'SAML AuthnRequest Parse Error: ' + err.message,
455
- error: err
456
- });
457
- }
458
- ;
459
- if (data) {
460
- req.authnRequest = {
461
- relayState: req.query.RelayState || req.body.RelayState,
462
- id: data.id,
463
- issuer: data.issuer,
464
- destination: data.destination,
465
- acsUrl: data.assertionConsumerServiceURL,
466
- forceAuthn: data.forceAuthn === 'true'
467
- };
468
- console.log('Received AuthnRequest => \n', req.authnRequest);
469
- }
470
- if (req.user != undefined) {
471
- return showUser(req, res, next);
472
- }
473
- else {
474
- console.log('Redirect to login => \n');
475
- res.redirect("/accounts/a/#/login?redirect_uri=" + encodeURIComponent(req.originalUrl));
476
- return res.end();
477
- }
478
- });
479
- };
480
- var getSessionIndex = function (req) {
481
- if (req && req.session) {
482
- return Math.abs(getHashCode(req.session.id)).toString();
483
- }
484
- };
485
- var getParticipant = function (req) {
486
- return {
487
- serviceProviderId: req.idp.options.serviceProviderId,
488
- sessionIndex: getSessionIndex(req),
489
- nameId: req.user.username,
490
- nameIdFormat: req.user.nameIdFormat,
491
- serviceProviderLogoutURL: req.idp.options.sloUrl
492
- };
493
- };
494
- var parseLogoutRequest = function (req, res, next) {
495
- if (!req.idp.options.sloUrl) {
496
- return res.render('error', {
497
- message: 'SAML Single Logout Service URL not defined for Service Provider'
498
- });
499
- }
500
- ;
501
- console.log('Processing SAML SLO request for participant => \n', req.participant);
502
- return samlp.logout({
503
- issuer: req.idp.options.issuer,
504
- cert: req.idp.options.cert,
505
- key: req.idp.options.key,
506
- digestAlgorithm: req.idp.options.digestAlgorithm,
507
- signatureAlgorithm: req.idp.options.signatureAlgorithm,
508
- sessionParticipants: new SessionParticipants([
509
- req.participant
510
- ]),
511
- clearIdPSession: function (callback) {
512
- console.log('Destroying session ' + req.session.id + ' for participant', req.participant);
513
- req.session.destroy();
514
- callback();
515
- }
516
- })(req, res, next);
517
- };
518
- /**
519
- * Routes
520
- */
521
- app.use(function (req, res, next) {
522
- if (argv.rollSession) {
523
- req.session.regenerate(function (err) {
524
- return next();
525
- });
526
- }
527
- else {
528
- next();
529
- }
530
- });
531
- app.use(function (req, res, next) {
532
- //req.user = argv.config.user;
533
- req.metadata = argv.config.metadata;
534
- req.idp = { options: idpOptions };
535
- if (req.user)
536
- req.participant = getParticipant(req);
537
- next();
538
- });
539
- app.get(['/', '/idp', IDP_PATHS.SSO], parseSamlRequest);
540
- app.post(['/', '/idp', IDP_PATHS.SSO], parseSamlRequest);
541
- app.get(IDP_PATHS.SLO, parseLogoutRequest);
542
- app.post(IDP_PATHS.SLO, parseLogoutRequest);
543
- app.post(IDP_PATHS.SIGN_IN, function (req, res) {
544
- var authOptions = extend({}, req.idp.options);
545
- Object.keys(req.body).forEach(function (key) {
546
- var buffer;
547
- if (key === '_authnRequest') {
548
- buffer = new Buffer(req.body[key], 'base64');
549
- req.authnRequest = JSON.parse(buffer.toString('utf8'));
550
- // Apply AuthnRequest Params
551
- authOptions.inResponseTo = req.authnRequest.id;
552
- if (req.idp.options.allowRequestAcsUrl && req.authnRequest.acsUrl) {
553
- authOptions.acsUrl = req.authnRequest.acsUrl;
554
- authOptions.recipient = req.authnRequest.acsUrl;
555
- authOptions.destination = req.authnRequest.acsUrl;
556
- authOptions.forceAuthn = req.authnRequest.forceAuthn;
557
- }
558
- if (req.authnRequest.relayState) {
559
- authOptions.RelayState = req.authnRequest.relayState;
560
- }
561
- }
562
- else {
563
- req.user[key] = req.body[key];
564
- }
565
- });
566
- if (!authOptions.encryptAssertion) {
567
- delete authOptions.encryptionCert;
568
- delete authOptions.encryptionPublicKey;
569
- }
570
- // Set Session Index
571
- authOptions.sessionIndex = getSessionIndex(req);
572
- // Keep calm and Single Sign On
573
- console.log(dedent(chalk(tslib_1.__makeTemplateObject(["\n Generating SAML Response using =>\n {bold User} => ", "\n {bold SAMLP Options} => ", "\n "], ["\n Generating SAML Response using =>\n {bold User} => ", "\n {bold SAMLP Options} => ", "\n "]), Object.entries(req.user).map(function (_a) {
574
- var key = _a[0], value = _a[1];
575
- return chalk(tslib_1.__makeTemplateObject(["\n ", ": {cyan ", "}"], ["\n ", ": {cyan ", "}"]), key, value);
576
- }).join(''), Object.entries(authOptions).map(function (_a) {
577
- var key = _a[0], value = _a[1];
578
- return chalk(tslib_1.__makeTemplateObject(["\n ", ": {cyan ", "}"], ["\n ", ": {cyan ", "}"]), key, formatOptionValue(key, value));
579
- }).join(''))));
580
- samlp.auth(authOptions)(req, res);
581
- });
582
- app.get(IDP_PATHS.METADATA, function (req, res, next) {
583
- samlp.metadata(req.idp.options)(req, res);
584
- });
585
- app.post(IDP_PATHS.METADATA, function (req, res, next) {
586
- if (req.body && req.body.attributeName && req.body.name) {
587
- var attributeExists = false;
588
- var attribute_1 = {
589
- id: req.body.attributeName,
590
- optional: true,
591
- name: req.body.name,
592
- description: req.body.description || '',
593
- multiValue: req.body.valueType === 'multi'
594
- };
595
- req.metadata.forEach(function (entry) {
596
- if (entry.id === req.body.attributeName) {
597
- entry = attribute_1;
598
- attributeExists = true;
599
- }
600
- });
601
- if (!attributeExists) {
602
- req.metadata.push(attribute_1);
603
- }
604
- console.log("Updated SAML Attribute Metadata => \n", req.metadata);
605
- res.status(200).end();
606
- }
607
- });
608
- app.get(IDP_PATHS.SIGN_OUT, function (req, res, next) {
609
- if (req.idp.options.sloUrl) {
610
- console.log('Initiating SAML SLO request for user: ' + req.user.username +
611
- ' with sessionIndex: ' + getSessionIndex(req));
612
- res.redirect(IDP_PATHS.SLO);
613
- }
614
- else {
615
- console.log('SAML SLO is not enabled for SP, destroying IDP session');
616
- req.session.destroy(function (err) {
617
- if (err) {
618
- throw err;
619
- }
620
- res.redirect('back');
621
- });
622
- }
623
- });
624
- app.get([IDP_PATHS.SETTINGS], function (req, res, next) {
625
- res.render('settings', {
626
- idp: req.idp.options
627
- });
628
- });
629
- app.post([IDP_PATHS.SETTINGS], function (req, res, next) {
630
- Object.keys(req.body).forEach(function (key) {
631
- switch (req.body[key].toLowerCase()) {
632
- case "true":
633
- case "yes":
634
- case "1":
635
- req.idp.options[key] = true;
636
- break;
637
- case "false":
638
- case "no":
639
- case "0":
640
- req.idp.options[key] = false;
641
- break;
642
- default:
643
- req.idp.options[key] = req.body[key];
644
- break;
645
- }
646
- if (req.body[key].match(/^\d+$/)) {
647
- req.idp.options[key] = parseInt(req.body[key], '10');
648
- }
649
- });
650
- console.log('Updated IdP Configuration => \n', req.idp.options);
651
- res.redirect('/');
652
- });
653
- // catch 404 and forward to error handler
654
- app.use(function (req, res, next) {
655
- var err = new Error('Route Not Found');
656
- err.status = 404;
657
- next(err);
658
- });
659
- // development error handler
660
- app.use(function (err, req, res, next) {
661
- if (err) {
662
- res.status(err.status || 500);
663
- res.render('error', {
664
- message: err.message,
665
- error: err
666
- });
667
- }
668
- });
669
- }
670
- function runServer(options) {
671
- var args = processArgs([], options);
672
- return _runServer(args.argv);
673
- }
674
- function main() {
675
- var args = processArgs(process.argv.slice(2));
676
- _runServer(args.argv);
677
- }
678
- module.exports = {
679
- samlIdp: {
680
- run: runServer,
681
- expressMiddleware: app
682
- }
683
- };
684
- //# sourceMappingURL=express-middleware.js.map