diff --git a/.gitignore b/.gitignore index 148cd043..883f117d 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ config.yml # Test results test-results/ + +# VS Code Local History extension +.history diff --git a/config.sample.yml b/config.sample.yml index 62e1a5c7..baa61dc6 100644 --- a/config.sample.yml +++ b/config.sample.yml @@ -103,7 +103,16 @@ auth: clientSecret: OAUTH2_CLIENT_SECRET authorizationURL: OAUTH2_AUTH_URL tokenURL: OAUTH2_TOKEN_URL - + oidc: + enabled: false + clientId: OPENID_CONNECT_CLIENT_ID + clientSecret: OPENID_CONNECT_CLIENT_SECRET + issuer: OPENID_CONNECT_ISSUER + userInfoUrl: OPENID_CONNECT_USER_INFO_URL + authorizationURL: OPENID_CONNECT_AUTHORIZATION_URL + tokenURL: OPENID_CONNECT_TOKEN_URL + emailClaim: OPENID_CONNECT_EMAIL_CLAIM_PATH + usernameClaim: OPENID_CONNECT_USERNAME_CLAIM_PATH # --------------------------------------------------------------------- # Secret key to use when encrypting sessions # --------------------------------------------------------------------- diff --git a/package.json b/package.json index cc018ffd..cb8e380b 100644 --- a/package.json +++ b/package.json @@ -103,6 +103,7 @@ "passport-google-oauth20": "~1.0.0", "passport-ldapauth": "~2.0.0", "passport-local": "~1.0.0", + "passport-openidconnect": "~0.0.2", "passport-slack": "0.0.7", "passport-windowslive": "~1.0.2", "passport.socketio": "~3.7.0", diff --git a/server/controllers/auth.js b/server/controllers/auth.js index 463fd9a1..c33937fc 100644 --- a/server/controllers/auth.js +++ b/server/controllers/auth.js @@ -98,6 +98,7 @@ router.get('/login/github', passport.authenticate('github', { scope: ['user:emai router.get('/login/slack', passport.authenticate('slack', { scope: ['identity.basic', 'identity.email'] })) router.get('/login/azure', passport.authenticate('azure_ad_oauth2')) router.get('/login/oauth2', passport.authenticate('oauth2')) +router.get('/login/oidc', passport.authenticate('oidc')) router.get('/login/ms/callback', passport.authenticate('windowslive', { failureRedirect: '/login', successRedirect: '/' })) router.get('/login/google/callback', passport.authenticate('google', { failureRedirect: '/login', successRedirect: '/' })) @@ -106,6 +107,7 @@ router.get('/login/github/callback', passport.authenticate('github', { failureRe router.get('/login/slack/callback', passport.authenticate('slack', { failureRedirect: '/login', successRedirect: '/' })) router.get('/login/azure/callback', passport.authenticate('azure_ad_oauth2', { failureRedirect: '/login', successRedirect: '/' })) router.get('/login/oauth2/callback', passport.authenticate('oauth2', { failureRedirect: '/login', successRedirect: '/' })) +router.get('/login/oidc/callback', passport.authenticate('oidc', { failureRedirect: '/login', successRedirect: '/' })) /** * Logout diff --git a/server/libs/auth.js b/server/libs/auth.js index 5f3e7029..588b6c4f 100644 --- a/server/libs/auth.js +++ b/server/libs/auth.js @@ -3,6 +3,7 @@ /* global appconfig, appdata, db, lang, winston */ const fs = require('fs') +const _ = require('lodash') module.exports = function (passport) { // Serialization user methods @@ -226,6 +227,33 @@ module.exports = function (passport) { )) } + // OpenID Connect + + if (appconfig.auth.oidc && appconfig.auth.oidc.enabled) { + const OIDCStrategy = require('passport-openidconnect').Strategy + passport.use('oidc', new OIDCStrategy({ + userInfoURL: appconfig.auth.oidc.userInfoUrl, + authorizationURL: appconfig.auth.oidc.authorizationURL, + tokenURL: appconfig.auth.oidc.tokenURL, + clientID: appconfig.auth.oidc.clientId, + clientSecret: appconfig.auth.oidc.clientSecret, + issuer: appconfig.auth.oidc.issuer, + callbackURL: appconfig.host + '/login/oidc/callback' + }, (iss, sub, profile, jwtClaims, accessToken, refreshToken, params, cb) => { + db.User.processProfile({ + id: jwtClaims.sub, + provider: 'oidc', + email: _.get(jwtClaims, appconfig.auth.oidc.emailClaim), + name: _.get(jwtClaims, appconfig.auth.oidc.usernameClaim) + }).then((user) => { + return cb(null, user) || true + }).catch((err) => { + return cb(err, null) || true + }) + } + )) + } + // Create users for first-time db.onReady.then(() => { diff --git a/server/locales/en/auth.json b/server/locales/en/auth.json index cc01ded2..e0bc6fbb 100644 --- a/server/locales/en/auth.json +++ b/server/locales/en/auth.json @@ -28,6 +28,7 @@ "github": "GitHub", "slack": "Slack", "ldap": "LDAP / Active Directory", - "oauth2": "OAuth2" + "oauth2": "OAuth2", + "oidc": "OpenID Connect" } } diff --git a/server/views/auth/login.pug b/server/views/auth/login.pug index d758407d..f2807204 100644 --- a/server/views/auth/login.pug +++ b/server/views/auth/login.pug @@ -72,6 +72,10 @@ html(data-logic='login') button.slack(onclick='window.location.assign("/login/oauth2")') i.icon-box span= t('auth:providers.oauth2') + if appconfig.auth.oidc && appconfig.auth.oidc.enabled + button.slack(onclick='window.location.assign("/login/oidc")') + i.icon-box + span= t('auth:providers.oidc') #copyright = t('footer.poweredby') + ' ' a.icon(href='https://github.com/Requarks/wiki') diff --git a/yarn.lock b/yarn.lock index ceae2c2c..d66d2dc0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -217,6 +217,15 @@ ajv@^4.7.0, ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + ajv@^5.2.0: version "5.2.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.2.tgz#47c68d69e86f5d953103b0074a9430dc63da5e39" @@ -463,10 +472,18 @@ aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + aws4@^1.2.1: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" +aws4@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" + axios@~0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.16.2.tgz#ba4f92f17167dfbab40983785454b9ac149c3c6d" @@ -1508,6 +1525,12 @@ colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" +combined-stream@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" @@ -2520,6 +2543,10 @@ extend@^3.0.0, extend@~3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" +extend@~3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + external-editor@^2.0.1, external-editor@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972" @@ -2566,6 +2593,10 @@ fast-future@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/fast-future/-/fast-future-1.0.2.tgz#8435a9aaa02d79248d17d704e76259301d99280a" +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -2755,6 +2786,14 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" +form-data@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + dependencies: + asynckit "^0.4.0" + combined-stream "1.0.6" + mime-types "^2.1.12" + forwarded@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" @@ -3073,6 +3112,10 @@ har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + har-validator@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" @@ -3080,6 +3123,13 @@ har-validator@~4.2.1: ajv "^4.9.1" har-schema "^1.0.5" +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -3217,6 +3267,14 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + i18next-express-middleware@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/i18next-express-middleware/-/i18next-express-middleware-1.0.5.tgz#12dce7c553866e11c108943d46ce494baf982219" @@ -4657,6 +4715,10 @@ mime-db@~1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" +mime-db@~1.35.0: + version "1.35.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" + mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.6, mime-types@~2.1.7: version "2.1.15" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" @@ -4669,6 +4731,12 @@ mime-types@~2.1.16: dependencies: mime-db "~1.29.0" +mime-types@~2.1.17: + version "2.1.19" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" + dependencies: + mime-db "~1.35.0" + mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" @@ -5110,7 +5178,7 @@ number-is-nan@^1.0.0: version "1.4.1" resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.1.tgz#7ae9b07b0ea804db7e25f05cb5fe4097d4e4949f" -oauth-sign@~0.8.1: +oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -5426,6 +5494,15 @@ passport-oauth@~0.1.1: passport "~0.1.1" pkginfo "0.2.x" +passport-openidconnect@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/passport-openidconnect/-/passport-openidconnect-0.0.2.tgz#e488f8bdb386c9a9fd39c91d5ab8c880156e8153" + dependencies: + oauth "0.9.x" + passport-strategy "1.x.x" + request "^2.75.0" + webfinger "0.4.x" + passport-slack@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/passport-slack/-/passport-slack-0.0.7.tgz#167eb80f0ab622d2156e7cae7055e16d0b1890d0" @@ -5521,6 +5598,10 @@ performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + pidusage@^1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-1.1.5.tgz#b8c8d32bdfaf36212ca9e741028876ea33217e66" @@ -5928,6 +6009,10 @@ qs@6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.0.tgz#8d04954d364def3efc55b5a0793e1e2c8b1e6e49" +qs@~6.5.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + random-bytes@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" @@ -6204,6 +6289,31 @@ request@2, request@^2.65.0, request@^2.67.0, request@^2.79.0, request@^2.81.0, r tunnel-agent "^0.6.0" uuid "^3.0.0" +request@^2.75.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -6322,7 +6432,7 @@ sass-graph@^2.1.1: scss-tokenizer "^0.2.3" yargs "^7.0.0" -sax@>=0.6.0, sax@^1.2.1: +sax@>=0.1.1, sax@>=0.6.0, sax@^1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -6713,6 +6823,10 @@ stdout-stream@^1.4.0: dependencies: readable-stream "^2.0.1" +step@0.0.x: + version "0.0.6" + resolved "https://registry.yarnpkg.com/step/-/step-0.0.6.tgz#143e7849a5d7d3f4a088fe29af94915216eeede2" + stopword@~0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/stopword/-/stopword-0.1.6.tgz#435cc3e9d4311aedca2876ed4cae79153cd3d0fb" @@ -7026,6 +7140,12 @@ tough-cookie@^2.3.2, tough-cookie@~2.3.0: dependencies: punycode "^1.4.1" +tough-cookie@~2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -7247,6 +7367,10 @@ uuid@^3.0.0, uuid@^3.0.1: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" +uuid@^3.1.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + uws@~0.14.4: version "0.14.5" resolved "https://registry.yarnpkg.com/uws/-/uws-0.14.5.tgz#67aaf33c46b2a587a5f6666d00f7691328f149dc" @@ -7400,6 +7524,13 @@ watch@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc" +webfinger@0.4.x: + version "0.4.2" + resolved "https://registry.yarnpkg.com/webfinger/-/webfinger-0.4.2.tgz#3477a6d97799461896039fcffc650b73468ee76d" + dependencies: + step "0.0.x" + xml2js "0.1.x" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -7555,6 +7686,12 @@ xml-parse-from-string@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" +xml2js@0.1.x: + version "0.1.14" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c" + dependencies: + sax ">=0.1.1" + xml2js@^0.4.5: version "0.4.17" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868"