mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-27 12:08:02 -05:00
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:
parent
287148f1e8
commit
5a1a25dda4
5 changed files with 103 additions and 109 deletions
|
@ -27,6 +27,7 @@ export enum ProviderEnum {
|
||||||
dropbox = 'dropbox',
|
dropbox = 'dropbox',
|
||||||
google = 'google',
|
google = 'google',
|
||||||
ldap = 'ldap',
|
ldap = 'ldap',
|
||||||
|
oauth2 = 'oauth2',
|
||||||
saml = 'saml',
|
saml = 'saml',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ import { DropboxMiddleware } from './dropbox'
|
||||||
import { GoogleMiddleware } from './google'
|
import { GoogleMiddleware } from './google'
|
||||||
import { LdapMiddleware } from './ldap'
|
import { LdapMiddleware } from './ldap'
|
||||||
import { SamlMiddleware } from './saml'
|
import { SamlMiddleware } from './saml'
|
||||||
import oauth2 from './oauth2'
|
import { OAuth2Middleware } from './oauth2'
|
||||||
import { EmailMiddleware } from './email'
|
import { EmailMiddleware } from './email'
|
||||||
import {OPenIDMiddleware } from './openid'
|
import { OPenIDMiddleware } from './openid'
|
||||||
|
|
||||||
const AuthRouter = Router()
|
const AuthRouter = Router()
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ if (config.isDropboxEnable) AuthRouter.use(DropboxMiddleware.getMiddleware())
|
||||||
if (config.isGoogleEnable) AuthRouter.use(GoogleMiddleware.getMiddleware())
|
if (config.isGoogleEnable) AuthRouter.use(GoogleMiddleware.getMiddleware())
|
||||||
if (config.isLDAPEnable) AuthRouter.use(LdapMiddleware.getMiddleware())
|
if (config.isLDAPEnable) AuthRouter.use(LdapMiddleware.getMiddleware())
|
||||||
if (config.isSAMLEnable) AuthRouter.use(SamlMiddleware.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.isEmailEnable) AuthRouter.use(EmailMiddleware.getMiddleware())
|
||||||
if (config.isOpenIDEnable) AuthRouter.use(OPenIDMiddleware.getMiddleware())
|
if (config.isOpenIDEnable) AuthRouter.use(OPenIDMiddleware.getMiddleware())
|
||||||
|
|
||||||
|
|
|
@ -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 + '/'
|
|
||||||
})
|
|
||||||
)
|
|
35
lib/web/auth/oauth2/index.ts
Normal file
35
lib/web/auth/oauth2/index.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
64
lib/web/auth/oauth2/oauth2-custom-strategy.ts
Normal file
64
lib/web/auth/oauth2/oauth2-custom-strategy.ts
Normal 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 }
|
Loading…
Reference in a new issue