From e45327df5d99c2dd47de36443d0d5a38b8eb6f87 Mon Sep 17 00:00:00 2001 From: Dexter Chua Date: Wed, 17 Jun 2020 21:09:47 +0800 Subject: [PATCH] Allow for undefined email and displayName OAuth2 allows the user to only consent to a subset of the scopes requested. Previously, the Generic Oauth2 implementation assumes that the `username`, `email` and `displayName` attributes are supplied, and may crash if they are not defined. This commit allows for `email` and `displayName` to not be defined, either through the user refusing consent or the OAuth2 configuration not asking for them in the first place (by not setting `userProfile*Attr`). If `email` is not provided, the `emails` property is simply left empty. If `displayName` is not provided, it is left undefined, and CodiMD uses the `username` whenever the `displayName` is expected. This does not deal with the case where `username` is not provided. Since usernames are not unique in CodiMD, it is possible to deal with this by setting a dummy username. This can be added in a future commit if desired. Fixes #406 Signed-off-by: Dexter Chua --- .../web/auth/oauth2/oauth2-custom-strategy.ts | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/lib/web/auth/oauth2/oauth2-custom-strategy.ts b/src/lib/web/auth/oauth2/oauth2-custom-strategy.ts index a502efbb5..28b3c244c 100644 --- a/src/lib/web/auth/oauth2/oauth2-custom-strategy.ts +++ b/src/lib/web/auth/oauth2/oauth2-custom-strategy.ts @@ -1,6 +1,7 @@ import { InternalOAuthError, Strategy as OAuth2Strategy } from 'passport-oauth2' import { config } from '../../../config' import { PassportProfile, ProviderEnum } from '../utils' +import { logger } from '../../../logger' function extractProfileAttribute (data, path: string): string { // can handle stuff like `attrs[0].name` @@ -15,14 +16,33 @@ function extractProfileAttribute (data, path: string): string { function parseProfile (data): Partial { const username = extractProfileAttribute(data, config.oauth2.userProfileUsernameAttr) - const displayName = extractProfileAttribute(data, config.oauth2.userProfileDisplayNameAttr) - const email = extractProfileAttribute(data, config.oauth2.userProfileEmailAttr) + let displayName: string | undefined + try { + // This may fail if the config.oauth2.userProfileDisplayNameAttr is undefined, + // or it is foo.bar and data["foo"] is undefined. + displayName = extractProfileAttribute(data, config.oauth2.userProfileDisplayNameAttr) + } catch (e) { + displayName = undefined + logger.debug('\'id_token[%s]\' is undefined. Setting \'displayName\' to \'undefined\'.\n%s', config.oauth2.userProfileDisplayNameAttr, e.message) + } + + const emails: string[] = [] + try { + const email = extractProfileAttribute(data, config.oauth2.userProfileEmailAttr) + if (email !== undefined) { + emails.push(email) + } else { + logger.debug('\'id_token[%s]\' is undefined. Setting \'emails\' to [].', config.oauth2.userProfileEmailAttr) + } + } catch (e) { + logger.debug('\'id_token[%s]\' is undefined. Setting \'emails\' to [].\n%s', config.oauth2.userProfileEmailAttr, e.message) + } return { id: username, username: username, displayName: displayName, - emails: [email] + emails: emails } }