mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	Fixed auth strategies when using with a second domain with a DNS (#4404)
This commit is contained in:
		
							parent
							
								
									0edf6883f2
								
							
						
					
					
						commit
						4092615c63
					
				
					 1 changed files with 299 additions and 215 deletions
				
			
		
							
								
								
									
										514
									
								
								webserver.js
									
										
									
									
									
								
							
							
						
						
									
										514
									
								
								webserver.js
									
										
									
									
									
								
							|  | @ -6021,6 +6021,23 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | |||
|             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)); } | ||||
|         } | ||||
| 
 | ||||
|         // Setup all domain auth strategy passport.js
 | ||||
|         for (var i in parent.config.domains) { | ||||
|             if (typeof parent.config.domains[i].authstrategies == 'object') { | ||||
|                 parent.config.domains[i].authstrategies.authStrategyFlags = 0; | ||||
|                 const authStrategyFlags = setupDomainAuthStrategy(parent.config.domains[i]); | ||||
|                 if (authStrategyFlags > 0) { | ||||
|                     if (parent.config.domains[i].dns != null) { | ||||
|                         if (typeof parent.config.domains[''].authstrategies != 'object') { parent.config.domains[''].authstrategies = { authStrategyFlags: 0 }; } | ||||
|                         parent.config.domains[''].authstrategies.authStrategyFlags |= authStrategyFlags; | ||||
|                     } else { | ||||
|                         if (typeof parent.config.domains[i].authstrategies != 'object') { parent.config.domains[i].authstrategies = { authStrategyFlags: 0 }; } | ||||
|                         parent.config.domains[i].authstrategies.authStrategyFlags |= authStrategyFlags; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Setup all HTTP handlers
 | ||||
|         if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req, obj.args.tlsoffload == null); }); } | ||||
|         for (var i in parent.config.domains) { | ||||
|  | @ -6201,26 +6218,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | |||
| 
 | ||||
|             // Setup auth strategies using passport if needed
 | ||||
|             if (typeof domain.authstrategies == 'object') { | ||||
|                 const passport = domain.passport = require('passport'); | ||||
|                 passport.serializeUser(function (user, done) { done(null, user.sid); }); | ||||
|                 passport.deserializeUser(function (sid, done) { done(null, { sid: sid }); }); | ||||
|                 obj.app.use(passport.initialize()); | ||||
|                 //obj.app.use(passport.session());
 | ||||
| 
 | ||||
|                 // Twitter
 | ||||
|                 if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) { | ||||
|                     const TwitterStrategy = require('passport-twitter'); | ||||
|                     var options = { consumerKey: domain.authstrategies.twitter.clientid, consumerSecret: domain.authstrategies.twitter.clientsecret }; | ||||
|                     if (typeof domain.authstrategies.twitter.callbackurl == 'string') { options.callbackURL = domain.authstrategies.twitter.callbackurl; } else { options.callbackURL = url + 'auth-twitter-callback'; } | ||||
|                     parent.debug('web', 'Adding Twitter SSO with options: ' + JSON.stringify(options)); | ||||
|                     passport.use('twitter-' + domain.id, new TwitterStrategy(options, | ||||
|                         function (token, tokenSecret, profile, cb) { | ||||
|                             parent.debug('web', 'Twitter profile: ' + JSON.stringify(profile)); | ||||
|                             var user = { sid: '~twitter:' + profile.id, name: profile.displayName, strategy: 'twitter' }; | ||||
|                             if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } | ||||
|                             return cb(null, user); | ||||
|                         } | ||||
|                     )); | ||||
|                 if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.twitter) != 0) { | ||||
|                     obj.app.get(url + 'auth-twitter', function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|  | @ -6242,19 +6241,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | |||
|                 } | ||||
| 
 | ||||
|                 // Google
 | ||||
|                 if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) { | ||||
|                     const GoogleStrategy = require('passport-google-oauth20'); | ||||
|                     var options = { clientID: domain.authstrategies.google.clientid, clientSecret: domain.authstrategies.google.clientsecret }; | ||||
|                     if (typeof domain.authstrategies.google.callbackurl == 'string') { options.callbackURL = domain.authstrategies.google.callbackurl; } else { options.callbackURL = url + 'auth-google-callback'; } | ||||
|                     parent.debug('web', 'Adding Google SSO with options: ' + JSON.stringify(options)); | ||||
|                     passport.use('google-' + domain.id, new GoogleStrategy(options, | ||||
|                         function (token, tokenSecret, profile, cb) { | ||||
|                             parent.debug('web', 'Google profile: ' + JSON.stringify(profile)); | ||||
|                             var user = { sid: '~google:' + profile.id, name: profile.displayName, strategy: 'google' }; | ||||
|                             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; } | ||||
|                             return cb(null, user); | ||||
|                         } | ||||
|                     )); | ||||
|                 if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.google) != 0) { | ||||
|                     obj.app.get(url + 'auth-google', function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|  | @ -6267,20 +6254,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | |||
|                     }, handleStrategyLogin); | ||||
|                 } | ||||
| 
 | ||||
|                 // Github
 | ||||
|                 if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) { | ||||
|                     const GitHubStrategy = require('passport-github2'); | ||||
|                     var options = { clientID: domain.authstrategies.github.clientid, clientSecret: domain.authstrategies.github.clientsecret }; | ||||
|                     if (typeof domain.authstrategies.github.callbackurl == 'string') { options.callbackURL = domain.authstrategies.github.callbackurl; } else { options.callbackURL = url + 'auth-github-callback'; } | ||||
|                     parent.debug('web', 'Adding Github SSO with options: ' + JSON.stringify(options)); | ||||
|                     passport.use('github-' + domain.id, new GitHubStrategy(options, | ||||
|                         function (token, tokenSecret, profile, cb) { | ||||
|                             parent.debug('web', 'Github profile: ' + JSON.stringify(profile)); | ||||
|                             var user = { sid: '~github:' + profile.id, name: profile.displayName, strategy: 'github' }; | ||||
|                             if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } | ||||
|                             return cb(null, user); | ||||
|                         } | ||||
|                     )); | ||||
|                 // GitHub
 | ||||
|                 if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.github) != 0) { | ||||
|                     obj.app.get(url + 'auth-github', function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|  | @ -6294,19 +6269,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | |||
|                 } | ||||
| 
 | ||||
|                 // Reddit
 | ||||
|                 if ((typeof domain.authstrategies.reddit == 'object') && (typeof domain.authstrategies.reddit.clientid == 'string') && (typeof domain.authstrategies.reddit.clientsecret == 'string')) { | ||||
|                     const RedditStrategy = require('passport-reddit'); | ||||
|                     var options = { clientID: domain.authstrategies.reddit.clientid, clientSecret: domain.authstrategies.reddit.clientsecret }; | ||||
|                     if (typeof domain.authstrategies.reddit.callbackurl == 'string') { options.callbackURL = domain.authstrategies.reddit.callbackurl; } else { options.callbackURL = url + 'auth-reddit-callback'; } | ||||
|                     parent.debug('web', 'Adding Reddit SSO with options: ' + JSON.stringify(options)); | ||||
|                     passport.use('reddit-' + domain.id, new RedditStrategy.Strategy(options, | ||||
|                         function (token, tokenSecret, profile, cb) { | ||||
|                             parent.debug('web', 'Reddit profile: ' + JSON.stringify(profile)); | ||||
|                             var user = { sid: '~reddit:' + profile.id, name: profile.name, strategy: 'reddit' }; | ||||
|                             if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } | ||||
|                             return cb(null, user); | ||||
|                         } | ||||
|                     )); | ||||
|                 if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.reddit) != 0) { | ||||
|                     obj.app.get(url + 'auth-reddit', function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|  | @ -6332,24 +6295,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | |||
|                 } | ||||
| 
 | ||||
|                 // Azure
 | ||||
|                 if ((typeof domain.authstrategies.azure == 'object') && (typeof domain.authstrategies.azure.clientid == 'string') && (typeof domain.authstrategies.azure.clientsecret == 'string')) { | ||||
|                     const AzureOAuth2Strategy = require('passport-azure-oauth2'); | ||||
|                     var options = { clientID: domain.authstrategies.azure.clientid, clientSecret: domain.authstrategies.azure.clientsecret, tenant: domain.authstrategies.azure.tenantid }; | ||||
|                     if (typeof domain.authstrategies.azure.callbackurl == 'string') { options.callbackURL = domain.authstrategies.azure.callbackurl; } else { options.callbackURL = url + 'auth-azure-callback'; } | ||||
|                     parent.debug('web', 'Adding Azure SSO with options: ' + JSON.stringify(options)); | ||||
|                     passport.use('azure-' + domain.id, new AzureOAuth2Strategy(options, | ||||
|                         function (accessToken, refreshtoken, params, profile, done) { | ||||
|                             var userex = null; | ||||
|                             try { userex = require('jwt-simple').decode(params.id_token, "", true); } catch (ex) { } | ||||
|                             parent.debug('web', 'Azure profile: ' + JSON.stringify(userex)); | ||||
|                             var user = null; | ||||
|                             if (userex != null) { | ||||
|                                 var user = { sid: '~azure:' + userex.unique_name, name: userex.name, strategy: 'azure' }; | ||||
|                                 if (typeof userex.email == 'string') { user.email = userex.email; } | ||||
|                             } | ||||
|                             return done(null, user); | ||||
|                         } | ||||
|                     )); | ||||
|                 if ((domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.azure) != 0) { | ||||
|                     obj.app.get(url + 'auth-azure', function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|  | @ -6374,155 +6320,52 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | |||
|                     }, handleStrategyLogin); | ||||
|                 } | ||||
| 
 | ||||
|                 // Generic OpenID Connect
 | ||||
|                 if ((typeof domain.authstrategies.oidc == 'object') && (typeof domain.authstrategies.oidc.clientid == 'string') && (typeof domain.authstrategies.oidc.clientsecret == 'string') && (typeof domain.authstrategies.oidc.issuer == 'string')) { | ||||
|                     var options = { | ||||
|                         authorizationURL: domain.authstrategies.oidc.authorizationurl, | ||||
|                         callbackURL: domain.authstrategies.oidc.callbackurl, | ||||
|                         clientID: domain.authstrategies.oidc.clientid, | ||||
|                         clientSecret: domain.authstrategies.oidc.clientsecret, | ||||
|                         issuer: domain.authstrategies.oidc.issuer, | ||||
|                         tokenURL: domain.authstrategies.oidc.tokenurl, | ||||
|                         userInfoURL: domain.authstrategies.oidc.userinfourl, | ||||
|                         scope: ['openid profile email'], | ||||
|                         responseMode: 'form_post', | ||||
|                         state: true | ||||
|                     }; | ||||
|                     const OIDCStrategy = require('@mstrhakr/passport-generic-oidc'); | ||||
|                     if (typeof domain.authstrategies.oidc.callbackurl == 'string') { options.callbackURL = domain.authstrategies.oidc.callbackurl; } else { options.callbackURL = url + 'oidc-callback'; } | ||||
|                     parent.debug('web', 'Adding Generic OIDC SSO with options: ' + JSON.stringify(options)); | ||||
|                     passport.use('openidconnect', new OIDCStrategy.Strategy(options, | ||||
|                         function verify(iss, sub, profile, cb) { | ||||
|                             var user = { sid: '~oidc:' + profile.id, name: profile.displayName, email: profile.email, strategy: 'oidc' }; | ||||
|                             parent.debug('AUTH', 'OIDC: Configured user: ' + JSON.stringify(user)); | ||||
|                             return cb(null, user); | ||||
|                         } | ||||
|                     )); | ||||
|                 // Generic OpenID
 | ||||
|                 if (domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.openid != 0) { | ||||
|                     obj.app.get(url + 'auth-oidc', domain.passport.authenticate('openidconnect')); | ||||
|                     obj.app.get(url + 'oidc-callback', domain.passport.authenticate('openidconnect', { failureRedirect: '/login?failed-auth-attempt', failureFlash: true }), handleStrategyLogin); | ||||
|                 } | ||||
| 
 | ||||
| 
 | ||||
|                 // Generic SAML
 | ||||
|                 if (typeof domain.authstrategies.saml == 'object') { | ||||
|                     if ((typeof domain.authstrategies.saml.cert != 'string') || (typeof domain.authstrategies.saml.idpurl != 'string')) { | ||||
|                         console.log('ERROR: Missing SAML configuration.'); | ||||
|                     } else { | ||||
|                         const certPath = obj.common.joinPath(obj.parent.datapath, domain.authstrategies.saml.cert); | ||||
|                         var cert = obj.fs.readFileSync(certPath); | ||||
|                         if (cert == null) { | ||||
|                             console.log('ERROR: Unable to read SAML IdP certificate: ' + domain.authstrategies.saml.cert); | ||||
|                         } else { | ||||
|                             var options = { entryPoint: domain.authstrategies.saml.idpurl, issuer: 'meshcentral' }; | ||||
|                             if (typeof domain.authstrategies.saml.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.saml.callbackurl; } else { options.callbackUrl = url + 'auth-saml-callback'; } | ||||
|                             if (domain.authstrategies.saml.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.saml.disablerequestedauthncontext; } | ||||
|                             if (typeof domain.authstrategies.saml.entityid == 'string') { options.issuer = domain.authstrategies.saml.entityid; } | ||||
|                             parent.debug('web', 'Adding SAML SSO with options: ' + JSON.stringify(options)); | ||||
|                             options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join(''); | ||||
|                             const SamlStrategy = require('passport-saml').Strategy; | ||||
|                             passport.use('saml-' + domain.id, new SamlStrategy(options, | ||||
|                                 function (profile, done) { | ||||
|                                     parent.debug('web', 'SAML profile: ' + JSON.stringify(profile)); | ||||
|                                     if (typeof profile.nameID != 'string') { return done(); } | ||||
|                                     var user = { sid: '~saml:' + profile.nameID, name: profile.nameID, strategy: 'saml' }; | ||||
|                                     if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; } | ||||
|                                     if (typeof profile.email == 'string') { user.email = profile.email; } | ||||
|                                     return done(null, user); | ||||
|                                 } | ||||
|                             )); | ||||
|                             obj.app.get(url + 'auth-saml', function (req, res, next) { | ||||
|                                 var domain = getDomain(req); | ||||
|                                 if (domain.passport == null) { next(); return; } | ||||
|                                 domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                             }); | ||||
|                             obj.app.post(url + 'auth-saml-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { | ||||
|                                 var domain = getDomain(req); | ||||
|                                 if (domain.passport == null) { next(); return; } | ||||
|                                 domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                             }, handleStrategyLogin); | ||||
|                         } | ||||
|                     } | ||||
|                 if (domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.saml != 0) { | ||||
|                     obj.app.get(url + 'auth-saml', function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|                         domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                     }); | ||||
|                     obj.app.post(url + 'auth-saml-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|                         domain.passport.authenticate('saml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                     }, handleStrategyLogin); | ||||
|                 } | ||||
| 
 | ||||
|                 // Intel SAML
 | ||||
|                 if (typeof domain.authstrategies.intel == 'object') { | ||||
|                     if ((typeof domain.authstrategies.intel.cert != 'string') || (typeof domain.authstrategies.intel.idpurl != 'string')) { | ||||
|                         console.log('ERROR: Missing Intel SAML configuration.'); | ||||
|                     } else { | ||||
|                         var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.intel.cert)); | ||||
|                         if (cert == null) { | ||||
|                             console.log('ERROR: Unable to read Intel SAML IdP certificate: ' + domain.authstrategies.intel.cert); | ||||
|                         } else { | ||||
|                             var options = { entryPoint: domain.authstrategies.intel.idpurl, issuer: 'meshcentral' }; | ||||
|                             if (typeof domain.authstrategies.intel.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.intel.callbackurl; } else { options.callbackUrl = url + 'auth-intel-callback'; } | ||||
|                             if (domain.authstrategies.intel.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.intel.disablerequestedauthncontext; } | ||||
|                             if (typeof domain.authstrategies.intel.entityid == 'string') { options.issuer = domain.authstrategies.intel.entityid; } | ||||
|                             parent.debug('web', 'Adding Intel SSO with options: ' + JSON.stringify(options)); | ||||
|                             options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join(''); | ||||
|                             const SamlStrategy = require('passport-saml').Strategy; | ||||
|                             passport.use('isaml-' + domain.id, new SamlStrategy(options, | ||||
|                                 function (profile, done) { | ||||
|                                     parent.debug('web', 'Intel profile: ' + JSON.stringify(profile)); | ||||
|                                     if (typeof profile.nameID != 'string') { return done(); } | ||||
|                                     var user = { sid: '~intel:' + profile.nameID, name: profile.nameID, strategy: 'intel' }; | ||||
|                                     if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; } | ||||
|                                     else if ((typeof profile.FirstName == 'string') && (typeof profile.LastName == 'string')) { user.name = profile.FirstName + ' ' + profile.LastName; } | ||||
|                                     if (typeof profile.email == 'string') { user.email = profile.email; } | ||||
|                                     else if (typeof profile.EmailAddress == 'string') { user.email = profile.EmailAddress; } | ||||
|                                     return done(null, user); | ||||
|                                 } | ||||
|                             )); | ||||
|                             obj.app.get(url + 'auth-intel', function (req, res, next) { | ||||
|                                 var domain = getDomain(req); | ||||
|                                 if (domain.passport == null) { next(); return; } | ||||
|                                 domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                             }); | ||||
|                             obj.app.post(url + 'auth-intel-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { | ||||
|                                 var domain = getDomain(req); | ||||
|                                 if (domain.passport == null) { next(); return; } | ||||
|                                 domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                             }, handleStrategyLogin); | ||||
|                         } | ||||
|                     } | ||||
|                 if (domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.intelSaml != 0) { | ||||
|                     obj.app.get(url + 'auth-intel', function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|                         domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                     }); | ||||
|                     obj.app.post(url + 'auth-intel-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|                         domain.passport.authenticate('isaml-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                     }, handleStrategyLogin); | ||||
|                 } | ||||
| 
 | ||||
|                 // JumpCloud SAML
 | ||||
|                 if (typeof domain.authstrategies.jumpcloud == 'object') { | ||||
|                     if ((typeof domain.authstrategies.jumpcloud.cert != 'string') || (typeof domain.authstrategies.jumpcloud.idpurl != 'string')) { | ||||
|                         console.log('ERROR: Missing JumpCloud SAML configuration.'); | ||||
|                     } else { | ||||
|                         var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.jumpcloud.cert)); | ||||
|                         if (cert == null) { | ||||
|                             console.log('ERROR: Unable to read JumpCloud IdP certificate: ' + domain.authstrategies.jumpcloud.cert); | ||||
|                         } else { | ||||
|                             var options = { entryPoint: domain.authstrategies.jumpcloud.idpurl, issuer: 'meshcentral' }; | ||||
|                             if (typeof domain.authstrategies.jumpcloud.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.jumpcloud.callbackurl; } else { options.callbackUrl = url + 'auth-jumpcloud-callback'; } | ||||
|                             if (typeof domain.authstrategies.jumpcloud.entityid == 'string') { options.issuer = domain.authstrategies.jumpcloud.entityid; } | ||||
|                             parent.debug('web', 'Adding JumpCloud SSO with options: ' + JSON.stringify(options)); | ||||
|                             options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join(''); | ||||
|                             const SamlStrategy = require('passport-saml').Strategy; | ||||
|                             passport.use('jumpcloud-' + domain.id, new SamlStrategy(options, | ||||
|                                 function (profile, done) { | ||||
|                                     parent.debug('web', 'JumpCloud profile: ' + JSON.stringify(profile)); | ||||
|                                     if (typeof profile.nameID != 'string') { return done(); } | ||||
|                                     var user = { sid: '~jumpcloud:' + profile.nameID, name: profile.nameID, strategy: 'jumpcloud' }; | ||||
|                                     if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; } | ||||
|                                     if (typeof profile.email == 'string') { user.email = profile.email; } | ||||
|                                     return done(null, user); | ||||
|                                 } | ||||
|                             )); | ||||
|                             obj.app.get(url + 'auth-jumpcloud', function (req, res, next) { | ||||
|                                 var domain = getDomain(req); | ||||
|                                 if (domain.passport == null) { next(); return; } | ||||
|                                 domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                             }); | ||||
|                             obj.app.post(url + 'auth-jumpcloud-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { | ||||
|                                 var domain = getDomain(req); | ||||
|                                 if (domain.passport == null) { next(); return; } | ||||
|                                 domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                             }, handleStrategyLogin); | ||||
|                         } | ||||
|                     } | ||||
|                 if (domain.authstrategies.authStrategyFlags & domainAuthStrategyConsts.jumpCloudSaml != 0) { | ||||
|                     obj.app.get(url + 'auth-jumpcloud', function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|                         domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                     }); | ||||
|                     obj.app.post(url + 'auth-jumpcloud-callback', obj.bodyParser.urlencoded({ extended: false }), function (req, res, next) { | ||||
|                         var domain = getDomain(req); | ||||
|                         if (domain.passport == null) { next(); return; } | ||||
|                         domain.passport.authenticate('jumpcloud-' + domain.id, { failureRedirect: '/', failureFlash: true })(req, res, next); | ||||
|                     }, handleStrategyLogin); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|  | @ -6793,6 +6636,247 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF | |||
|         if (doneFunc) doneFunc(); | ||||
|     } | ||||
| 
 | ||||
|     // Auth strategy flags
 | ||||
|     const domainAuthStrategyConsts = { | ||||
|         twitter: 1, | ||||
|         google: 2, | ||||
|         github: 3, | ||||
|         reddit: 8, | ||||
|         azure: 16, | ||||
|         openid: 32, | ||||
|         saml: 64, | ||||
|         intelSaml: 128, | ||||
|         jumpCloudSaml: 256 | ||||
|     } | ||||
| 
 | ||||
|     // Setup auth strategies for a domain
 | ||||
|     function setupDomainAuthStrategy(domain) { | ||||
|         // Return the auth strategies that have been setup
 | ||||
|         var authStrategyFlags = 0; | ||||
| 
 | ||||
|         // Setup auth strategies using passport if needed
 | ||||
|         if (typeof domain.authstrategies != 'object') return authStrategyFlags; | ||||
| 
 | ||||
|         const url = domain.url; | ||||
|         const passport = domain.passport = require('passport'); | ||||
|         passport.serializeUser(function (user, done) { done(null, user.sid); }); | ||||
|         passport.deserializeUser(function (sid, done) { done(null, { sid: sid }); }); | ||||
|         obj.app.use(passport.initialize()); | ||||
| 
 | ||||
|         // Twitter
 | ||||
|         if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.clientid == 'string') && (typeof domain.authstrategies.twitter.clientsecret == 'string')) { | ||||
|             const TwitterStrategy = require('passport-twitter'); | ||||
|             var options = { consumerKey: domain.authstrategies.twitter.clientid, consumerSecret: domain.authstrategies.twitter.clientsecret }; | ||||
|             if (typeof domain.authstrategies.twitter.callbackurl == 'string') { options.callbackURL = domain.authstrategies.twitter.callbackurl; } else { options.callbackURL = url + 'auth-twitter-callback'; } | ||||
|             parent.debug('web', 'Adding Twitter SSO with options: ' + JSON.stringify(options)); | ||||
|             passport.use('twitter-' + domain.id, new TwitterStrategy(options, | ||||
|                 function (token, tokenSecret, profile, cb) { | ||||
|                     parent.debug('web', 'Twitter profile: ' + JSON.stringify(profile)); | ||||
|                     var user = { sid: '~twitter:' + profile.id, name: profile.displayName, strategy: 'twitter' }; | ||||
|                     if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } | ||||
|                     return cb(null, user); | ||||
|                 } | ||||
|             )); | ||||
|             authStrategyFlags |= domainAuthStrategyConsts.twitter; | ||||
|         } | ||||
| 
 | ||||
|         // Google
 | ||||
|         if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) { | ||||
|             const GoogleStrategy = require('passport-google-oauth20'); | ||||
|             var options = { clientID: domain.authstrategies.google.clientid, clientSecret: domain.authstrategies.google.clientsecret }; | ||||
|             if (typeof domain.authstrategies.google.callbackurl == 'string') { options.callbackURL = domain.authstrategies.google.callbackurl; } else { options.callbackURL = url + 'auth-google-callback'; } | ||||
|             parent.debug('web', 'Adding Google SSO with options: ' + JSON.stringify(options)); | ||||
|             passport.use('google-' + domain.id, new GoogleStrategy(options, | ||||
|                 function (token, tokenSecret, profile, cb) { | ||||
|                     parent.debug('web', 'Google profile: ' + JSON.stringify(profile)); | ||||
|                     var user = { sid: '~google:' + profile.id, name: profile.displayName, strategy: 'google' }; | ||||
|                     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; } | ||||
|                     return cb(null, user); | ||||
|                 } | ||||
|             )); | ||||
|             authStrategyFlags |= domainAuthStrategyConsts.google; | ||||
|         } | ||||
| 
 | ||||
|         // Github
 | ||||
|         if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) { | ||||
|             const GitHubStrategy = require('passport-github2'); | ||||
|             var options = { clientID: domain.authstrategies.github.clientid, clientSecret: domain.authstrategies.github.clientsecret }; | ||||
|             if (typeof domain.authstrategies.github.callbackurl == 'string') { options.callbackURL = domain.authstrategies.github.callbackurl; } else { options.callbackURL = url + 'auth-github-callback'; } | ||||
|             parent.debug('web', 'Adding Github SSO with options: ' + JSON.stringify(options)); | ||||
|             passport.use('github-' + domain.id, new GitHubStrategy(options, | ||||
|                 function (token, tokenSecret, profile, cb) { | ||||
|                     parent.debug('web', 'Github profile: ' + JSON.stringify(profile)); | ||||
|                     var user = { sid: '~github:' + profile.id, name: profile.displayName, strategy: 'github' }; | ||||
|                     if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } | ||||
|                     return cb(null, user); | ||||
|                 } | ||||
|             )); | ||||
|             authStrategyFlags |= domainAuthStrategyConsts.github; | ||||
|         } | ||||
| 
 | ||||
|         // Reddit
 | ||||
|         if ((typeof domain.authstrategies.reddit == 'object') && (typeof domain.authstrategies.reddit.clientid == 'string') && (typeof domain.authstrategies.reddit.clientsecret == 'string')) { | ||||
|             const RedditStrategy = require('passport-reddit'); | ||||
|             var options = { clientID: domain.authstrategies.reddit.clientid, clientSecret: domain.authstrategies.reddit.clientsecret }; | ||||
|             if (typeof domain.authstrategies.reddit.callbackurl == 'string') { options.callbackURL = domain.authstrategies.reddit.callbackurl; } else { options.callbackURL = url + 'auth-reddit-callback'; } | ||||
|             parent.debug('web', 'Adding Reddit SSO with options: ' + JSON.stringify(options)); | ||||
|             passport.use('reddit-' + domain.id, new RedditStrategy.Strategy(options, | ||||
|                 function (token, tokenSecret, profile, cb) { | ||||
|                     parent.debug('web', 'Reddit profile: ' + JSON.stringify(profile)); | ||||
|                     var user = { sid: '~reddit:' + profile.id, name: profile.name, strategy: 'reddit' }; | ||||
|                     if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } | ||||
|                     return cb(null, user); | ||||
|                 } | ||||
|             )); | ||||
|             authStrategyFlags |= domainAuthStrategyConsts.reddit; | ||||
|         } | ||||
| 
 | ||||
|         // Azure
 | ||||
|         if ((typeof domain.authstrategies.azure == 'object') && (typeof domain.authstrategies.azure.clientid == 'string') && (typeof domain.authstrategies.azure.clientsecret == 'string')) { | ||||
|             const AzureOAuth2Strategy = require('passport-azure-oauth2'); | ||||
|             var options = { clientID: domain.authstrategies.azure.clientid, clientSecret: domain.authstrategies.azure.clientsecret, tenant: domain.authstrategies.azure.tenantid }; | ||||
|             if (typeof domain.authstrategies.azure.callbackurl == 'string') { options.callbackURL = domain.authstrategies.azure.callbackurl; } else { options.callbackURL = url + 'auth-azure-callback'; } | ||||
|             parent.debug('web', 'Adding Azure SSO with options: ' + JSON.stringify(options)); | ||||
|             passport.use('azure-' + domain.id, new AzureOAuth2Strategy(options, | ||||
|                 function (accessToken, refreshtoken, params, profile, done) { | ||||
|                     var userex = null; | ||||
|                     try { userex = require('jwt-simple').decode(params.id_token, '', true); } catch (ex) { } | ||||
|                     parent.debug('web', 'Azure profile: ' + JSON.stringify(userex)); | ||||
|                     var user = null; | ||||
|                     if (userex != null) { | ||||
|                         var user = { sid: '~azure:' + userex.unique_name, name: userex.name, strategy: 'azure' }; | ||||
|                         if (typeof userex.email == 'string') { user.email = userex.email; } | ||||
|                     } | ||||
|                     return done(null, user); | ||||
|                 } | ||||
|             )); | ||||
|             authStrategyFlags |= domainAuthStrategyConsts.azure; | ||||
|         } | ||||
| 
 | ||||
|         // Generic OpenID Connect
 | ||||
|         if ((typeof domain.authstrategies.oidc == 'object') && (typeof domain.authstrategies.oidc.clientid == 'string') && (typeof domain.authstrategies.oidc.clientsecret == 'string') && (typeof domain.authstrategies.oidc.issuer == 'string')) { | ||||
|             var options = { | ||||
|                 authorizationURL: domain.authstrategies.oidc.authorizationurl, | ||||
|                 callbackURL: domain.authstrategies.oidc.callbackurl, | ||||
|                 clientID: domain.authstrategies.oidc.clientid, | ||||
|                 clientSecret: domain.authstrategies.oidc.clientsecret, | ||||
|                 issuer: domain.authstrategies.oidc.issuer, | ||||
|                 tokenURL: domain.authstrategies.oidc.tokenurl, | ||||
|                 userInfoURL: domain.authstrategies.oidc.userinfourl, | ||||
|                 scope: ['openid profile email'], | ||||
|                 responseMode: 'form_post', | ||||
|                 state: true | ||||
|             }; | ||||
|             const OIDCStrategy = require('@mstrhakr/passport-generic-oidc'); | ||||
|             if (typeof domain.authstrategies.oidc.callbackurl == 'string') { options.callbackURL = domain.authstrategies.oidc.callbackurl; } else { options.callbackURL = url + 'oidc-callback'; } | ||||
|             parent.debug('web', 'Adding Generic OIDC SSO with options: ' + JSON.stringify(options)); | ||||
|             passport.use('openidconnect', new OIDCStrategy.Strategy(options, | ||||
|                 function verify(iss, sub, profile, cb) { | ||||
|                     var user = { sid: '~oidc:' + profile.id, name: profile.displayName, email: profile.email, strategy: 'oidc' }; | ||||
|                     parent.debug('AUTH', 'OIDC: Configured user: ' + JSON.stringify(user)); | ||||
|                     return cb(null, user); | ||||
|                 } | ||||
|             )); | ||||
|             authStrategyFlags |= domainAuthStrategyConsts.openid; | ||||
|         } | ||||
| 
 | ||||
|         // Generic SAML
 | ||||
|         if (typeof domain.authstrategies.saml == 'object') { | ||||
|             if ((typeof domain.authstrategies.saml.cert != 'string') || (typeof domain.authstrategies.saml.idpurl != 'string')) { | ||||
|                 console.log('ERROR: Missing SAML configuration.'); | ||||
|             } else { | ||||
|                 const certPath = obj.common.joinPath(obj.parent.datapath, domain.authstrategies.saml.cert); | ||||
|                 var cert = obj.fs.readFileSync(certPath); | ||||
|                 if (cert == null) { | ||||
|                     console.log('ERROR: Unable to read SAML IdP certificate: ' + domain.authstrategies.saml.cert); | ||||
|                 } else { | ||||
|                     var options = { entryPoint: domain.authstrategies.saml.idpurl, issuer: 'meshcentral' }; | ||||
|                     if (typeof domain.authstrategies.saml.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.saml.callbackurl; } else { options.callbackUrl = url + 'auth-saml-callback'; } | ||||
|                     if (domain.authstrategies.saml.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.saml.disablerequestedauthncontext; } | ||||
|                     if (typeof domain.authstrategies.saml.entityid == 'string') { options.issuer = domain.authstrategies.saml.entityid; } | ||||
|                     parent.debug('web', 'Adding SAML SSO with options: ' + JSON.stringify(options)); | ||||
|                     options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join(''); | ||||
|                     const SamlStrategy = require('passport-saml').Strategy; | ||||
|                     passport.use('saml-' + domain.id, new SamlStrategy(options, | ||||
|                         function (profile, done) { | ||||
|                             parent.debug('web', 'SAML profile: ' + JSON.stringify(profile)); | ||||
|                             if (typeof profile.nameID != 'string') { return done(); } | ||||
|                             var user = { sid: '~saml:' + profile.nameID, name: profile.nameID, strategy: 'saml' }; | ||||
|                             if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; } | ||||
|                             if (typeof profile.email == 'string') { user.email = profile.email; } | ||||
|                             return done(null, user); | ||||
|                         } | ||||
|                     )); | ||||
|                     authStrategyFlags |= domainAuthStrategyConsts.saml; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Intel SAML
 | ||||
|         if (typeof domain.authstrategies.intel == 'object') { | ||||
|             if ((typeof domain.authstrategies.intel.cert != 'string') || (typeof domain.authstrategies.intel.idpurl != 'string')) { | ||||
|                 console.log('ERROR: Missing Intel SAML configuration.'); | ||||
|             } else { | ||||
|                 var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.intel.cert)); | ||||
|                 if (cert == null) { | ||||
|                     console.log('ERROR: Unable to read Intel SAML IdP certificate: ' + domain.authstrategies.intel.cert); | ||||
|                 } else { | ||||
|                     var options = { entryPoint: domain.authstrategies.intel.idpurl, issuer: 'meshcentral' }; | ||||
|                     if (typeof domain.authstrategies.intel.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.intel.callbackurl; } else { options.callbackUrl = url + 'auth-intel-callback'; } | ||||
|                     if (domain.authstrategies.intel.disablerequestedauthncontext != null) { options.disableRequestedAuthnContext = domain.authstrategies.intel.disablerequestedauthncontext; } | ||||
|                     if (typeof domain.authstrategies.intel.entityid == 'string') { options.issuer = domain.authstrategies.intel.entityid; } | ||||
|                     parent.debug('web', 'Adding Intel SSO with options: ' + JSON.stringify(options)); | ||||
|                     options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join(''); | ||||
|                     const SamlStrategy = require('passport-saml').Strategy; | ||||
|                     passport.use('isaml-' + domain.id, new SamlStrategy(options, | ||||
|                         function (profile, done) { | ||||
|                             parent.debug('web', 'Intel profile: ' + JSON.stringify(profile)); | ||||
|                             if (typeof profile.nameID != 'string') { return done(); } | ||||
|                             var user = { sid: '~intel:' + profile.nameID, name: profile.nameID, strategy: 'intel' }; | ||||
|                             if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; } | ||||
|                             else if ((typeof profile.FirstName == 'string') && (typeof profile.LastName == 'string')) { user.name = profile.FirstName + ' ' + profile.LastName; } | ||||
|                             if (typeof profile.email == 'string') { user.email = profile.email; } | ||||
|                             else if (typeof profile.EmailAddress == 'string') { user.email = profile.EmailAddress; } | ||||
|                             return done(null, user); | ||||
|                         } | ||||
|                     )); | ||||
|                     authStrategyFlags |= domainAuthStrategyConsts.intelSaml; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // JumpCloud SAML
 | ||||
|         if (typeof domain.authstrategies.jumpcloud == 'object') { | ||||
|             if ((typeof domain.authstrategies.jumpcloud.cert != 'string') || (typeof domain.authstrategies.jumpcloud.idpurl != 'string')) { | ||||
|                 console.log('ERROR: Missing JumpCloud SAML configuration.'); | ||||
|             } else { | ||||
|                 var cert = obj.fs.readFileSync(obj.common.joinPath(obj.parent.datapath, domain.authstrategies.jumpcloud.cert)); | ||||
|                 if (cert == null) { | ||||
|                     console.log('ERROR: Unable to read JumpCloud IdP certificate: ' + domain.authstrategies.jumpcloud.cert); | ||||
|                 } else { | ||||
|                     var options = { entryPoint: domain.authstrategies.jumpcloud.idpurl, issuer: 'meshcentral' }; | ||||
|                     if (typeof domain.authstrategies.jumpcloud.callbackurl == 'string') { options.callbackUrl = domain.authstrategies.jumpcloud.callbackurl; } else { options.callbackUrl = url + 'auth-jumpcloud-callback'; } | ||||
|                     if (typeof domain.authstrategies.jumpcloud.entityid == 'string') { options.issuer = domain.authstrategies.jumpcloud.entityid; } | ||||
|                     parent.debug('web', 'Adding JumpCloud SSO with options: ' + JSON.stringify(options)); | ||||
|                     options.cert = cert.toString().split('-----BEGIN CERTIFICATE-----').join('').split('-----END CERTIFICATE-----').join(''); | ||||
|                     const SamlStrategy = require('passport-saml').Strategy; | ||||
|                     passport.use('jumpcloud-' + domain.id, new SamlStrategy(options, | ||||
|                         function (profile, done) { | ||||
|                             parent.debug('web', 'JumpCloud profile: ' + JSON.stringify(profile)); | ||||
|                             if (typeof profile.nameID != 'string') { return done(); } | ||||
|                             var user = { sid: '~jumpcloud:' + profile.nameID, name: profile.nameID, strategy: 'jumpcloud' }; | ||||
|                             if ((typeof profile.firstname == 'string') && (typeof profile.lastname == 'string')) { user.name = profile.firstname + ' ' + profile.lastname; } | ||||
|                             if (typeof profile.email == 'string') { user.email = profile.email; } | ||||
|                             return done(null, user); | ||||
|                         } | ||||
|                     )); | ||||
|                     authStrategyFlags |= domainAuthStrategyConsts.jumpCloudSaml; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return authStrategyFlags; | ||||
|     } | ||||
| 
 | ||||
|     // Handle an incoming request as a web relay 
 | ||||
|     function handleWebRelayRequest(req, res) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue