From 08ea9a5c8160493647727dd026b9158fce63e5e1 Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Wed, 6 Apr 2022 12:38:40 -0400 Subject: [PATCH 01/13] added oidc conf to schema --- meshcentral-config-schema.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index 3c9603a4..dc94e40b 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -1069,6 +1069,21 @@ "logouturl": {"type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."} }, "required": [ "entityid", "idpurl", "cert" ] + }, + "oidc": { + "type": "object", + "properties": { + "url": { "type": "string", "format": "uri" }, + "authorizationURL": { "type": "string", "format": "uri" }, + "tokenURL": { "type": "string", "format": "uri" }, + "userInfoURL": { "type": "string", "format": "uri" }, + "logouturl": { "type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."}, + "newAccounts": { "type": "boolean", "default": true }, + "clientid": { "type": "string" }, + "clientsecret": { "type": "string" }, + "callbackURL": { "type": "string", "format": "uri" } + }, + "required": [ "url", "authorizationURL", "tokenURL", "userInfoURL", "logouturl", "clientid", "clientsecret", "callbackURL" ] } } } From 8b29852638d023428f2f4ecfac617e55913f12be Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Wed, 6 Apr 2022 12:38:54 -0400 Subject: [PATCH 02/13] added oidc images to public --- public/images/Login/oidc32.png | Bin 0 -> 1756 bytes public/images/Login/oidc64.png | Bin 0 -> 2772 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/images/Login/oidc32.png create mode 100644 public/images/Login/oidc64.png diff --git a/public/images/Login/oidc32.png b/public/images/Login/oidc32.png new file mode 100644 index 0000000000000000000000000000000000000000..63891fb8d164f7b8392e2162a216e78a8e1a5dfa GIT binary patch literal 1756 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 akp2hIuoX^X5GrB-00001B literal 0 HcmV?d00001 From f9e92a9e04b56504c22ad884097875fedaf3eda2 Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Wed, 6 Apr 2022 12:39:13 -0400 Subject: [PATCH 03/13] added oidc lines to views --- views/default.handlebars | 1 + views/login-mobile.handlebars | 2 ++ views/login.handlebars | 2 ++ views/login2.handlebars | 2 ++ 4 files changed, 7 insertions(+) diff --git a/views/default.handlebars b/views/default.handlebars index 727b1ee3..afc88080 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -14852,6 +14852,7 @@ 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('~azure:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/azure64.png'; } + else if (shortuserid.startsWith('~oidc:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/oidc64.png'; } else if (shortuserid.startsWith('~jumpcloud:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/jumpcloud64.png'; } else if (shortuserid.startsWith('~intel:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/intel64.png'; } else if (shortuserid.startsWith('~:')) { QV('p30userAuthServiceLogo', true); Q('p30userAuthServiceLogo').src = 'images/login/generic64.png'; } diff --git a/views/login-mobile.handlebars b/views/login-mobile.handlebars index e11f9f7b..d2d1dcf7 100644 --- a/views/login-mobile.handlebars +++ b/views/login-mobile.handlebars @@ -90,6 +90,7 @@ + @@ -387,6 +388,7 @@ if (authStrategies.indexOf('github') >= 0) { QV('auth-github', true); } if (authStrategies.indexOf('reddit') >= 0) { QV('auth-reddit', true); } if (authStrategies.indexOf('azure') >= 0) { QV('auth-azure', true); } + if (authStrategies.indexOf('oidc') >= 0) { QV('auth-oidc', true); } if (authStrategies.indexOf('jumpcloud') >= 0) { QV('auth-jumpcloud', true); } if (authStrategies.indexOf('intel') >= 0) { QV('auth-intel', true); } if (authStrategies.indexOf('saml') >= 0) { QV('auth-saml', true); } diff --git a/views/login.handlebars b/views/login.handlebars index 8fedea2f..ab41e945 100644 --- a/views/login.handlebars +++ b/views/login.handlebars @@ -82,6 +82,7 @@ + @@ -408,6 +409,7 @@ if (authStrategies.indexOf('github') >= 0) { QV('auth-github', true); } if (authStrategies.indexOf('reddit') >= 0) { QV('auth-reddit', true); } if (authStrategies.indexOf('azure') >= 0) { QV('auth-azure', true); } + if (authStrategies.indexOf('oidc') >= 0) { QV('auth-oidc', true); } if (authStrategies.indexOf('jumpcloud') >= 0) { QV('auth-jumpcloud', true); } if (authStrategies.indexOf('intel') >= 0) { QV('auth-intel', true); } if (authStrategies.indexOf('saml') >= 0) { QV('auth-saml', true); } diff --git a/views/login2.handlebars b/views/login2.handlebars index 63b44c78..969db815 100644 --- a/views/login2.handlebars +++ b/views/login2.handlebars @@ -104,6 +104,7 @@ + @@ -473,6 +474,7 @@ if (authStrategies.indexOf('github') >= 0) { QV('auth-github', true); } if (authStrategies.indexOf('reddit') >= 0) { QV('auth-reddit', true); } if (authStrategies.indexOf('azure') >= 0) { QV('auth-azure', true); } + if (authStrategies.indexOf('oidc') >= 0) { QV('auth-oidc', true); } if (authStrategies.indexOf('jumpcloud') >= 0) { QV('auth-jumpcloud', true); } if (authStrategies.indexOf('intel') >= 0) { QV('auth-intel', true); } if (authStrategies.indexOf('saml') >= 0) { QV('auth-saml', true); } From 640933fc6ef1f33e298c53cb89401353a84e626b Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Wed, 6 Apr 2022 12:40:42 -0400 Subject: [PATCH 04/13] implemented passport-openidconnect used passport-openidconnect to get login 90% working, i get as far as the oidc host sending me back to mesh central with a good auth but i dont get logged in, still testing --- webserver.js | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/webserver.js b/webserver.js index 12974a6b..5acfebcf 100644 --- a/webserver.js +++ b/webserver.js @@ -783,6 +783,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (u.startsWith('~github:') && (domain.authstrategies.github != null) && (typeof domain.authstrategies.github.logouturl == 'string')) { res.redirect(domain.authstrategies.github.logouturl); return; } if (u.startsWith('~reddit:') && (domain.authstrategies.reddit != null) && (typeof domain.authstrategies.reddit.logouturl == 'string')) { res.redirect(domain.authstrategies.reddit.logouturl); return; } if (u.startsWith('~azure:') && (domain.authstrategies.azure != null) && (typeof domain.authstrategies.azure.logouturl == 'string')) { res.redirect(domain.authstrategies.azure.logouturl); return; } + if (u.startsWith('~oidc:') && (domain.authstrategies.oidc != null) && (typeof domain.authstrategies.oidc.logouturl == 'string')) { res.redirect(domain.authstrategies.oidc.logouturl); return; } if (u.startsWith('~jumpcloud:') && (domain.authstrategies.jumpcloud != null) && (typeof domain.authstrategies.jumpcloud.logouturl == 'string')) { res.redirect(domain.authstrategies.jumpcloud.logouturl); return; } if (u.startsWith('~saml:') && (domain.authstrategies.saml != null) && (typeof domain.authstrategies.saml.logouturl == 'string')) { res.redirect(domain.authstrategies.saml.logouturl); return; } if (u.startsWith('~intel:') && (domain.authstrategies.intel != null) && (typeof domain.authstrategies.intel.logouturl == 'string')) { res.redirect(domain.authstrategies.intel.logouturl); return; } @@ -3008,6 +3009,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF if (typeof domain.authstrategies.github == 'object') { authStrategies.push('github'); } if (typeof domain.authstrategies.reddit == 'object') { authStrategies.push('reddit'); } if (typeof domain.authstrategies.azure == 'object') { authStrategies.push('azure'); } + if (typeof domain.authstrategies.oidc == 'object') { authStrategies.push('oidc'); } if (typeof domain.authstrategies.intel == 'object') { authStrategies.push('intel'); } if (typeof domain.authstrategies.jumpcloud == 'object') { authStrategies.push('jumpcloud'); } if (typeof domain.authstrategies.saml == 'object') { authStrategies.push('saml'); } @@ -6239,6 +6241,82 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF }, handleStrategyLogin); } + + // passport-openidconnect example code +/* var OpenIDConnectStrategy = require('passport-openidconnect'); + + passport.use(new OpenIDConnectStrategy({ + issuer: 'https://server.example.com', + authorizationURL: 'https://server.example.com/authorize', + tokenURL: 'https://server.example.com/token', + userInfoURL: 'https://server.example.com/userinfo', + clientID: process.env['CLIENT_ID'], + clientSecret: process.env['CLIENT_SECRET'], + callbackURL: 'https://client.example.org/cb' + + )); */ + // 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 email profile' ], + state: true + }; + const OIDCStrategy = require('passport-openidconnect'); + 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('oidc-' + domain.id, new OIDCStrategy(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', 'OpenID Connect profile: ' + JSON.stringify(userex)); + var user = null; + if (userex != null) { + var user = { sid: '~oidc:' + userex.unique_name, name: userex.name, strategy: 'oidc' }; + if (typeof userex.email == 'string') { user.email = userex.email; } + } + return done(null, user); + } + )); +/* passport.use('oidc-' + domain.id, new OIDCStrategy.Strategy(options, + function (authorization_code, refresh_token, profile, cb) { + parent.debug('web', 'OIDC profile: ' + JSON.stringify(profile)); + var user = { sid: '~oidc:' + profile.id, name: profile.displayName, strategy: 'oidc' }; + 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); + } + )); */ + obj.app.get(url + 'auth-oidc', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + domain.passport.authenticate('oidc-' + domain.id, { scope: 'openid email profile', state: obj.parent.encodeCookie({ 'p': 'azure' }, obj.parent.loginCookieEncryptionKey) })(req, res, next); + }); + obj.app.get(url + 'oidc-callback', function (req, res, next) { + var domain = getDomain(req); + if (domain.passport == null) { next(); return; } + 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 != null) { + var c = obj.parent.decodeCookie(req.query.state, obj.parent.loginCookieEncryptionKey, 10); // 10 minute timeout + if ((c != null) && (c.p == 'oidc')) { domain.passport.authenticate('oidc-' + domain.id, { failureRedirect: '/' })(req, res, next); return; } + } + next(); + } + }, handleStrategyLogin); + } + + // Generic SAML if (typeof domain.authstrategies.saml == 'object') { if ((typeof domain.authstrategies.saml.cert != 'string') || (typeof domain.authstrategies.saml.idpurl != 'string')) { From 191285c4d2b96795333d3d3328564d55b48141ae Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Wed, 6 Apr 2022 12:41:15 -0400 Subject: [PATCH 05/13] added oidc check --- meshcentral.js | 1 + 1 file changed, 1 insertion(+) diff --git a/meshcentral.js b/meshcentral.js index f69e0faf..2ea3897c 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -3495,6 +3495,7 @@ function mainStart() { 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 ((typeof config.domains[i].authstrategies.reddit == 'object') && (typeof config.domains[i].authstrategies.reddit.clientid == 'string') && (typeof config.domains[i].authstrategies.reddit.clientsecret == 'string') && (passport.indexOf('passport-reddit') == -1)) { passport.push('passport-reddit'); } if ((typeof config.domains[i].authstrategies.azure == 'object') && (typeof config.domains[i].authstrategies.azure.clientid == 'string') && (typeof config.domains[i].authstrategies.azure.clientsecret == 'string') && (typeof config.domains[i].authstrategies.azure.tenantid == 'string') && (passport.indexOf('passport-azure-oauth2') == -1)) { passport.push('passport-azure-oauth2'); passport.push('jwt-simple'); } + if ((typeof config.domains[i].authstrategies.oidc == 'object') && (typeof config.domains[i].authstrategies.oidc.clientid == 'string') && (typeof config.domains[i].authstrategies.oidc.clientsecret == 'string') && (passport.indexOf('passport-openidconnect') == -1)) { passport.push('passport-openidconnect'); } if ((typeof config.domains[i].authstrategies.saml == 'object') || (typeof config.domains[i].authstrategies.jumpcloud == 'object')) { passport.push('passport-saml'); } } if (config.domains[i].sessionrecording != null) { sessionRecording = true; } From 48a68197b2007076130bc5bf9dd9123c3ba79f3d Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Wed, 6 Apr 2022 12:41:56 -0400 Subject: [PATCH 06/13] added oidc section also seems to be some kind of formatting change causing multiple other changes --- sample-config-advanced.json | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/sample-config-advanced.json b/sample-config-advanced.json index 34693586..78fb4d55 100644 --- a/sample-config-advanced.json +++ b/sample-config-advanced.json @@ -250,21 +250,21 @@ "files": "{0} started a remote files session." }, "_agentCustomization": { - "displayName": "Compagny® Product™", - "description": "Compagny® Product™ agent for remote monitoring, management and assistance.", + "displayName": "Compagny� Product�", + "description": "Compagny� Product� agent for remote monitoring, management and assistance.", "companyName": "Compagny", "serviceName": "compagnyagent", "image": "agent-logo.png", "fileName": "compagnyagent" }, "_assistantCustomization": { - "title": "Compagny® Product™", + "title": "Compagny� Product�", "image": "assistant-logo.png", "fileName": "compagny" }, "_androidCustomization": { - "title": "Compagny® Product™", - "subtitle": "Product Subtitle™", + "title": "Compagny� Product�", + "subtitle": "Product Subtitle�", "image": "assistant-logo.png" }, "_userAllowedIP": "127.0.0.1,192.168.1.0/24", @@ -407,6 +407,17 @@ "entityid": "meshcentral", "idpurl": "https://server/saml2", "cert": "saml.pem" + }, + "oidc": { + "url": "https://server/openidconnect-callback", + "authorizationURL": "https://server/api/oidc/authorization", + "tokenURL": "https://server/api/oidc/token", + "userInfoURL": "https://server/api/oidc/userinfo", + "logouturl": "https://server/logout", + "newAccounts": true, + "clientid": "00000000-0000-0000-0000-000000000000", + "clientsecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "callbackURL": "https://server/oidc-callback" } } }, From 126c1474cc25c158b4201a0719c3578daf8e0a66 Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Fri, 8 Apr 2022 00:14:58 -0400 Subject: [PATCH 07/13] working generic oidc section tested with authelia, works for me :) --- webserver.js | 65 ++++++++-------------------------------------------- 1 file changed, 9 insertions(+), 56 deletions(-) diff --git a/webserver.js b/webserver.js index 5acfebcf..55e4aaa9 100644 --- a/webserver.js +++ b/webserver.js @@ -6241,20 +6241,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF }, handleStrategyLogin); } - - // passport-openidconnect example code -/* var OpenIDConnectStrategy = require('passport-openidconnect'); - - passport.use(new OpenIDConnectStrategy({ - issuer: 'https://server.example.com', - authorizationURL: 'https://server.example.com/authorize', - tokenURL: 'https://server.example.com/token', - userInfoURL: 'https://server.example.com/userinfo', - clientID: process.env['CLIENT_ID'], - clientSecret: process.env['CLIENT_SECRET'], - callbackURL: 'https://client.example.org/cb' - - )); */ // 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 = { @@ -6265,55 +6251,22 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF issuer: domain.authstrategies.oidc.issuer, tokenURL: domain.authstrategies.oidc.tokenurl, userInfoURL: domain.authstrategies.oidc.userinfourl, - scope: [ 'openid email profile' ], + scope: [ 'openid profile email' ], + responseMode: 'form_post' , state: true }; const OIDCStrategy = require('passport-openidconnect'); 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('oidc-' + domain.id, new OIDCStrategy(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', 'OpenID Connect profile: ' + JSON.stringify(userex)); - var user = null; - if (userex != null) { - var user = { sid: '~oidc:' + userex.unique_name, name: userex.name, strategy: 'oidc' }; - if (typeof userex.email == 'string') { user.email = userex.email; } - } - return done(null, user); - } - )); -/* passport.use('oidc-' + domain.id, new OIDCStrategy.Strategy(options, - function (authorization_code, refresh_token, profile, cb) { - parent.debug('web', 'OIDC profile: ' + JSON.stringify(profile)); - var user = { sid: '~oidc:' + profile.id, name: profile.displayName, strategy: 'oidc' }; - if ((typeof profile.emails == 'object') && (profile.emails[0] != null) && (typeof profile.emails[0].value == 'string')) { user.email = profile.emails[0].value; } + 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); } - )); */ - obj.app.get(url + 'auth-oidc', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - domain.passport.authenticate('oidc-' + domain.id, { scope: 'openid email profile', state: obj.parent.encodeCookie({ 'p': 'azure' }, obj.parent.loginCookieEncryptionKey) })(req, res, next); - }); - obj.app.get(url + 'oidc-callback', function (req, res, next) { - var domain = getDomain(req); - if (domain.passport == null) { next(); return; } - 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 != null) { - var c = obj.parent.decodeCookie(req.query.state, obj.parent.loginCookieEncryptionKey, 10); // 10 minute timeout - if ((c != null) && (c.p == 'oidc')) { domain.passport.authenticate('oidc-' + domain.id, { failureRedirect: '/' })(req, res, next); return; } - } - next(); - } - }, handleStrategyLogin); + )); + 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); } From 931adff892a67c79aea6d67e381d2abba92be43b Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Fri, 8 Apr 2022 00:15:17 -0400 Subject: [PATCH 08/13] change url to issuer --- meshcentral-config-schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index dc94e40b..104f89c0 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -1073,7 +1073,7 @@ "oidc": { "type": "object", "properties": { - "url": { "type": "string", "format": "uri" }, + "issuer": { "type": "string", "format": "uri" }, "authorizationURL": { "type": "string", "format": "uri" }, "tokenURL": { "type": "string", "format": "uri" }, "userInfoURL": { "type": "string", "format": "uri" }, From 4eefe1531c4f15e84c86a51c6002d85178753c50 Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Fri, 8 Apr 2022 00:15:53 -0400 Subject: [PATCH 09/13] reorganized example config --- sample-config-advanced.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sample-config-advanced.json b/sample-config-advanced.json index 78fb4d55..bd457505 100644 --- a/sample-config-advanced.json +++ b/sample-config-advanced.json @@ -138,7 +138,7 @@ "footer": "Default page footer", "newAccounts": false }, - "_domains": { + "domains": { "": { "_siteStyle": 2, "title": "MyServer", @@ -409,15 +409,15 @@ "cert": "saml.pem" }, "oidc": { - "url": "https://server/openidconnect-callback", - "authorizationURL": "https://server/api/oidc/authorization", - "tokenURL": "https://server/api/oidc/token", - "userInfoURL": "https://server/api/oidc/userinfo", - "logouturl": "https://server/logout", - "newAccounts": true, + "authorizationURL": "https://sso.server.com/api/oidc/authorization", + "callbackURL": "https://mesh.server.com/oidc-callback", "clientid": "00000000-0000-0000-0000-000000000000", "clientsecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - "callbackURL": "https://server/oidc-callback" + "issuer": "https://sso.server.com", + "tokenURL": "https://sso.server.com/api/oidc/token", + "userInfoURL": "https://sso.server.com/api/oidc/userinfo", + "logoutURL": "https://sso.server.com/logout", + "newAccounts": true } } }, From 149573a87857b1d67bbbfc893e4777c30f1d7e38 Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Fri, 8 Apr 2022 11:38:55 -0400 Subject: [PATCH 10/13] swapped to working passport oidc module --- meshcentral.js | 2 +- webserver.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meshcentral.js b/meshcentral.js index 2ea3897c..812246e7 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -3495,7 +3495,7 @@ function mainStart() { 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 ((typeof config.domains[i].authstrategies.reddit == 'object') && (typeof config.domains[i].authstrategies.reddit.clientid == 'string') && (typeof config.domains[i].authstrategies.reddit.clientsecret == 'string') && (passport.indexOf('passport-reddit') == -1)) { passport.push('passport-reddit'); } if ((typeof config.domains[i].authstrategies.azure == 'object') && (typeof config.domains[i].authstrategies.azure.clientid == 'string') && (typeof config.domains[i].authstrategies.azure.clientsecret == 'string') && (typeof config.domains[i].authstrategies.azure.tenantid == 'string') && (passport.indexOf('passport-azure-oauth2') == -1)) { passport.push('passport-azure-oauth2'); passport.push('jwt-simple'); } - if ((typeof config.domains[i].authstrategies.oidc == 'object') && (typeof config.domains[i].authstrategies.oidc.clientid == 'string') && (typeof config.domains[i].authstrategies.oidc.clientsecret == 'string') && (passport.indexOf('passport-openidconnect') == -1)) { passport.push('passport-openidconnect'); } + if ((typeof config.domains[i].authstrategies.oidc == 'object') && (typeof config.domains[i].authstrategies.oidc.clientid == 'string') && (typeof config.domains[i].authstrategies.oidc.clientsecret == 'string') && (passport.indexOf('passport-generic-oidc') == -1)) { passport.push('passport-generic-oidc'); } if ((typeof config.domains[i].authstrategies.saml == 'object') || (typeof config.domains[i].authstrategies.jumpcloud == 'object')) { passport.push('passport-saml'); } } if (config.domains[i].sessionrecording != null) { sessionRecording = true; } diff --git a/webserver.js b/webserver.js index 55e4aaa9..c5f2cf87 100644 --- a/webserver.js +++ b/webserver.js @@ -6255,7 +6255,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF responseMode: 'form_post' , state: true }; - const OIDCStrategy = require('passport-openidconnect'); + const OIDCStrategy = require('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, From ba82a005f4475ed20e293f0a7478d61661a17e86 Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Fri, 8 Apr 2022 11:55:54 -0400 Subject: [PATCH 11/13] update oidc npm module --- meshcentral.js | 2 +- webserver.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/meshcentral.js b/meshcentral.js index 812246e7..2c5179b6 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -3495,7 +3495,7 @@ function mainStart() { 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 ((typeof config.domains[i].authstrategies.reddit == 'object') && (typeof config.domains[i].authstrategies.reddit.clientid == 'string') && (typeof config.domains[i].authstrategies.reddit.clientsecret == 'string') && (passport.indexOf('passport-reddit') == -1)) { passport.push('passport-reddit'); } if ((typeof config.domains[i].authstrategies.azure == 'object') && (typeof config.domains[i].authstrategies.azure.clientid == 'string') && (typeof config.domains[i].authstrategies.azure.clientsecret == 'string') && (typeof config.domains[i].authstrategies.azure.tenantid == 'string') && (passport.indexOf('passport-azure-oauth2') == -1)) { passport.push('passport-azure-oauth2'); passport.push('jwt-simple'); } - if ((typeof config.domains[i].authstrategies.oidc == 'object') && (typeof config.domains[i].authstrategies.oidc.clientid == 'string') && (typeof config.domains[i].authstrategies.oidc.clientsecret == 'string') && (passport.indexOf('passport-generic-oidc') == -1)) { passport.push('passport-generic-oidc'); } + if ((typeof config.domains[i].authstrategies.oidc == 'object') && (typeof config.domains[i].authstrategies.oidc.clientid == 'string') && (typeof config.domains[i].authstrategies.oidc.clientsecret == 'string') && (passport.indexOf('@mstrhakr/passport-generic-oidc') == -1)) { passport.push('@mstrhakr/passport-generic-oidc'); } if ((typeof config.domains[i].authstrategies.saml == 'object') || (typeof config.domains[i].authstrategies.jumpcloud == 'object')) { passport.push('passport-saml'); } } if (config.domains[i].sessionrecording != null) { sessionRecording = true; } diff --git a/webserver.js b/webserver.js index c5f2cf87..8c4393c8 100644 --- a/webserver.js +++ b/webserver.js @@ -6255,7 +6255,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF responseMode: 'form_post' , state: true }; - const OIDCStrategy = require('passport-generic-oidc'); + 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, From 8e0e72ec185b7c2f4053a699dad24b88d5bcb388 Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:00:10 -0400 Subject: [PATCH 12/13] fixed typos and missing special chars --- sample-config-advanced.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sample-config-advanced.json b/sample-config-advanced.json index bd457505..0d9df467 100644 --- a/sample-config-advanced.json +++ b/sample-config-advanced.json @@ -250,21 +250,21 @@ "files": "{0} started a remote files session." }, "_agentCustomization": { - "displayName": "Compagny� Product�", - "description": "Compagny� Product� agent for remote monitoring, management and assistance.", - "companyName": "Compagny", - "serviceName": "compagnyagent", + "displayName": "Company® Productâ„¢", + "description": "Company® Productâ„¢ agent for remote monitoring, management and assistance.", + "companyName": "Company®", + "serviceName": "companyagent", "image": "agent-logo.png", "fileName": "compagnyagent" }, "_assistantCustomization": { - "title": "Compagny� Product�", + "title": "Company® Productâ„¢", "image": "assistant-logo.png", "fileName": "compagny" }, "_androidCustomization": { - "title": "Compagny� Product�", - "subtitle": "Product Subtitle�", + "title": "Company® Productâ„¢", + "subtitle": "Product Subtitleâ„¢", "image": "assistant-logo.png" }, "_userAllowedIP": "127.0.0.1,192.168.1.0/24", From 4315950d73658f01f9db25e3897f881df3f6b739 Mon Sep 17 00:00:00 2001 From: mstrhakr <37352843+mstrhakr@users.noreply.github.com> Date: Fri, 8 Apr 2022 12:09:07 -0400 Subject: [PATCH 13/13] reordered and added descriptions --- meshcentral-config-schema.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/meshcentral-config-schema.json b/meshcentral-config-schema.json index 104f89c0..429d4d91 100644 --- a/meshcentral-config-schema.json +++ b/meshcentral-config-schema.json @@ -1073,17 +1073,17 @@ "oidc": { "type": "object", "properties": { - "issuer": { "type": "string", "format": "uri" }, - "authorizationURL": { "type": "string", "format": "uri" }, - "tokenURL": { "type": "string", "format": "uri" }, - "userInfoURL": { "type": "string", "format": "uri" }, - "logouturl": { "type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link."}, - "newAccounts": { "type": "boolean", "default": true }, + "authorizationURL": { "type": "string", "format": "uri", "description": "If set, this will be used as the authorization URL. (If set tokenURL and userInfoURL need set also)" }, + "callbackURL": { "type": "string", "format": "uri", "description": "Required, this is the URL that your SSO provider sends auth approval to." }, "clientid": { "type": "string" }, "clientsecret": { "type": "string" }, - "callbackURL": { "type": "string", "format": "uri" } + "issuer": { "type": "string", "format": "uri", "description": "Full URL of SSO portal" }, + "tokenURL": { "type": "string", "format": "uri", "description": "If set, this will be used as the token URL. (If set authorizationURL and userInfoURL need set also)" }, + "userInfoURL": { "type": "string", "format": "uri", "description": "If set, this will be used as the user info URL. (If set authorizationURL and tokenURL need set also)" }, + "logouturl": { "type": "string", "format": "uri", "description": "Then set, the user will be redirected to this URL when hitting the logout link." }, + "newAccounts": { "type": "boolean", "default": true } }, - "required": [ "url", "authorizationURL", "tokenURL", "userInfoURL", "logouturl", "clientid", "clientsecret", "callbackURL" ] + "required": [ "issuer", "clientid", "clientsecret", "callbackURL" ] } } }