Merge pull request #3856 from mstrhakr/generic-oidc

Feature Request: Generic OIDC
This commit is contained in:
Ylian Saint-Hilaire 2022-04-08 09:58:54 -07:00 committed by GitHub
commit a8992f6a09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 73 additions and 8 deletions

View File

@ -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": {
"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" },
"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": [ "issuer", "clientid", "clientsecret", "callbackURL" ]
}
}
}

View File

@ -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('@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; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -138,7 +138,7 @@
"footer": "Default page footer",
"newAccounts": false
},
"_domains": {
"domains": {
"": {
"_siteStyle": 2,
"title": "MyServer",
@ -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",
@ -407,6 +407,17 @@
"entityid": "meshcentral",
"idpurl": "https://server/saml2",
"cert": "saml.pem"
},
"oidc": {
"authorizationURL": "https://sso.server.com/api/oidc/authorization",
"callbackURL": "https://mesh.server.com/oidc-callback",
"clientid": "00000000-0000-0000-0000-000000000000",
"clientsecret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"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
}
}
},

View File

@ -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'; }

View File

@ -90,6 +90,7 @@
<a id="auth-github" href="auth-github" style="display:none"><img src="images/login/github32.png" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using GitHub" /></a>
<a id="auth-reddit" href="auth-reddit" style="display:none"><img src="images/login/reddit32.png" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using Reddit" /></a>
<a id="auth-azure" href="auth-azure" style="display:none"><img src="images/login/azure32.png" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using Azure" /></a>
<a id="auth-oidc" href="auth-oidc" style="display:none"><img src="images/login/oidc32.png" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using OpenID Connect" /></a>
<a id="auth-jumpcloud" href="auth-jumpcloud" style="display:none"><img src="images/login/jumpcloud32.png" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using JumpCloud" /></a>
<a id="auth-intel" href="auth-intel" style="display:none"><img src="images/login/intel32.png" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using Intel" /></a>
<a id="auth-saml" href="auth-saml" style="display:none"><img src="images/login/generic32.png" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Single Sign-in" /></a>
@ -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); }

View File

@ -82,6 +82,7 @@
<a id="auth-github" href="auth-github" style="display:none"><img src="images/login/github32.png" srcset="images/login/github64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using GitHub" /></a>
<a id="auth-reddit" href="auth-reddit" style="display:none"><img src="images/login/reddit32.png" srcset="images/login/reddit64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using Reddit" /></a>
<a id="auth-azure" href="auth-azure" style="display:none"><img src="images/login/azure32.png" srcset="images/login/azure64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using Azure" /></a>
<a id="auth-oidc" href="auth-oidc" style="display:none"><img src="images/login/oidc32.png" srcset="images/login/oidc64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using OpenID Connect" /></a>
<a id="auth-jumpcloud" href="auth-jumpcloud" style="display:none"><img src="images/login/jumpcloud32.png" srcset="images/login/jumpcloud64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using JumpCloud" /></a>
<a id="auth-intel" href="auth-intel" style="display:none"><img src="images/login/intel32.png" srcset="images/login/intel64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using Intel" /></a>
<a id="auth-saml" href="auth-saml" style="display:none"><img src="images/login/generic32.png" srcset="images/login/generic64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Single Sign-in" /></a>
@ -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); }

View File

@ -104,6 +104,7 @@
<a id="auth-github" href="auth-github" style="display:none"><img src="images/login/github32.png" srcset="images/login/github64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using GitHub" /></a>
<a id="auth-reddit" href="auth-reddit" style="display:none"><img src="images/login/reddit32.png" srcset="images/login/reddit64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using Reddit" /></a>
<a id="auth-azure" href="auth-azure" style="display:none"><img src="images/login/azure32.png" srcset="images/login/azure64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using Azure" /></a>
<a id="auth-oidc" href="auth-oidc" style="display:none"><img src="images/login/oidc32.png" srcset="images/login/oidc64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using OpenID Connect" /></a>
<a id="auth-jumpcloud" href="auth-jumpcloud" style="display:none"><img src="images/login/jumpcloud32.png" srcset="images/login/jumpcloud64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using JumpCloud" /></a>
<a id="auth-intel" href="auth-intel" style="display:none"><img src="images/login/intel32.png" srcset="images/login/intel64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Sign-in using Intel" /></a>
<a id="auth-saml" href="auth-saml" style="display:none"><img src="images/login/generic32.png" srcset="images/login/generic64.png 2x" loading="lazy" width="32" height="32" style="margin-left:3px;margin-right:3px;border-radius:3px;box-shadow:2px 2px 5px black;cursor:pointer" title="Single Sign-in" /></a>
@ -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); }

View File

@ -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,35 @@ 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);
}
));
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')) {