Fixed auth strategies when using with a second domain with a DNS (#4404)
Ylian Saint-Hilaire committed
Aug 17, 2022 at 14:14 UTC
4092615c631efe3aab5dfb1f0e7936de707e5eaf
1 file changed
+299
-215
webserver.js
+299
-215
@@ -6021,6 +6021,23 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6021
if ((parent.config.domains[i].dns == null) && (parent.config.domains[i].share != null)) { obj.app.use(parent.config.domains[i].url, obj.express.static(parent.config.domains[i].share)); }
6022
}
6023
6024
+ // Setup all domain auth strategy passport.js
6025
+ for (var i in parent.config.domains) {
6026
+ if (typeof parent.config.domains[i].authstrategies == 'object') {
6027
+ parent.config.domains[i].authstrategies.authStrategyFlags = 0;
6028
+ const authStrategyFlags = setupDomainAuthStrategy(parent.config.domains[i]);
6029
+ if (authStrategyFlags > 0) {
6030
+ if (parent.config.domains[i].dns != null) {
6031
+ if (typeof parent.config.domains[''].authstrategies != 'object') { parent.config.domains[''].authstrategies = { authStrategyFlags: 0 }; }
6032
+ parent.config.domains[''].authstrategies.authStrategyFlags |= authStrategyFlags;
6033
+ } else {
6034
+ if (typeof parent.config.domains[i].authstrategies != 'object') { parent.config.domains[i].authstrategies = { authStrategyFlags: 0 }; }
6035
+ parent.config.domains[i].authstrategies.authStrategyFlags |= authStrategyFlags;
6036
+ }
6037
+ }
6038
+ }
6039
+ }
6040
+
6041
// Setup all HTTP handlers
6042
if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req, obj.args.tlsoffload == null); }); }
6043
for (var i in parent.config.domains) {
@@ -6201,26 +6218,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6218
6219
// Setup auth strategies using passport if needed
6220
if (typeof domain.authstrategies == 'object') {
6204
- const passport = domain.passport = require('passport');
6205
- passport.serializeUser(function (user, done) { done(null, user.sid); });
6206
- passport.deserializeUser(function (sid, done) { done(null, { sid: sid }); });
6207
- obj.app.use(passport.initialize());
6208
- //obj.app.use(passport.session());
6209
-
6221
// Twitter
6211
- if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) {
6212
- const TwitterStrategy = require('passport-twitter');
6213
- var options = { consumerKey: domain.authstrategies.twitter.clientid, consumerSecret: domain.authstrategies.twitter.clientsecret };
6214
- if (typeof domain.authstrategies.twitter.callbackurl == 'string') { options.callbackURL = domain.authstrategies.twitter.callbackurl; } else { options.callbackURL = url + 'auth-twitter-callback'; }
6215
- parent.debug('web', 'Adding Twitter SSO with options: ' + JSON.stringify(options));
6216
- passport.use('twitter-' + domain.id, new TwitterStrategy(options,
6217
- function (token, tokenSecret, profile, cb) {
6218
- parent.debug('web', 'Twitter profile: ' + JSON.stringify(profile));
6219
- var user = { sid: '~twitter:' + profile.id, name: profile.displayName, strategy: 'twitter' };
6220
- if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; }
6221
- return cb(null, user);
6222
- }
6223
- ));
6222
+ if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.twitter) != 0) {
6223
obj.app.get(url + 'auth-twitter', function (req, res, next) {
6224
var domain = getDomain(req);
6225
if (domain.passport == null) { next(); return; }
@@ -6242,19 +6241,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6241
}
6242
6243
// Google
6245
- if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) {
6246
- const GoogleStrategy = require('passport-google-oauth20');
6247
- var options = { clientID: domain.authstrategies.google.clientid, clientSecret: domain.authstrategies.google.clientsecret };
6248
- if (typeof domain.authstrategies.google.callbackurl == 'string') { options.callbackURL = domain.authstrategies.google.callbackurl; } else { options.callbackURL = url + 'auth-google-callback'; }
6249
- parent.debug('web', 'Adding Google SSO with options: ' + JSON.stringify(options));
6250
- passport.use('google-' + domain.id, new GoogleStrategy(options,
6251
- function (token, tokenSecret, profile, cb) {
6252
- parent.debug('web', 'Google profile: ' + JSON.stringify(profile));
6253
- var user = { sid: '~google:' + profile.id, name: profile.displayName, strategy: 'google' };
6254
- if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string') && (profile.emails[0].verified == true)) { user.email = profile.emails[0].value; }
6255
- return cb(null, user);
6256
- }
6257
- ));
6244
+ if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.google) != 0) {
6245
obj.app.get(url + 'auth-google', function (req, res, next) {
6246
var domain = getDomain(req);
6247
if (domain.passport == null) { next(); return; }
@@ -6267,20 +6254,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6254
}, handleStrategyLogin);
6255
}
6256
6270
- // Github
6271
- if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) {
6272
- const GitHubStrategy = require('passport-github2');
6273
- var options = { clientID: domain.authstrategies.github.clientid, clientSecret: domain.authstrategies.github.clientsecret };
6274
- if (typeof domain.authstrategies.github.callbackurl == 'string') { options.callbackURL = domain.authstrategies.github.callbackurl; } else { options.callbackURL = url + 'auth-github-callback'; }
6275
- parent.debug('web', 'Adding Github SSO with options: ' + JSON.stringify(options));
6276
- passport.use('github-' + domain.id, new GitHubStrategy(options,
6277
- function (token, tokenSecret, profile, cb) {
6278
- parent.debug('web', 'Github profile: ' + JSON.stringify(profile));
6279
- var user = { sid: '~github:' + profile.id, name: profile.displayName, strategy: 'github' };
6280
- if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; }
6281
- return cb(null, user);
6282
- }
6283
- ));
6257
+ // GitHub
6258
+ if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.github) != 0) {
6259
obj.app.get(url + 'auth-github', function (req, res, next) {
6260
var domain = getDomain(req);
6261
if (domain.passport == null) { next(); return; }
@@ -6294,19 +6269,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6269
}
6270
6271
// Reddit
6297
- if ((typeof domain.authstrategies.reddit == 'object') && (typeof domain.authstrategies.reddit.clientid == 'string') && (typeof domain.authstrategies.reddit.clientsecret == 'string')) {
6298
- const RedditStrategy = require('passport-reddit');
6299
- var options = { clientID: domain.authstrategies.reddit.clientid, clientSecret: domain.authstrategies.reddit.clientsecret };
6300
- if (typeof domain.authstrategies.reddit.callbackurl == 'string') { options.callbackURL = domain.authstrategies.reddit.callbackurl; } else { options.callbackURL = url + 'auth-reddit-callback'; }
6301
- parent.debug('web', 'Adding Reddit SSO with options: ' + JSON.stringify(options));
6302
- passport.use('reddit-' + domain.id, new RedditStrategy.Strategy(options,
6303
- function (token, tokenSecret, profile, cb) {
6304
- parent.debug('web', 'Reddit profile: ' + JSON.stringify(profile));
6305
- var user = { sid: '~reddit:' + profile.id, name: profile.name, strategy: 'reddit' };
6306
- if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; }
6307
- return cb(null, user);
6308
- }
6309
- ));
6272
+ if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.reddit) != 0) {
6273
obj.app.get(url + 'auth-reddit', function (req, res, next) {
6274
var domain = getDomain(req);
6275
if (domain.passport == null) { next(); return; }
@@ -6332,24 +6295,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6295
}
6296
6297
// Azure
6335
- if ((typeof domain.authstrategies.azure == 'object') && (typeof domain.authstrategies.azure.clientid == 'string') && (typeof domain.authstrategies.azure.clientsecret == 'string')) {
6336
- const AzureOAuth2Strategy = require('passport-azure-oauth2');
6337
- var options = { clientID: domain.authstrategies.azure.clientid, clientSecret: domain.authstrategies.azure.clientsecret, tenant: domain.authstrategies.azure.tenantid };
6338
- if (typeof domain.authstrategies.azure.callbackurl == 'string') { options.callbackURL = domain.authstrategies.azure.callbackurl; } else { options.callbackURL = url + 'auth-azure-callback'; }
6339
- parent.debug('web', 'Adding Azure SSO with options: ' + JSON.stringify(options));
6340
- passport.use('azure-' + domain.id, new AzureOAuth2Strategy(options,
6341
- function (accessToken, refreshtoken, params, profile, done) {
6342
- var userex = null;
6343
- try { userex = require('jwt-simple').decode(params.id_token, "", true); } catch (ex) { }
6344
- parent.debug('web', 'Azure profile: ' + JSON.stringify(userex));
6345
- var user = null;
6346
- if (userex != null) {
6347
- var user = { sid: '~azure:' + userex.unique_name, name: userex.name, strategy: 'azure' };
6348
- if (typeof userex.email == 'string') { user.email = userex.email; }
6349
- }
6350
- return done(null, user);
6351
- }
6352
- ));
6298
+ if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.azure) != 0) {
6299
obj.app.get(url + 'auth-azure', function (req, res, next) {
6300
var domain = getDomain(req);
6301
if (domain.passport == null) { next(); return; }
@@ -6374,155 +6320,52 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6320
}, handleStrategyLogin);
6321
}
6322
6377
- // Generic OpenID Connect
6378
- if ((typeof domain.authstrategies.oidc == 'object') && (typeof domain.authstrategies.oidc.clientid == 'string') && (typeof domain.authstrategies.oidc.clientsecret == 'string') && (typeof domain.authstrategies.oidc.issuer == 'string')) {
6379
- var options = {
6380
- authorizationURL: domain.authstrategies.oidc.authorizationurl,
6381
- callbackURL: domain.authstrategies.oidc.callbackurl,
6382
- clientID: domain.authstrategies.oidc.clientid,
6383
- clientSecret: domain.authstrategies.oidc.clientsecret,
6384
- issuer: domain.authstrategies.oidc.issuer,
6385
- tokenURL: domain.authstrategies.oidc.tokenurl,
6386
- userInfoURL: domain.authstrategies.oidc.userinfourl,
6387
- scope: ['openid profile email'],
6388
- responseMode: 'form_post',
6389
- state: true
6390
- };
6391
- const OIDCStrategy = require('@mstrhakr/passport-generic-oidc');
6392
- if (typeof domain.authstrategies.oidc.callbackurl == 'string') { options.callbackURL = domain.authstrategies.oidc.callbackurl; } else { options.callbackURL = url + 'oidc-callback'; }
6393
- parent.debug('web', 'Adding Generic OIDC SSO with options: ' + JSON.stringify(options));
6394
- passport.use('openidconnect', new OIDCStrategy.Strategy(options,
6395
- function verify(iss, sub, profile, cb) {
6396
- var user = { sid: '~oidc:' + profile.id, name: profile.displayName, email: profile.email, strategy: 'oidc' };
6397
- parent.debug('AUTH', 'OIDC: Configured user: ' + JSON.stringify(user));
6398
- return cb(null, user);
6399
- }
6400
- ));
6323
+ // Generic OpenID
6324
+ if (domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.openid != 0) {
6325
obj.app.get(url + 'auth-oidc', domain.passport.authenticate('openidconnect'));
6326
obj.app.get(url + 'oidc-callback', domain.passport.authenticate('openidconnect', { failureRedirect: '/login?failed-auth-attempt', failureFlash: true }), handleStrategyLogin);
6327
}
6328
6405
-
6329
// Generic SAML
6407
- if (typeof domain.authstrategies.saml == 'object') {
6408
- if ((typeof domain.authstrategies.saml.cert != 'string') || (typeof domain.authstrategies.saml.idpurl != 'string')) {
6409
- console.log('ERROR: Missing SAML configuration.');
6410
- } else {
6411
- const certPath = obj.common.joinPath(obj.parent.datapath, domain.authstrategies.saml.cert);
6412
- var cert = obj.fs.readFileSync(certPath);
6413
- if (cert == null) {
6414
- console.log('ERROR: Unable to read SAML IdP certificate: ' + domain.authstrategies.saml.cert);
6415
- } else {
6416
- var options = { entryPoint: domain.authstrategies.saml.idpurl, issuer: 'meshcentral' };
6417
- if (typeof domain.authstrategies.saml.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.saml.callbackurl; } else { options.callbackUrl = url + 'auth-saml-callback'; }
6418
- if (domain.authstrategies.saml.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.saml.disablerequestedauthncontext; }
6419
- if (typeof domain.authstrategies.saml.entityid == 'string') { options.issuer = domain.authstrategies.saml.entityid; }
6420
- parent.debug('web', 'Adding SAML SSO with options: ' + JSON.stringify(options));
6421
- options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('');
6422
- const SamlStrategy = require('passport-saml').Strategy;
6423
- passport.use('saml-' + domain.id, new SamlStrategy(options,
6424
- function (profile, done) {
6425
- parent.debug('web', 'SAML profile: ' + JSON.stringify(profile));
6426
- if (typeof profile.nameID != 'string') { return done(); }
6427
- var user = { sid: '~saml:' + profile.nameID, name: profile.nameID, strategy: 'saml' };
6428
- if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; }
6429
- if (typeof profile.email == 'string') { user.email = profile.email; }
6430
- return done(null, user);
6431
- }
6432
- ));
6433
- obj.app.get(url + 'auth-saml', function (req, res, next) {
6434
- var domain = getDomain(req);
6435
- if (domain.passport == null) { next(); return; }
6436
- domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6437
- });
6438
- obj.app.post(url + 'auth-saml-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) {
6439
- var domain = getDomain(req);
6440
- if (domain.passport == null) { next(); return; }
6441
- domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6442
- }, handleStrategyLogin);
6443
- }
6444
- }
6330
+ if (domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.saml != 0) {
6331
+ obj.app.get(url + 'auth-saml', function (req, res, next) {
6332
+ var domain = getDomain(req);
6333
+ if (domain.passport == null) { next(); return; }
6334
+ domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6335
+ });
6336
+ obj.app.post(url + 'auth-saml-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) {
6337
+ var domain = getDomain(req);
6338
+ if (domain.passport == null) { next(); return; }
6339
+ domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6340
+ }, handleStrategyLogin);
6341
}
6342
6343
// Intel SAML
6448
- if (typeof domain.authstrategies.intel == 'object') {
6449
- if ((typeof domain.authstrategies.intel.cert != 'string') || (typeof domain.authstrategies.intel.idpurl != 'string')) {
6450
- console.log('ERROR: Missing Intel SAML configuration.');
6451
- } else {
6452
- var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.intel.cert));
6453
- if (cert == null) {
6454
- console.log('ERROR: Unable to read Intel SAML IdP certificate: ' + domain.authstrategies.intel.cert);
6455
- } else {
6456
- var options = { entryPoint: domain.authstrategies.intel.idpurl, issuer: 'meshcentral' };
6457
- if (typeof domain.authstrategies.intel.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.intel.callbackurl; } else { options.callbackUrl = url + 'auth-intel-callback'; }
6458
- if (domain.authstrategies.intel.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.intel.disablerequestedauthncontext; }
6459
- if (typeof domain.authstrategies.intel.entityid == 'string') { options.issuer = domain.authstrategies.intel.entityid; }
6460
- parent.debug('web', 'Adding Intel SSO with options: ' + JSON.stringify(options));
6461
- options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('');
6462
- const SamlStrategy = require('passport-saml').Strategy;
6463
- passport.use('isaml-' + domain.id, new SamlStrategy(options,
6464
- function (profile, done) {
6465
- parent.debug('web', 'Intel profile: ' + JSON.stringify(profile));
6466
- if (typeof profile.nameID != 'string') { return done(); }
6467
- var user = { sid: '~intel:' + profile.nameID, name: profile.nameID, strategy: 'intel' };
6468
- if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; }
6469
- else if ((typeof profile.FirstName == 'string') && (typeof profile.LastName == 'string')) { user.name = profile.FirstName + ' ' + profile.LastName; }
6470
- if (typeof profile.email == 'string') { user.email = profile.email; }
6471
- else if (typeof profile.EmailAddress == 'string') { user.email = profile.EmailAddress; }
6472
- return done(null, user);
6473
- }
6474
- ));
6475
- obj.app.get(url + 'auth-intel', function (req, res, next) {
6476
- var domain = getDomain(req);
6477
- if (domain.passport == null) { next(); return; }
6478
- domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6479
- });
6480
- obj.app.post(url + 'auth-intel-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) {
6481
- var domain = getDomain(req);
6482
- if (domain.passport == null) { next(); return; }
6483
- domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6484
- }, handleStrategyLogin);
6485
- }
6486
- }
6344
+ if (domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.intelSaml != 0) {
6345
+ obj.app.get(url + 'auth-intel', function (req, res, next) {
6346
+ var domain = getDomain(req);
6347
+ if (domain.passport == null) { next(); return; }
6348
+ domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6349
+ });
6350
+ obj.app.post(url + 'auth-intel-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) {
6351
+ var domain = getDomain(req);
6352
+ if (domain.passport == null) { next(); return; }
6353
+ domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6354
+ }, handleStrategyLogin);
6355
}
6356
6357
// JumpCloud SAML
6490
- if (typeof domain.authstrategies.jumpcloud == 'object') {
6491
- if ((typeof domain.authstrategies.jumpcloud.cert != 'string') || (typeof domain.authstrategies.jumpcloud.idpurl != 'string')) {
6492
- console.log('ERROR: Missing JumpCloud SAML configuration.');
6493
- } else {
6494
- var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.jumpcloud.cert));
6495
- if (cert == null) {
6496
- console.log('ERROR: Unable to read JumpCloud IdP certificate: ' + domain.authstrategies.jumpcloud.cert);
6497
- } else {
6498
- var options = { entryPoint: domain.authstrategies.jumpcloud.idpurl, issuer: 'meshcentral' };
6499
- if (typeof domain.authstrategies.jumpcloud.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.jumpcloud.callbackurl; } else { options.callbackUrl = url + 'auth-jumpcloud-callback'; }
6500
- if (typeof domain.authstrategies.jumpcloud.entityid == 'string') { options.issuer = domain.authstrategies.jumpcloud.entityid; }
6501
- parent.debug('web', 'Adding JumpCloud SSO with options: ' + JSON.stringify(options));
6502
- options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('');
6503
- const SamlStrategy = require('passport-saml').Strategy;
6504
- passport.use('jumpcloud-' + domain.id, new SamlStrategy(options,
6505
- function (profile, done) {
6506
- parent.debug('web', 'JumpCloud profile: ' + JSON.stringify(profile));
6507
- if (typeof profile.nameID != 'string') { return done(); }
6508
- var user = { sid: '~jumpcloud:' + profile.nameID, name: profile.nameID, strategy: 'jumpcloud' };
6509
- if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; }
6510
- if (typeof profile.email == 'string') { user.email = profile.email; }
6511
- return done(null, user);
6512
- }
6513
- ));
6514
- obj.app.get(url + 'auth-jumpcloud', function (req, res, next) {
6515
- var domain = getDomain(req);
6516
- if (domain.passport == null) { next(); return; }
6517
- domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6518
- });
6519
- obj.app.post(url + 'auth-jumpcloud-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) {
6520
- var domain = getDomain(req);
6521
- if (domain.passport == null) { next(); return; }
6522
- domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6523
- }, handleStrategyLogin);
6524
- }
6525
- }
6358
+ if (domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.jumpCloudSaml != 0) {
6359
+ obj.app.get(url + 'auth-jumpcloud', function (req, res, next) {
6360
+ var domain = getDomain(req);
6361
+ if (domain.passport == null) { next(); return; }
6362
+ domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6363
+ });
6364
+ obj.app.post(url + 'auth-jumpcloud-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) {
6365
+ var domain = getDomain(req);
6366
+ if (domain.passport == null) { next(); return; }
6367
+ domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next);
6368
+ }, handleStrategyLogin);
6369
}
6370
}
6371
@@ -6793,6 +6636,247 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
6636
if (doneFunc) doneFunc();
6637
}
6638
6639
+ // Auth strategy flags
6640
+ const domainAuthStrategyConsts = {
6641
+ twitter: 1,
6642
+ google: 2,
6643
+ github: 3,
6644
+ reddit: 8,
6645
+ azure: 16,
6646
+ openid: 32,
6647
+ saml: 64,
6648
+ intelSaml: 128,
6649
+ jumpCloudSaml: 256
6650
+ }
6651
+
6652
+ // Setup auth strategies for a domain
6653
+ function setupDomainAuthStrategy(domain) {
6654
+ // Return the auth strategies that have been setup
6655
+ var authStrategyFlags = 0;
6656
+
6657
+ // Setup auth strategies using passport if needed
6658
+ if (typeof domain.authstrategies != 'object') return authStrategyFlags;
6659
+
6660
+ const url = domain.url;
6661
+ const passport = domain.passport = require('passport');
6662
+ passport.serializeUser(function (user, done) { done(null, user.sid); });
6663
+ passport.deserializeUser(function (sid, done) { done(null, { sid: sid }); });
6664
+ obj.app.use(passport.initialize());
6665
+
6666
+ // Twitter
6667
+ if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) {
6668
+ const TwitterStrategy = require('passport-twitter');
6669
+ var options = { consumerKey: domain.authstrategies.twitter.clientid, consumerSecret: domain.authstrategies.twitter.clientsecret };
6670
+ if (typeof domain.authstrategies.twitter.callbackurl == 'string') { options.callbackURL = domain.authstrategies.twitter.callbackurl; } else { options.callbackURL = url + 'auth-twitter-callback'; }
6671
+ parent.debug('web', 'Adding Twitter SSO with options: ' + JSON.stringify(options));
6672
+ passport.use('twitter-' + domain.id, new TwitterStrategy(options,
6673
+ function (token, tokenSecret, profile, cb) {
6674
+ parent.debug('web', 'Twitter profile: ' + JSON.stringify(profile));
6675
+ var user = { sid: '~twitter:' + profile.id, name: profile.displayName, strategy: 'twitter' };
6676
+ if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; }
6677
+ return cb(null, user);
6678
+ }
6679
+ ));
6680
+ authStrategyFlags |= domainAuthStrategyConsts.twitter;
6681
+ }
6682
+
6683
+ // Google
6684
+ if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) {
6685
+ const GoogleStrategy = require('passport-google-oauth20');
6686
+ var options = { clientID: domain.authstrategies.google.clientid, clientSecret: domain.authstrategies.google.clientsecret };
6687
+ if (typeof domain.authstrategies.google.callbackurl == 'string') { options.callbackURL = domain.authstrategies.google.callbackurl; } else { options.callbackURL = url + 'auth-google-callback'; }
6688
+ parent.debug('web', 'Adding Google SSO with options: ' + JSON.stringify(options));
6689
+ passport.use('google-' + domain.id, new GoogleStrategy(options,
6690
+ function (token, tokenSecret, profile, cb) {
6691
+ parent.debug('web', 'Google profile: ' + JSON.stringify(profile));
6692
+ var user = { sid: '~google:' + profile.id, name: profile.displayName, strategy: 'google' };
6693
+ if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string') && (profile.emails[0].verified == true)) { user.email = profile.emails[0].value; }
6694
+ return cb(null, user);
6695
+ }
6696
+ ));
6697
+ authStrategyFlags |= domainAuthStrategyConsts.google;
6698
+ }
6699
+
6700
+ // Github
6701
+ if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) {
6702
+ const GitHubStrategy = require('passport-github2');
6703
+ var options = { clientID: domain.authstrategies.github.clientid, clientSecret: domain.authstrategies.github.clientsecret };
6704
+ if (typeof domain.authstrategies.github.callbackurl == 'string') { options.callbackURL = domain.authstrategies.github.callbackurl; } else { options.callbackURL = url + 'auth-github-callback'; }
6705
+ parent.debug('web', 'Adding Github SSO with options: ' + JSON.stringify(options));
6706
+ passport.use('github-' + domain.id, new GitHubStrategy(options,
6707
+ function (token, tokenSecret, profile, cb) {
6708
+ parent.debug('web', 'Github profile: ' + JSON.stringify(profile));
6709
+ var user = { sid: '~github:' + profile.id, name: profile.displayName, strategy: 'github' };
6710
+ if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; }
6711
+ return cb(null, user);
6712
+ }
6713
+ ));
6714
+ authStrategyFlags |= domainAuthStrategyConsts.github;
6715
+ }
6716
+
6717
+ // Reddit
6718
+ if ((typeof domain.authstrategies.reddit == 'object') && (typeof domain.authstrategies.reddit.clientid == 'string') && (typeof domain.authstrategies.reddit.clientsecret == 'string')) {
6719
+ const RedditStrategy = require('passport-reddit');
6720
+ var options = { clientID: domain.authstrategies.reddit.clientid, clientSecret: domain.authstrategies.reddit.clientsecret };
6721
+ if (typeof domain.authstrategies.reddit.callbackurl == 'string') { options.callbackURL = domain.authstrategies.reddit.callbackurl; } else { options.callbackURL = url + 'auth-reddit-callback'; }
6722
+ parent.debug('web', 'Adding Reddit SSO with options: ' + JSON.stringify(options));
6723
+ passport.use('reddit-' + domain.id, new RedditStrategy.Strategy(options,
6724
+ function (token, tokenSecret, profile, cb) {
6725
+ parent.debug('web', 'Reddit profile: ' + JSON.stringify(profile));
6726
+ var user = { sid: '~reddit:' + profile.id, name: profile.name, strategy: 'reddit' };
6727
+ if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; }
6728
+ return cb(null, user);
6729
+ }
6730
+ ));
6731
+ authStrategyFlags |= domainAuthStrategyConsts.reddit;
6732
+ }
6733
+
6734
+ // Azure
6735
+ if ((typeof domain.authstrategies.azure == 'object') && (typeof domain.authstrategies.azure.clientid == 'string') && (typeof domain.authstrategies.azure.clientsecret == 'string')) {
6736
+ const AzureOAuth2Strategy = require('passport-azure-oauth2');
6737
+ var options = { clientID: domain.authstrategies.azure.clientid, clientSecret: domain.authstrategies.azure.clientsecret, tenant: domain.authstrategies.azure.tenantid };
6738
+ if (typeof domain.authstrategies.azure.callbackurl == 'string') { options.callbackURL = domain.authstrategies.azure.callbackurl; } else { options.callbackURL = url + 'auth-azure-callback'; }
6739
+ parent.debug('web', 'Adding Azure SSO with options: ' + JSON.stringify(options));
6740
+ passport.use('azure-' + domain.id, new AzureOAuth2Strategy(options,
6741
+ function (accessToken, refreshtoken, params, profile, done) {
6742
+ var userex = null;
6743
+ try { userex = require('jwt-simple').decode(params.id_token, '', true); } catch (ex) { }
6744
+ parent.debug('web', 'Azure profile: ' + JSON.stringify(userex));
6745
+ var user = null;
6746
+ if (userex != null) {
6747
+ var user = { sid: '~azure:' + userex.unique_name, name: userex.name, strategy: 'azure' };
6748
+ if (typeof userex.email == 'string') { user.email = userex.email; }
6749
+ }
6750
+ return done(null, user);
6751
+ }
6752
+ ));
6753
+ authStrategyFlags |= domainAuthStrategyConsts.azure;
6754
+ }
6755
+
6756
+ // Generic OpenID Connect
6757
+ if ((typeof domain.authstrategies.oidc == 'object') && (typeof domain.authstrategies.oidc.clientid == 'string') && (typeof domain.authstrategies.oidc.clientsecret == 'string') && (typeof domain.authstrategies.oidc.issuer == 'string')) {
6758
+ var options = {
6759
+ authorizationURL: domain.authstrategies.oidc.authorizationurl,
6760
+ callbackURL: domain.authstrategies.oidc.callbackurl,
6761
+ clientID: domain.authstrategies.oidc.clientid,
6762
+ clientSecret: domain.authstrategies.oidc.clientsecret,
6763
+ issuer: domain.authstrategies.oidc.issuer,
6764
+ tokenURL: domain.authstrategies.oidc.tokenurl,
6765
+ userInfoURL: domain.authstrategies.oidc.userinfourl,
6766
+ scope: ['openid profile email'],
6767
+ responseMode: 'form_post',
6768
+ state: true
6769
+ };
6770
+ const OIDCStrategy = require('@mstrhakr/passport-generic-oidc');
6771
+ if (typeof domain.authstrategies.oidc.callbackurl == 'string') { options.callbackURL = domain.authstrategies.oidc.callbackurl; } else { options.callbackURL = url + 'oidc-callback'; }
6772
+ parent.debug('web', 'Adding Generic OIDC SSO with options: ' + JSON.stringify(options));
6773
+ passport.use('openidconnect', new OIDCStrategy.Strategy(options,
6774
+ function verify(iss, sub, profile, cb) {
6775
+ var user = { sid: '~oidc:' + profile.id, name: profile.displayName, email: profile.email, strategy: 'oidc' };
6776
+ parent.debug('AUTH', 'OIDC: Configured user: ' + JSON.stringify(user));
6777
+ return cb(null, user);
6778
+ }
6779
+ ));
6780
+ authStrategyFlags |= domainAuthStrategyConsts.openid;
6781
+ }
6782
+
6783
+ // Generic SAML
6784
+ if (typeof domain.authstrategies.saml == 'object') {
6785
+ if ((typeof domain.authstrategies.saml.cert != 'string') || (typeof domain.authstrategies.saml.idpurl != 'string')) {
6786
+ console.log('ERROR: Missing SAML configuration.');
6787
+ } else {
6788
+ const certPath = obj.common.joinPath(obj.parent.datapath, domain.authstrategies.saml.cert);
6789
+ var cert = obj.fs.readFileSync(certPath);
6790
+ if (cert == null) {
6791
+ console.log('ERROR: Unable to read SAML IdP certificate: ' + domain.authstrategies.saml.cert);
6792
+ } else {
6793
+ var options = { entryPoint: domain.authstrategies.saml.idpurl, issuer: 'meshcentral' };
6794
+ if (typeof domain.authstrategies.saml.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.saml.callbackurl; } else { options.callbackUrl = url + 'auth-saml-callback'; }
6795
+ if (domain.authstrategies.saml.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.saml.disablerequestedauthncontext; }
6796
+ if (typeof domain.authstrategies.saml.entityid == 'string') { options.issuer = domain.authstrategies.saml.entityid; }
6797
+ parent.debug('web', 'Adding SAML SSO with options: ' + JSON.stringify(options));
6798
+ options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('');
6799
+ const SamlStrategy = require('passport-saml').Strategy;
6800
+ passport.use('saml-' + domain.id, new SamlStrategy(options,
6801
+ function (profile, done) {
6802
+ parent.debug('web', 'SAML profile: ' + JSON.stringify(profile));
6803
+ if (typeof profile.nameID != 'string') { return done(); }
6804
+ var user = { sid: '~saml:' + profile.nameID, name: profile.nameID, strategy: 'saml' };
6805
+ if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; }
6806
+ if (typeof profile.email == 'string') { user.email = profile.email; }
6807
+ return done(null, user);
6808
+ }
6809
+ ));
6810
+ authStrategyFlags |= domainAuthStrategyConsts.saml;
6811
+ }
6812
+ }
6813
+ }
6814
+
6815
+ // Intel SAML
6816
+ if (typeof domain.authstrategies.intel == 'object') {
6817
+ if ((typeof domain.authstrategies.intel.cert != 'string') || (typeof domain.authstrategies.intel.idpurl != 'string')) {
6818
+ console.log('ERROR: Missing Intel SAML configuration.');
6819
+ } else {
6820
+ var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.intel.cert));
6821
+ if (cert == null) {
6822
+ console.log('ERROR: Unable to read Intel SAML IdP certificate: ' + domain.authstrategies.intel.cert);
6823
+ } else {
6824
+ var options = { entryPoint: domain.authstrategies.intel.idpurl, issuer: 'meshcentral' };
6825
+ if (typeof domain.authstrategies.intel.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.intel.callbackurl; } else { options.callbackUrl = url + 'auth-intel-callback'; }
6826
+ if (domain.authstrategies.intel.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.intel.disablerequestedauthncontext; }
6827
+ if (typeof domain.authstrategies.intel.entityid == 'string') { options.issuer = domain.authstrategies.intel.entityid; }
6828
+ parent.debug('web', 'Adding Intel SSO with options: ' + JSON.stringify(options));
6829
+ options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('');
6830
+ const SamlStrategy = require('passport-saml').Strategy;
6831
+ passport.use('isaml-' + domain.id, new SamlStrategy(options,
6832
+ function (profile, done) {
6833
+ parent.debug('web', 'Intel profile: ' + JSON.stringify(profile));
6834
+ if (typeof profile.nameID != 'string') { return done(); }
6835
+ var user = { sid: '~intel:' + profile.nameID, name: profile.nameID, strategy: 'intel' };
6836
+ if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; }
6837
+ else if ((typeof profile.FirstName == 'string') && (typeof profile.LastName == 'string')) { user.name = profile.FirstName + ' ' + profile.LastName; }
6838
+ if (typeof profile.email == 'string') { user.email = profile.email; }
6839
+ else if (typeof profile.EmailAddress == 'string') { user.email = profile.EmailAddress; }
6840
+ return done(null, user);
6841
+ }
6842
+ ));
6843
+ authStrategyFlags |= domainAuthStrategyConsts.intelSaml;
6844
+ }
6845
+ }
6846
+ }
6847
+
6848
+ // JumpCloud SAML
6849
+ if (typeof domain.authstrategies.jumpcloud == 'object') {
6850
+ if ((typeof domain.authstrategies.jumpcloud.cert != 'string') || (typeof domain.authstrategies.jumpcloud.idpurl != 'string')) {
6851
+ console.log('ERROR: Missing JumpCloud SAML configuration.');
6852
+ } else {
6853
+ var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.jumpcloud.cert));
6854
+ if (cert == null) {
6855
+ console.log('ERROR: Unable to read JumpCloud IdP certificate: ' + domain.authstrategies.jumpcloud.cert);
6856
+ } else {
6857
+ var options = { entryPoint: domain.authstrategies.jumpcloud.idpurl, issuer: 'meshcentral' };
6858
+ if (typeof domain.authstrategies.jumpcloud.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.jumpcloud.callbackurl; } else { options.callbackUrl = url + 'auth-jumpcloud-callback'; }
6859
+ if (typeof domain.authstrategies.jumpcloud.entityid == 'string') { options.issuer = domain.authstrategies.jumpcloud.entityid; }
6860
+ parent.debug('web', 'Adding JumpCloud SSO with options: ' + JSON.stringify(options));
6861
+ options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join('');
6862
+ const SamlStrategy = require('passport-saml').Strategy;
6863
+ passport.use('jumpcloud-' + domain.id, new SamlStrategy(options,
6864
+ function (profile, done) {
6865
+ parent.debug('web', 'JumpCloud profile: ' + JSON.stringify(profile));
6866
+ if (typeof profile.nameID != 'string') { return done(); }
6867
+ var user = { sid: '~jumpcloud:' + profile.nameID, name: profile.nameID, strategy: 'jumpcloud' };
6868
+ if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; }
6869
+ if (typeof profile.email == 'string') { user.email = profile.email; }
6870
+ return done(null, user);
6871
+ }
6872
+ ));
6873
+ authStrategyFlags |= domainAuthStrategyConsts.jumpCloudSaml;
6874
+ }
6875
+ }
6876
+ }
6877
+
6878
+ return authStrategyFlags;
6879
+ }
6880
6881
// Handle an incoming request as a web relay
6882
function handleWebRelayRequest(req, res) {