added auth/oauth2.ts

added oauth2 to ProviderEnum

Signed-off-by: Philip Molares <philip.molares@udo.edu>
Signed-off-by: David Mehren <dmehren1@gmail.com>
This commit is contained in:
Philip Molares 2020-04-13 15:45:29 +02:00 committed by David Mehren
parent 287148f1e8
commit 5a1a25dda4
No known key found for this signature in database
GPG key ID: 6017AF117F9756CB
5 changed files with 103 additions and 109 deletions

View file

@ -27,6 +27,7 @@ export enum ProviderEnum {
dropbox = 'dropbox',
google = 'google',
ldap = 'ldap',
oauth2 = 'oauth2',
saml = 'saml',
}

View file

@ -11,9 +11,9 @@ import { DropboxMiddleware } from './dropbox'
import { GoogleMiddleware } from './google'
import { LdapMiddleware } from './ldap'
import { SamlMiddleware } from './saml'
import oauth2 from './oauth2'
import { OAuth2Middleware } from './oauth2'
import { EmailMiddleware } from './email'
import {OPenIDMiddleware } from './openid'
import { OPenIDMiddleware } from './openid'
const AuthRouter = Router()
@ -51,7 +51,7 @@ if (config.isDropboxEnable) AuthRouter.use(DropboxMiddleware.getMiddleware())
if (config.isGoogleEnable) AuthRouter.use(GoogleMiddleware.getMiddleware())
if (config.isLDAPEnable) AuthRouter.use(LdapMiddleware.getMiddleware())
if (config.isSAMLEnable) AuthRouter.use(SamlMiddleware.getMiddleware())
if (config.isOAuth2Enable) AuthRouter.use(oauth2)
if (config.isOAuth2Enable) AuthRouter.use(OAuth2Middleware.getMiddleware())
if (config.isEmailEnable) AuthRouter.use(EmailMiddleware.getMiddleware())
if (config.isOpenIDEnable) AuthRouter.use(OPenIDMiddleware.getMiddleware())

View file

@ -1,106 +0,0 @@
'use strict'
const Router = require('express').Router
const passport = require('passport')
const { Strategy, InternalOAuthError } = require('passport-oauth2')
const config = require('../../../config')
const { passportGeneralCallback } = require('../utils')
let oauth2Auth = module.exports = Router()
class OAuth2CustomStrategy extends Strategy {
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 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 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,
scope: config.oauth2.scope
}, passportGeneralCallback))
oauth2Auth.get('/auth/oauth2', function (req, res, next) {
passport.authenticate('oauth2')(req, res, next)
})
// github auth callback
oauth2Auth.get('/auth/oauth2/callback',
passport.authenticate('oauth2', {
successReturnToOrRedirect: config.serverURL + '/',
failureRedirect: config.serverURL + '/'
})
)

View file

@ -0,0 +1,35 @@
import { Router } from 'express'
import passport from 'passport'
import { OAuth2CustomStrategy } from './oauth2-custom-strategy'
import { config } from '../../../config'
import { passportGeneralCallback } from '../utils'
import { AuthMiddleware } from '../interface'
export const OAuth2Middleware: AuthMiddleware = {
getMiddleware (): Router {
const OAuth2Auth = Router()
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,
scope: config.oauth2.scope
}, passportGeneralCallback))
OAuth2Auth.get('/auth/oauth2', passport.authenticate('oauth2'))
// github auth callback
OAuth2Auth.get('/auth/oauth2/callback',
passport.authenticate('oauth2', {
successReturnToOrRedirect: config.serverURL + '/',
failureRedirect: config.serverURL + '/'
})
)
return OAuth2Auth
}
}

View file

@ -0,0 +1,64 @@
import { InternalOAuthError, Strategy as OAuth2Strategy } from 'passport-oauth2'
import { config } from '../../../config'
import { Profile, ProviderEnum } from '../../../models/user'
function extractProfileAttribute (data, path: string): any {
// can handle stuff like `attrs[0].name`
const pathArray = path.split('.')
for (const segment of pathArray) {
const regex = /([\d\w]+)\[(.*)\]/
const m = regex.exec(segment)
data = m ? data[m[1]][m[2]] : data[segment]
}
return data
}
function parseProfile (data): Partial<Profile> {
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,
emails: [email]
}
}
class OAuth2CustomStrategy extends OAuth2Strategy {
private readonly _userProfileURL: string;
constructor (options, verify) {
options.customHeaders = options.customHeaders || {}
super(options, verify)
this.name = 'oauth2'
this._userProfileURL = options.userProfileURL
this._oauth2.useAuthorizationHeaderforGET(true)
}
userProfile (accessToken, done): void {
this._oauth2.get(this._userProfileURL, accessToken, function (err, body, _) {
let json
if (err) {
return done(new InternalOAuthError('Failed to fetch user profile', err))
}
try {
if (body !== undefined) {
json = JSON.parse(body.toString())
}
} catch (ex) {
return done(new Error('Failed to parse user profile'))
}
const profile = parseProfile(json)
profile.provider = ProviderEnum.oauth2
done(null, profile)
})
}
}
export { OAuth2CustomStrategy }