diff --git a/public/styles/style.css b/public/styles/style.css index 1e571a3c..697f5fde 100644 --- a/public/styles/style.css +++ b/public/styles/style.css @@ -803,6 +803,21 @@ NoMeshesPanel img { background-color:#44F; } +.userAuthStrategyLogo { + text-align:center; + position:absolute; + right:20px; + top:140px; + width:64px; + height:64px; + color:#FFF; + padding:2px; + background-color:#FFF; + border-radius:20px; + box-shadow: 2px 2px 10px black; + z-index:1; +} + #xdevices { max-height: calc(100vh - 242px); overflow-y: auto; diff --git a/sample-config.json b/sample-config.json index a954f780..9605c233 100644 --- a/sample-config.json +++ b/sample-config.json @@ -157,6 +157,29 @@ "_maxRecordingSizeMegabytes": 3, "__protocols__": "Is an array: 1 = Terminal, 2 = Desktop, 5 = Files, 100 = Intel AMT WSMAN, 101 = Intel AMT Redirection", "protocols": [ 1, 2, 101 ] + }, + "_authStrategies": { + "__comment__" : "This section is used to allow users to login using other accounts. You will need to get an API key from the services and register callback URL's", + "twitter": { + "__callbackurl": "https://server/auth-twitter-callback", + "apikey": "xxxxxxxxxxxxxxxxxxxxxxx", + "apisecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + "google": { + "__callbackurl": "https://server/auth-google-callback", + "clientid": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com", + "clientsecret": "xxxxxxxxxxxxxxxxxxxxxxx" + }, + "github": { + "__callbackurl": "https://server/auth-github-callback", + "clientid": "xxxxxxxxxxxxxxxxxxxxxxx", + "clientsecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + }, + "reddit": { + "__callbackurl": "https://server/auth-reddit-callback", + "clientid": "xxxxxxxxxxxxxxxxxxxxxxx", + "clientsecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + } } }, "_customer1": { diff --git a/views/default.handlebars b/views/default.handlebars index d26b59d0..c4f32683 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -885,7 +885,8 @@
- + + @@ -9928,9 +9929,9 @@ if ((users == null) || ((features & 4) != 0)) { QH('p3users', ''); return; } // Sort the list of user id's - var sortedUserIds = [], maxUsers = 100, hiddenUsers = 0; - for (var i in users) { sortedUserIds.push(i); } - sortedUserIds.sort(); + var sortedUsers = [], maxUsers = 100, hiddenUsers = 0; + for (var i in users) { sortedUsers.push(users[i]); } + sortedUsers.sort(nameSort); // Get search var userSearch = Q('UserSearchInput').value.toLowerCase(); @@ -9949,8 +9950,8 @@ for (var i=0;i= 0)) || @@ -9967,8 +9968,8 @@ } addHeader = true; // Offline users - for (var i in sortedUserIds) { - var user = users[sortedUserIds[i]], sessions = null; + for (var i in sortedUsers) { + var user = sortedUsers[i], sessions = null; if (wssessions != null) { sessions = wssessions[user._id]; } if ((sessions == null) && ((userSearch != null) && ((userSearch == '') || (user.name.toLowerCase().indexOf(userSearch) >= 0)) || @@ -10859,6 +10860,15 @@ Q('MainUserImage').classList.remove('gray'); if (activeSessions == 0) { Q('MainUserImage').classList.add('gray'); } + // Add user auth strategy + var shortuserid = user._id.split('/')[2]; + if (shortuserid.startsWith('~twitter:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/twitter64.png';; } + else if (shortuserid.startsWith('~google:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/google64.png';; } + else if (shortuserid.startsWith('~github:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/github64.png';; } + else if (shortuserid.startsWith('~reddit:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/reddit64.png';; } + else if (shortuserid.startsWith('~intel:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/intel64.png';; } + else { QV('p30userAuthServiceLogo', false); } + // Server permissions var msg = [], premsg = ''; if ((user.siteadmin != null) && ((user.siteadmin & 32) != 0) && (user.siteadmin != 0xFFFFFFFF)) { premsg = ' '; msg.push("Locked account"); } @@ -11979,7 +11989,7 @@ if ((xxcurrentView == 11) && (desktop != null) && (desktop.m.recordedData != null)) { deskRecordSession(); } // If we are trying to go to "My Users" and we are not a user manager, move to recordings - if ((x == 4) && (users == null) || ((features & 4) != 0)) { x = 52; } + if (((x == 4) && ((userinfo.siteadmin & 2) == 0)) || ((features & 4) != 0)) { x = 52; } // Edit this line when adding a new screen for (var i = 0; i < 53; i++) { QV('p' + i, i == x); } diff --git a/webserver.js b/webserver.js index 11311345..47c4730e 100644 --- a/webserver.js +++ b/webserver.js @@ -4043,6 +4043,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { passport.serializeUser(function (user, done) { done(null, user.id); }); passport.deserializeUser(function (id, done) { done(null, { id: id }); }); obj.app.use(passport.initialize()); + //obj.app.use(passport.session()); // Twitter if ((typeof domain.authstrategies.twitter == 'object') && (typeof domain.authstrategies.twitter.apikey == 'string') && (typeof domain.authstrategies.twitter.apisecret == 'string')) { @@ -4055,7 +4056,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { } )); obj.app.get(url + 'auth-twitter', domain.passport.authenticate('twitter')); - obj.app.get(url + 'auth-twitter-callback', domain.passport.authenticate('twitter', { failureRedirect: '/' }), handleStrategyLogin); + obj.app.get(url + 'auth-twitter-callback', function (req, res, next) { + if ((Object.keys(req.session).length == 0) && (req.query.nmr == null)) { + // This is an empty session likely due to the 302 redirection, redirect again (this is a bit of a hack). + var url = req.url; + if (url.indexOf('?') >= 0) { url += '&nmr=1'; } else { url += '?nmr=1'; } // Add this to the URL to prevent redirect loop. + res.set('Content-Type', 'text/html'); + res.end(''); + } else { + domain.passport.authenticate('twitter', { failureRedirect: '/' })(req, res, next); + } + }, handleStrategyLogin); } // Google @@ -4096,19 +4107,27 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { return cb(null, user); } )); - obj.app.get(url + 'auth-reddit', function(req, res, next) { - domain.passport.authenticate('reddit', { state: 'rcookie', duration: 'permanent' })(req, res, next); // TODO: Replace 'rcookie' with a time-limited cookie + obj.app.get(url + 'auth-reddit', function (req, res, next) { + req.session.rstate = obj.crypto.randomBytes(32).toString('hex'); + domain.passport.authenticate('reddit', { state: req.session.rstate, duration: 'permanent' })(req, res, next); // TODO: Replace 'rcookie' with a time-limited cookie }); - obj.app.get(url + 'auth-reddit-callback', - function(req, res, next) { - if (req.query.state == 'rcookie') { + obj.app.get(url + 'auth-reddit-callback', function (req, res, next) { + if ((Object.keys(req.session).length == 0) && (req.query.nmr == null)) { + // This is an empty session likely due to the 302 redirection, redirect again (this is a bit of a hack). + var url = req.url; + if (url.indexOf('?') >= 0) { url += '&nmr=1'; } else { url += '?nmr=1'; } // Add this to the URL to prevent redirect loop. + res.set('Content-Type', 'text/html'); + res.end(''); + } else { + if (req.query.state == req.session.rstate) { delete req.session.rstate; domain.passport.authenticate('reddit', { failureRedirect: '/' })(req, res, next); } else { delete req.session.rstate; next(new Error(403)); } - }, handleStrategyLogin); + } + }, handleStrategyLogin); } }