summaryrefslogtreecommitdiff
path: root/lib/web
diff options
context:
space:
mode:
Diffstat (limited to 'lib/web')
-rw-r--r--lib/web/auth/index.js1
-rw-r--r--lib/web/auth/oauth2/index.js106
2 files changed, 107 insertions, 0 deletions
diff --git a/lib/web/auth/index.js b/lib/web/auth/index.js
index eb42fb36..61e7c3f9 100644
--- a/lib/web/auth/index.js
+++ b/lib/web/auth/index.js
@@ -43,6 +43,7 @@ if (config.isDropboxEnable) authRouter.use(require('./dropbox'))
if (config.isGoogleEnable) authRouter.use(require('./google'))
if (config.isLDAPEnable) authRouter.use(require('./ldap'))
if (config.isSAMLEnable) authRouter.use(require('./saml'))
+if (config.isOAuth2Enable) authRouter.use(require('./oauth2'))
if (config.isEmailEnable) authRouter.use(require('./email'))
// logout
diff --git a/lib/web/auth/oauth2/index.js b/lib/web/auth/oauth2/index.js
new file mode 100644
index 00000000..f2a3132d
--- /dev/null
+++ b/lib/web/auth/oauth2/index.js
@@ -0,0 +1,106 @@
+'use strict'
+
+const Router = require('express').Router
+const passport = require('passport')
+const OAuth2Strategy = require('passport-oauth2').Strategy
+const config = require('../../../config')
+const {setReturnToFromReferer, passportGeneralCallback} = require('../utils')
+
+let oauth2Auth = module.exports = Router()
+
+class OAuth2CustomStrategy extends OAuth2Strategy {
+ constructor (options, verify) {
+ options.customHeaders = options.customHeaders || {}
+ super(options, verify)
+ this.name = 'oauth2'
+ this._userProfileURL = options.userProfileURL
+ this._oauth2.useAuthorizationHeaderforGET(true)
+ }
+
+ userProfile (accessToken, done) {
+ this._oauth2.get(this._userProfileURL, accessToken, function (err, body, res) {
+ var json
+
+ if (err) {
+ return done(new passport.InternalOAuthError('Failed to fetch user profile', err))
+ }
+
+ try {
+ json = JSON.parse(body)
+ } catch (ex) {
+ return done(new Error('Failed to parse user profile'))
+ }
+
+ let profile = parseProfile(json)
+ profile.provider = 'oauth2'
+
+ done(null, profile)
+ })
+ }
+}
+
+function extractProfileAttribute (data, path) {
+ // can handle stuff like `attrs[0].name`
+ path = path.split('.')
+ for (const segment of path) {
+ const m = segment.match(/([\d\w]+)\[(.*)\]/)
+ data = m ? data[m[1]][m[2]] : data[segment]
+ }
+ return data
+}
+
+function parseProfile (data) {
+ const username = extractProfileAttribute(data, config.oauth2.userProfileUsernameAttr)
+ const displayName = extractProfileAttribute(data, config.oauth2.userProfileDisplayNameAttr)
+ const email = extractProfileAttribute(data, config.oauth2.userProfileEmailAttr)
+
+ return {
+ id: username,
+ username: username,
+ displayName: displayName,
+ email: email
+ }
+}
+
+OAuth2CustomStrategy.prototype.userProfile = function (accessToken, done) {
+ this._oauth2.get(this._userProfileURL, accessToken, function (err, body, res) {
+ var json
+
+ if (err) {
+ return done(new passport.InternalOAuthError('Failed to fetch user profile', err))
+ }
+
+ try {
+ json = JSON.parse(body)
+ } catch (ex) {
+ return done(new Error('Failed to parse user profile'))
+ }
+
+ let profile = parseProfile(json)
+ profile.provider = 'oauth2'
+
+ done(null, profile)
+ })
+}
+
+passport.use(new OAuth2CustomStrategy({
+ authorizationURL: config.oauth2.authorizationURL,
+ tokenURL: config.oauth2.tokenURL,
+ clientID: config.oauth2.clientID,
+ clientSecret: config.oauth2.clientSecret,
+ callbackURL: config.serverURL + '/auth/oauth2/callback',
+ userProfileURL: config.oauth2.userProfileURL
+}, passportGeneralCallback))
+
+oauth2Auth.get('/auth/oauth2', function (req, res, next) {
+ setReturnToFromReferer(req)
+ passport.authenticate('oauth2')(req, res, next)
+})
+
+// github auth callback
+oauth2Auth.get('/auth/oauth2/callback',
+ passport.authenticate('oauth2', {
+ successReturnToOrRedirect: config.serverurl + '/',
+ failureRedirect: config.serverurl + '/'
+ })
+)