Added passport-openidconnect implementation

This commit is contained in:
lukeIam 2023-04-14 20:26:29 +02:00
parent 08676a675a
commit 62b0940766
4 changed files with 118 additions and 4 deletions

26
package-lock.json generated
View File

@ -19,6 +19,7 @@
"passport-google-oauth20": "^2.0.0", "passport-google-oauth20": "^2.0.0",
"passport-jwt": "^4.0.1", "passport-jwt": "^4.0.1",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"passport-openidconnect": "^0.1.1",
"socket.io": "^4.5.4", "socket.io": "^4.5.4",
"xml2js": "^0.4.23" "xml2js": "^0.4.23"
}, },
@ -1138,6 +1139,22 @@
"url": "https://github.com/sponsors/jaredhanson" "url": "https://github.com/sponsors/jaredhanson"
} }
}, },
"node_modules/passport-openidconnect": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/passport-openidconnect/-/passport-openidconnect-0.1.1.tgz",
"integrity": "sha512-r0QJiWEzwCg2MeCIXVP5G6YxVRqnEsZ2HpgKRthZ9AiQHJrgGUytXpsdcGF9BRwd3yMrEesb/uG/Yxb86rrY0g==",
"dependencies": {
"oauth": "0.9.x",
"passport-strategy": "1.x.x"
},
"engines": {
"node": ">= 0.6.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jaredhanson"
}
},
"node_modules/passport-strategy": { "node_modules/passport-strategy": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
@ -2417,6 +2434,15 @@
"utils-merge": "1.x.x" "utils-merge": "1.x.x"
} }
}, },
"passport-openidconnect": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/passport-openidconnect/-/passport-openidconnect-0.1.1.tgz",
"integrity": "sha512-r0QJiWEzwCg2MeCIXVP5G6YxVRqnEsZ2HpgKRthZ9AiQHJrgGUytXpsdcGF9BRwd3yMrEesb/uG/Yxb86rrY0g==",
"requires": {
"oauth": "0.9.x",
"passport-strategy": "1.x.x"
}
},
"passport-strategy": { "passport-strategy": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",

View File

@ -40,6 +40,7 @@
"passport-google-oauth20": "^2.0.0", "passport-google-oauth20": "^2.0.0",
"passport-jwt": "^4.0.1", "passport-jwt": "^4.0.1",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"passport-openidconnect": "^0.1.1",
"socket.io": "^4.5.4", "socket.io": "^4.5.4",
"xml2js": "^0.4.23" "xml2js": "^0.4.23"
}, },

View File

@ -5,6 +5,7 @@ const LocalStrategy = require('passport-local')
const JwtStrategy = require('passport-jwt').Strategy; const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt; const ExtractJwt = require('passport-jwt').ExtractJwt;
const GoogleStrategy = require('passport-google-oauth20').Strategy; const GoogleStrategy = require('passport-google-oauth20').Strategy;
var OpenIDConnectStrategy = require('passport-openidconnect');
const User = require('./objects/user/User.js') const User = require('./objects/user/User.js')
/** /**
@ -24,17 +25,52 @@ class Auth {
if (global.ServerSettings.authActiveAuthMethods.includes("local")) { if (global.ServerSettings.authActiveAuthMethods.includes("local")) {
passport.use(new LocalStrategy(this.localAuthCheckUserPw.bind(this))) passport.use(new LocalStrategy(this.localAuthCheckUserPw.bind(this)))
} }
// Check if we should load the google-oauth20 strategy // Check if we should load the google-oauth20 strategy
if (global.ServerSettings.authActiveAuthMethods.includes("google-oauth20")) { if (global.ServerSettings.authActiveAuthMethods.includes("google-oauth20")) {
passport.use(new GoogleStrategy({ passport.use(new GoogleStrategy({
clientID: global.ServerSettings.authGoogleOauth20ClientID, clientID: global.ServerSettings.authGoogleOauth20ClientID,
clientSecret: global.ServerSettings.authGoogleOauth20ClientSecret, clientSecret: global.ServerSettings.authGoogleOauth20ClientSecret,
callbackURL: global.ServerSettings.authGoogleOauth20CallbackURL callbackURL: global.ServerSettings.authGoogleOauth20CallbackURL
}, function (accessToken, refreshToken, profile, done) { }, (function (accessToken, refreshToken, profile, done) {
// TODO: what to use as username // TODO: what to use as username
// TODO: do we want to create the users which does not exist? // TODO: do we want to create the users which does not exist?
return done(null, { username: profile.emails[0].value }) var user = this.db.users.find(u => u.username.toLowerCase() === profile.emails[0].value.toLowerCase())
}))
if (!user || !user.isActive) {
done(null, null)
return
}
return done(null, user)
}).bind(this)))
}
// Check if we should load the openid strategy
if (global.ServerSettings.authActiveAuthMethods.includes("openid")) {
passport.use(new OpenIDConnectStrategy({
issuer: global.ServerSettings.authOpenIDIssuerURL,
authorizationURL: global.ServerSettings.authOpenIDAuthorizationURL,
tokenURL: global.ServerSettings.authOpenIDTokenURL,
userInfoURL: global.ServerSettings.authOpenIDUserInfoURL,
clientID: global.ServerSettings.authOpenIDClientID,
clientSecret: global.ServerSettings.authOpenIDClientSecret,
callbackURL: global.ServerSettings.authOpenIDCallbackURL,
scope: ["openid", "email", "profile"],
skipUserProfile: false
},
(function (issuer, profile, done) {
// TODO: what to use as username
// TODO: do we want to create the users which does not exist?
var user = this.db.users.find(u => u.username.toLowerCase() === profile.emails[0].value.toLowerCase())
if (!user || !user.isActive) {
done(null, null)
return
}
return done(null, user)
}).bind(this)))
} }
// Load the JwtStrategy (always) -> for bearer token auth // Load the JwtStrategy (always) -> for bearer token auth
@ -99,6 +135,18 @@ class Auth {
}).bind(this) }).bind(this)
) )
// openid strategy login route (this redirects to the configured openid login provider)
router.get('/auth/openid', passport.authenticate('openidconnect'));
// openid strategy callback route (this receives the token from the configured openid login provider)
router.get('/auth/openid/callback',
passport.authenticate('openidconnect', { failureRedirect: '/login' }),
(function (req, res) {
// return the user login response json if the login was successfull
res.json(this.getUserLoginResponsePayload(req.user.username))
}).bind(this)
)
// Logout route // Logout route
router.get('/logout', function (req, res) { router.get('/logout', function (req, res) {
// TODO: invalidate possible JWTs // TODO: invalidate possible JWTs

View File

@ -67,6 +67,14 @@ class ServerSettings {
this.authGoogleOauth20ClientSecret = '' this.authGoogleOauth20ClientSecret = ''
this.authGoogleOauth20CallbackURL = '' this.authGoogleOauth20CallbackURL = ''
// generic-oauth20 settings
this.authOpenIDIssuerURL = ''
this.authOpenIDAuthorizationURL = ''
this.authOpenIDTokenURL = ''
this.authOpenIDUserInfoURL = ''
this.authOpenIDClientID = ''
this.authOpenIDClientSecret = ''
this.authOpenIDCallbackURL = ''
if (settings) { if (settings) {
this.construct(settings) this.construct(settings)
@ -117,6 +125,14 @@ class ServerSettings {
this.authGoogleOauth20ClientSecret = settings.authGoogleOauth20ClientSecret || '' this.authGoogleOauth20ClientSecret = settings.authGoogleOauth20ClientSecret || ''
this.authGoogleOauth20CallbackURL = settings.authGoogleOauth20CallbackURL || '' this.authGoogleOauth20CallbackURL = settings.authGoogleOauth20CallbackURL || ''
this.authOpenIDIssuerURL = settings.authOpenIDIssuerURL || ''
this.authOpenIDAuthorizationURL = settings.authOpenIDAuthorizationURL || ''
this.authOpenIDTokenURL = settings.authOpenIDTokenURL || ''
this.authOpenIDUserInfoURL = settings.authOpenIDUserInfoURL || ''
this.authOpenIDClientID = settings.authOpenIDClientID || ''
this.authOpenIDClientSecret = settings.authOpenIDClientSecret || ''
this.authOpenIDCallbackURL = settings.authOpenIDCallbackURL || ''
if (!Array.isArray(this.authActiveAuthMethods)) { if (!Array.isArray(this.authActiveAuthMethods)) {
this.authActiveAuthMethods = ['local'] this.authActiveAuthMethods = ['local']
} }
@ -131,6 +147,20 @@ class ServerSettings {
this.authActiveAuthMethods.splice(this.authActiveAuthMethods.indexOf('google-oauth20', 0), 1); this.authActiveAuthMethods.splice(this.authActiveAuthMethods.indexOf('google-oauth20', 0), 1);
} }
// remove uninitialized methods
// OpenID
if (this.authActiveAuthMethods.includes('generic-oauth20') && (
this.authOpenIDIssuerURL === '' ||
this.authOpenIDAuthorizationURL === '' ||
this.authOpenIDTokenURL === '' ||
this.authOpenIDUserInfoURL === '' ||
this.authOpenIDClientID === '' ||
this.authOpenIDClientSecret === '' ||
this.authOpenIDCallbackURL === ''
)) {
this.authActiveAuthMethods.splice(this.authActiveAuthMethods.indexOf('generic-oauth20', 0), 1);
}
// fallback to local // fallback to local
if (!Array.isArray(this.authActiveAuthMethods) || this.authActiveAuthMethods.length == 0) { if (!Array.isArray(this.authActiveAuthMethods) || this.authActiveAuthMethods.length == 0) {
this.authActiveAuthMethods = ['local'] this.authActiveAuthMethods = ['local']
@ -189,7 +219,14 @@ class ServerSettings {
authActiveAuthMethods: this.authActiveAuthMethods, authActiveAuthMethods: this.authActiveAuthMethods,
authGoogleOauth20ClientID: this.authGoogleOauth20ClientID, // Do not return to client authGoogleOauth20ClientID: this.authGoogleOauth20ClientID, // Do not return to client
authGoogleOauth20ClientSecret: this.authGoogleOauth20ClientSecret, // Do not return to client authGoogleOauth20ClientSecret: this.authGoogleOauth20ClientSecret, // Do not return to client
authGoogleOauth20CallbackURL: this.authGoogleOauth20CallbackURL authGoogleOauth20CallbackURL: this.authGoogleOauth20CallbackURL,
authOpenIDIssuerURL: this.authOpenIDIssuerURL,
authOpenIDAuthorizationURL: this.authOpenIDAuthorizationURL,
authOpenIDTokenURL: this.authOpenIDTokenURL,
authOpenIDUserInfoURL: this.authOpenIDUserInfoURL,
authOpenIDClientID: this.authOpenIDClientID, // Do not return to client
authOpenIDClientSecret: this.authOpenIDClientSecret, // Do not return to client
authOpenIDCallbackURL: this.authOpenIDCallbackURL
} }
} }
@ -198,6 +235,8 @@ class ServerSettings {
delete json.tokenSecret delete json.tokenSecret
delete json.authGoogleOauth20ClientID delete json.authGoogleOauth20ClientID
delete json.authGoogleOauth20ClientSecret delete json.authGoogleOauth20ClientSecret
delete json.authOpenIDClientID
delete json.authOpenIDClientSecret
return json return json
} }