diff --git a/MeshCentralServer.njsproj b/MeshCentralServer.njsproj
index 4bc2a1ee..e752bf83 100644
--- a/MeshCentralServer.njsproj
+++ b/MeshCentralServer.njsproj
@@ -502,6 +502,7 @@
+
@@ -512,6 +513,7 @@
+
diff --git a/agents/MeshCmd-signed.exe b/agents/MeshCmd-signed.exe
index c25f64de..feeadaa1 100644
Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ
diff --git a/agents/MeshCmd64-signed.exe b/agents/MeshCmd64-signed.exe
index a16938aa..f3d0d0bb 100644
Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ
diff --git a/agents/MeshService-signed.exe b/agents/MeshService-signed.exe
index b91921f4..838c9690 100644
Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ
diff --git a/agents/MeshService.exe b/agents/MeshService.exe
index 14e59669..ab1c1243 100644
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
diff --git a/agents/MeshService64-signed.exe b/agents/MeshService64-signed.exe
index ba3471ec..ced04ee6 100644
Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ
diff --git a/agents/MeshService64.exe b/agents/MeshService64.exe
index 9b8b6185..e7b68774 100644
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
diff --git a/agents/agents-new/MeshCmd-signed.exe b/agents/agents-new/MeshCmd-signed.exe
new file mode 100644
index 00000000..feeadaa1
Binary files /dev/null and b/agents/agents-new/MeshCmd-signed.exe differ
diff --git a/agents/agents-new/MeshCmd64-signed.exe b/agents/agents-new/MeshCmd64-signed.exe
new file mode 100644
index 00000000..f3d0d0bb
Binary files /dev/null and b/agents/agents-new/MeshCmd64-signed.exe differ
diff --git a/agents/agents-new/MeshService-signed.exe b/agents/agents-new/MeshService-signed.exe
new file mode 100644
index 00000000..838c9690
Binary files /dev/null and b/agents/agents-new/MeshService-signed.exe differ
diff --git a/agents/agents-new/MeshService.exe b/agents/agents-new/MeshService.exe
new file mode 100644
index 00000000..ab1c1243
Binary files /dev/null and b/agents/agents-new/MeshService.exe differ
diff --git a/agents/agents-new/MeshService64-signed.exe b/agents/agents-new/MeshService64-signed.exe
new file mode 100644
index 00000000..ced04ee6
Binary files /dev/null and b/agents/agents-new/MeshService64-signed.exe differ
diff --git a/agents/agents-new/MeshService64.exe b/agents/agents-new/MeshService64.exe
new file mode 100644
index 00000000..e7b68774
Binary files /dev/null and b/agents/agents-new/MeshService64.exe differ
diff --git a/agents/agents-old/MeshCmd-signed.exe b/agents/agents-old/MeshCmd-signed.exe
new file mode 100644
index 00000000..c25f64de
Binary files /dev/null and b/agents/agents-old/MeshCmd-signed.exe differ
diff --git a/agents/agents-old/MeshCmd64-signed.exe b/agents/agents-old/MeshCmd64-signed.exe
new file mode 100644
index 00000000..a16938aa
Binary files /dev/null and b/agents/agents-old/MeshCmd64-signed.exe differ
diff --git a/agents/agents-old/MeshService-signed.exe b/agents/agents-old/MeshService-signed.exe
new file mode 100644
index 00000000..b91921f4
Binary files /dev/null and b/agents/agents-old/MeshService-signed.exe differ
diff --git a/agents/agents-old/MeshService.exe b/agents/agents-old/MeshService.exe
new file mode 100644
index 00000000..14e59669
Binary files /dev/null and b/agents/agents-old/MeshService.exe differ
diff --git a/agents/agents-old/MeshService64-signed.exe b/agents/agents-old/MeshService64-signed.exe
new file mode 100644
index 00000000..ba3471ec
Binary files /dev/null and b/agents/agents-old/MeshService64-signed.exe differ
diff --git a/agents/agents-old/MeshService64.exe b/agents/agents-old/MeshService64.exe
new file mode 100644
index 00000000..9b8b6185
Binary files /dev/null and b/agents/agents-old/MeshService64.exe differ
diff --git a/agents/meshagent_arm b/agents/agents-old/meshagent_arm
similarity index 100%
rename from agents/meshagent_arm
rename to agents/agents-old/meshagent_arm
diff --git a/agents/meshagent_arm-linaro b/agents/agents-old/meshagent_arm-linaro
similarity index 100%
rename from agents/meshagent_arm-linaro
rename to agents/agents-old/meshagent_arm-linaro
diff --git a/agents/meshagent_arm64 b/agents/agents-old/meshagent_arm64
similarity index 100%
rename from agents/meshagent_arm64
rename to agents/agents-old/meshagent_arm64
diff --git a/agents/meshagent_armhf b/agents/agents-old/meshagent_armhf
similarity index 100%
rename from agents/meshagent_armhf
rename to agents/agents-old/meshagent_armhf
diff --git a/agents/meshagent_freebsd_x86-64 b/agents/agents-old/meshagent_freebsd_x86-64
similarity index 100%
rename from agents/meshagent_freebsd_x86-64
rename to agents/agents-old/meshagent_freebsd_x86-64
diff --git a/agents/meshagent_mips b/agents/agents-old/meshagent_mips
similarity index 100%
rename from agents/meshagent_mips
rename to agents/agents-old/meshagent_mips
diff --git a/agents/meshagent_osx-x86-64 b/agents/agents-old/meshagent_osx-x86-64
similarity index 100%
rename from agents/meshagent_osx-x86-64
rename to agents/agents-old/meshagent_osx-x86-64
diff --git a/agents/meshagent_pogo b/agents/agents-old/meshagent_pogo
similarity index 100%
rename from agents/meshagent_pogo
rename to agents/agents-old/meshagent_pogo
diff --git a/agents/meshagent_poky b/agents/agents-old/meshagent_poky
similarity index 100%
rename from agents/meshagent_poky
rename to agents/agents-old/meshagent_poky
diff --git a/agents/meshagent_poky64 b/agents/agents-old/meshagent_poky64
similarity index 100%
rename from agents/meshagent_poky64
rename to agents/agents-old/meshagent_poky64
diff --git a/agents/meshagent_x86 b/agents/agents-old/meshagent_x86
similarity index 100%
rename from agents/meshagent_x86
rename to agents/agents-old/meshagent_x86
diff --git a/agents/meshagent_x86-64 b/agents/agents-old/meshagent_x86-64
similarity index 100%
rename from agents/meshagent_x86-64
rename to agents/agents-old/meshagent_x86-64
diff --git a/agents/meshagent_x86-64_nokvm b/agents/agents-old/meshagent_x86-64_nokvm
similarity index 100%
rename from agents/meshagent_x86-64_nokvm
rename to agents/agents-old/meshagent_x86-64_nokvm
diff --git a/agents/meshagent_x86_nokvm b/agents/agents-old/meshagent_x86_nokvm
similarity index 100%
rename from agents/meshagent_x86_nokvm
rename to agents/agents-old/meshagent_x86_nokvm
diff --git a/meshcentral.js b/meshcentral.js
index 309b7d0d..3dfd01d3 100644
--- a/meshcentral.js
+++ b/meshcentral.js
@@ -2537,9 +2537,10 @@ function mainStart() {
// Lowercase the auth value if present
for (var i in config.domains) { if (typeof config.domains[i].auth == 'string') { config.domains[i].auth = config.domains[i].auth.toLowerCase(); } }
- // Check if Windows SSPI and YubiKey OTP will be used
+ // Check if Windows SSPI, LDAP, Passport and YubiKey OTP will be used
var sspi = false;
var ldap = false;
+ var passport = null;
var allsspi = true;
var yubikey = false;
var recordingIndex = false;
@@ -2549,6 +2550,12 @@ function mainStart() {
for (var i in config.domains) {
if (config.domains[i].yubikey != null) { yubikey = true; }
if (config.domains[i].auth == 'ldap') { ldap = true; }
+ if ((typeof config.domains[i].authstrategies == 'object')) {
+ if (passport == null) { passport = ['passport']; }
+ if ((typeof config.domains[i].authstrategies.twitter == 'object') && (typeof config.domains[i].authstrategies.twitter.apikey == 'string') && (typeof config.domains[i].authstrategies.twitter.apisecret == 'string') && (passport.indexOf('passport-twitter') == -1)) { passport.push('passport-twitter'); }
+ if ((typeof config.domains[i].authstrategies.google == 'object') && (typeof config.domains[i].authstrategies.google.clientid == 'string') && (typeof config.domains[i].authstrategies.google.clientsecret == 'string') && (passport.indexOf('passport-google-oauth20') == -1)) { passport.push('passport-google-oauth20'); }
+ if ((typeof config.domains[i].authstrategies.github == 'object') && (typeof config.domains[i].authstrategies.github.clientid == 'string') && (typeof config.domains[i].authstrategies.github.clientsecret == 'string') && (passport.indexOf('passport-github2') == -1)) { passport.push('passport-github2'); }
+ }
if ((config.domains[i].sessionrecording != null) && (config.domains[i].sessionrecording.index == true)) { recordingIndex = true; }
}
@@ -2559,6 +2566,7 @@ function mainStart() {
var modules = ['ws', 'cbor', 'nedb', 'https', 'yauzl', 'xmldom', 'ipcheck', 'express', 'archiver', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'cookie-session', 'express-handlebars'];
if (require('os').platform() == 'win32') { modules.push('node-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
if (ldap == true) { modules.push('ldapauth-fork'); }
+ if (passport != null) { modules.push(...passport); }
if (recordingIndex == true) { modules.push('image-size'); } // Need to get the remote desktop JPEG sizes to index the recodring file.
if (config.letsencrypt != null) { if (nodeVersion < 8) { addServerWarning("Let's Encrypt support requires Node v8.x or higher.", !args.launch); } else { modules.push('acme-client'); } } // Add acme-client module
if (config.settings.mqtt != null) { modules.push('aedes'); } // Add MQTT Modules
diff --git a/public/images/Login/github32.png b/public/images/Login/github32.png
new file mode 100644
index 00000000..38eee764
Binary files /dev/null and b/public/images/Login/github32.png differ
diff --git a/public/images/Login/github64.png b/public/images/Login/github64.png
new file mode 100644
index 00000000..11c0e9d5
Binary files /dev/null and b/public/images/Login/github64.png differ
diff --git a/public/images/Login/google32.png b/public/images/Login/google32.png
new file mode 100644
index 00000000..c917a320
Binary files /dev/null and b/public/images/Login/google32.png differ
diff --git a/public/images/Login/google64.png b/public/images/Login/google64.png
new file mode 100644
index 00000000..26cdd42b
Binary files /dev/null and b/public/images/Login/google64.png differ
diff --git a/public/images/Login/twitter32.png b/public/images/Login/twitter32.png
new file mode 100644
index 00000000..972023f7
Binary files /dev/null and b/public/images/Login/twitter32.png differ
diff --git a/public/images/Login/twitter64.png b/public/images/Login/twitter64.png
new file mode 100644
index 00000000..a145ca24
Binary files /dev/null and b/public/images/Login/twitter64.png differ
diff --git a/views/login.handlebars b/views/login.handlebars
index 788d9b32..539b8e20 100644
--- a/views/login.handlebars
+++ b/views/login.handlebars
@@ -70,6 +70,13 @@
Don't have an account? Create one.
+
+
+
Log in using an existing account
+
+
+
+
@@ -302,6 +309,7 @@
var otpemail = (decodeURIComponent('{{{otpemail}}}') === 'true');
var otpsms = (decodeURIComponent('{{{otpsms}}}') === 'true');
var twoFactorCookieDays = parseInt('{{{twoFactorCookieDays}}}');
+ var authStrategies = '{{{authStrategies}}}'.split(',');
function startup() {
// Display the right server message
@@ -368,6 +376,14 @@
QV('createPanelHint', passRequirements.hint === true);
QV('resetpasswordpanelHint', passRequirements.hint === true);
+ // Setup authentication strategies
+ if (authStrategies != '') {
+ QV('authStrategies', true);
+ if (authStrategies.indexOf('twitter') >= 0) { QV('auth-twitter', true); }
+ if (authStrategies.indexOf('google') >= 0) { QV('auth-google', true); }
+ if (authStrategies.indexOf('github') >= 0) { QV('auth-github', true); }
+ }
+
// Display the welcome text
if (welcomeText) {
QH('welcomeText', welcomeText);
diff --git a/webserver.js b/webserver.js
index 696ea586..74b1dd2c 100644
--- a/webserver.js
+++ b/webserver.js
@@ -1982,8 +1982,16 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
var twoFactorCookieDays = 30;
if (typeof domain.twofactorcookiedurationdays == 'number') { twoFactorCookieDays = domain.twofactorcookiedurationdays; }
+ // See what authentication strategies we have
+ var authStrategies = [];
+ if (typeof domain.authstrategies == 'object') {
+ if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.apikey == 'string') && (typeof domain.authstrategies.twitter.apisecret == 'string')) { authStrategies.push('twitter'); }
+ if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) { authStrategies.push('google'); }
+ if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) { authStrategies.push('github'); }
+ }
+
// Render the login page
- render(req, res, getRenderPage('login', req, domain), getRenderArgs({ loginmode: loginmode, rootCertLink: getRootCertLink(), newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate, otpemail: otpemail, otpsms: otpsms, twoFactorCookieDays: twoFactorCookieDays }, req, domain));
+ render(req, res, getRenderPage('login', req, domain), getRenderArgs({ loginmode: loginmode, rootCertLink: getRootCertLink(), newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate, otpemail: otpemail, otpsms: otpsms, twoFactorCookieDays: twoFactorCookieDays, authStrategies: authStrategies.join(',') }, req, domain));
}
// Handle a post request on the root
@@ -3917,7 +3925,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
if (parent.multiServer != null) { obj.app.ws('/meshserver.ashx', function (ws, req) { parent.multiServer.CreatePeerInServer(parent.multiServer, ws, req); }); }
for (var i in parent.config.domains) {
if (parent.config.domains[i].dns != null) { continue; } // This is a subdomain with a DNS name, no added HTTP bindings needed.
- var url = parent.config.domains[i].url;
+ var domain = parent.config.domains[i];
+ var url = domain.url;
obj.app.get(url, handleRootRequest);
obj.app.post(url, handleRootPostRequest);
obj.app.get(url + 'backup.zip', handleBackupRequest);
@@ -3969,7 +3978,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
}
});
});
- if (parent.config.domains[i].agentinvitecodes == true) {
+ if (domain.agentinvitecodes == true) {
obj.app.get(url + 'invite', handleInviteRequest);
obj.app.post(url + 'invite', handleInviteRequest);
}
@@ -3979,6 +3988,74 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
obj.app.get(url + 'pluginHandler.js', obj.handlePluginJS);
}
+ // Setup passport if needed
+ if (typeof domain.authstrategies == 'object') {
+ const passport = domain.passport = require('passport');
+ if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.apikey == 'string') && (typeof domain.authstrategies.twitter.apisecret == 'string')) {
+ const TwitterStrategy = require('passport-twitter');
+ passport.use(new TwitterStrategy({
+ consumerKey: domain.authstrategies.twitter.apikey,
+ consumerSecret: domain.authstrategies.twitter.apisecret,
+ callbackURL: url + 'auth-twitter-callback'
+ },
+ function (token, tokenSecret, profile, cb) {
+ console.log('Twitter1', token, tokenSecret, profile);
+ //User.findOrCreate({ twitterId: profile.id }, function (err, user) { return cb(err, user); });
+ }
+ ));
+ obj.app.get(url + 'auth-twitter', domain.passport.authenticate('twitter'));
+ obj.app.get(url + 'https://alt.meshcentral.com',
+ domain.passport.authenticate('twitter', { failureRedirect: '/' }),
+ function (req, res) {
+ // Successful authentication, redirect home.
+ console.log('Twitter2');
+ res.redirect('/');
+ });
+ }
+ if ((typeof domain.authstrategies.google == 'object') && (typeof domain.authstrategies.google.clientid == 'string') && (typeof domain.authstrategies.google.clientsecret == 'string')) {
+ const GoogleStrategy = require('passport-google-oauth20');
+ passport.use(new GoogleStrategy({
+ clientID: domain.authstrategies.google.clientid,
+ clientSecret: domain.authstrategies.google.clientsecret,
+ callbackURL: url + 'auth-google-callback'
+ },
+ function (token, tokenSecret, profile, cb) {
+ console.log('Google1', token, tokenSecret, profile);
+ //User.findOrCreate({ googleId: profile.id }, function (err, user) { return cb(err, user); });
+ }
+ ));
+ obj.app.get(url + 'auth-google', domain.passport.authenticate('google'));
+ obj.app.get(url + 'auth-google-callback',
+ domain.passport.authenticate('google', { failureRedirect: '/' }),
+ function (req, res) {
+ // Successful authentication, redirect home.
+ console.log('Google2');
+ res.redirect('/');
+ });
+ }
+ if ((typeof domain.authstrategies.github == 'object') && (typeof domain.authstrategies.github.clientid == 'string') && (typeof domain.authstrategies.github.clientsecret == 'string')) {
+ const GitHubStrategy = require('passport-github2');
+ passport.use(new GitHubStrategy({
+ clientID: domain.authstrategies.github.clientid,
+ clientSecret: domain.authstrategies.github.clientsecret,
+ callbackURL: url + 'auth-github-callback'
+ },
+ function (token, tokenSecret, profile, cb) {
+ console.log('GitHub1', token, tokenSecret, profile);
+ //User.findOrCreate({ githubId: profile.id }, function (err, user) { return cb(err, user); });
+ }
+ ));
+ obj.app.get(url + 'auth-github', domain.passport.authenticate('github', { scope: ['user:email'] }));
+ obj.app.get(url + 'auth-github-callback',
+ domain.passport.authenticate('google', { failureRedirect: '/' }),
+ function (req, res) {
+ // Successful authentication, redirect home.
+ console.log('GitHub2');
+ res.redirect('/');
+ });
+ }
+ }
+
// Server redirects
if (parent.config.domains[i].redirects) { for (var j in parent.config.domains[i].redirects) { if (j[0] != '_') { obj.app.get(url + j, obj.handleDomainRedirect); } } }