Integrate with configuration ui / support for email usernames

This commit is contained in:
Rory Powell 2021-07-08 13:04:04 +01:00
parent ef8b9b40c1
commit aa601f3701
2 changed files with 44 additions and 27 deletions

View File

@ -2,24 +2,6 @@ const fetch = require("node-fetch")
const OIDCStrategy = require("@techpass/passport-openidconnect").Strategy const OIDCStrategy = require("@techpass/passport-openidconnect").Strategy
const { authenticateThirdParty } = require("./third-party-common") const { authenticateThirdParty } = require("./third-party-common")
/**
* @param {*} profile The structured profile created by passport using the user info endpoint
* @param {*} jwtClaims The claims returned in the id token
*/
function getEmail(profile, jwtClaims) {
// profile not guaranteed to contain email e.g. github connected azure ad account
if (profile._json.email) {
return profile._json.email
}
// fallback to id token
if (jwtClaims.email) {
return jwtClaims.email
}
return null;
}
/** /**
* @param {*} issuer The identity provider base URL * @param {*} issuer The identity provider base URL
* @param {*} sub The user ID * @param {*} sub The user ID
@ -62,25 +44,52 @@ async function authenticate(
done) done)
} }
/**
* @param {*} profile The structured profile created by passport using the user info endpoint
* @param {*} jwtClaims The claims returned in the id token
*/
function getEmail(profile, jwtClaims) {
// profile not guaranteed to contain email e.g. github connected azure ad account
if (profile._json.email) {
return profile._json.email
}
// fallback to id token email
if (jwtClaims.email) {
return jwtClaims.email
}
// fallback to id token preferred username
const username = jwtClaims.preferred_username
if (username && validEmail(username)) {
return username
}
return null;
}
function validEmail(value) {
return (
(value && !!value.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/))
)
}
/** /**
* Create an instance of the oidc passport strategy. This wrapper fetches the configuration * Create an instance of the oidc passport strategy. This wrapper fetches the configuration
* from couchDB rather than environment variables, using this factory is necessary for dynamically configuring passport. * from couchDB rather than environment variables, using this factory is necessary for dynamically configuring passport.
* @returns Dynamically configured Passport OIDC Strategy * @returns Dynamically configured Passport OIDC Strategy
*/ */
exports.strategyFactory = async function (callbackUrl) { exports.strategyFactory = async function (config, callbackUrl) {
try { try {
const configurationUrl = const { clientId, clientSecret, configUrl } = config
"https://login.microsoftonline.com/2668c0dd-7ed2-4db3-b387-05b6f9204a70/v2.0/.well-known/openid-configuration"
const clientSecret = "g-ty~2iW.bo.88xj_QI6~hdc-H8mP2Xbnd"
const clientId = "bed2017b-2f53-42a9-8ef9-e58918935e07"
if (!clientId || !clientSecret || !callbackUrl || !configurationUrl) { if (!clientId || !clientSecret || !callbackUrl || !configUrl) {
throw new Error( throw new Error(
"Configuration invalid. Must contain clientID, clientSecret, callbackUrl and configurationUrl" "Configuration invalid. Must contain clientID, clientSecret, callbackUrl and configUrl"
) )
} }
const response = await fetch(configurationUrl) const response = await fetch(configUrl)
if (!response.ok) { if (!response.ok) {
throw new Error(`Unexpected response when fetching openid-configuration: ${response.statusText}`) throw new Error(`Unexpected response when fetching openid-configuration: ${response.statusText}`)

View File

@ -133,8 +133,16 @@ exports.googleAuth = async (ctx, next) => {
} }
async function oidcStrategyFactory(ctx) { async function oidcStrategyFactory(ctx) {
const db = new CouchDB(GLOBAL_DB)
const config = await authPkg.db.getScopedConfig(db, {
type: Configs.OIDC,
group: ctx.query.group,
})
const callbackUrl = `${ctx.protocol}://${ctx.host}/api/admin/auth/oidc/callback` const callbackUrl = `${ctx.protocol}://${ctx.host}/api/admin/auth/oidc/callback`
return oidc.strategyFactory(callbackUrl)
return oidc.strategyFactory(config, callbackUrl)
} }
/** /**