diff --git a/packages/backend/src/misc/normalize-email-address.ts b/packages/backend/src/misc/normalize-email-address.ts new file mode 100644 index 0000000000..126eefa7e4 --- /dev/null +++ b/packages/backend/src/misc/normalize-email-address.ts @@ -0,0 +1,5 @@ +const specialCharactersRegexp = /(\(.*?\)|(\+.*(?=@)))/gu; + +export function normalizeEmailAddress(email: string | null): string | null { + return email?.replaceAll(specialCharactersRegexp, '') ?? null; +} diff --git a/packages/backend/src/server/sso/JWTIdentifyProviderService.ts b/packages/backend/src/server/sso/JWTIdentifyProviderService.ts index 03ee7a7298..182b6af04d 100644 --- a/packages/backend/src/server/sso/JWTIdentifyProviderService.ts +++ b/packages/backend/src/server/sso/JWTIdentifyProviderService.ts @@ -22,6 +22,7 @@ import type { MiLocalUser } from '@/models/User.js'; import { CacheService } from '@/core/CacheService.js'; import { LoggerService } from '@/core/LoggerService.js'; import { RoleService } from '@/core/RoleService.js'; +import { normalizeEmailAddress } from '@/misc/normalize-email-address.js'; import type { FastifyInstance } from 'fastify'; @Injectable() @@ -175,7 +176,7 @@ export class JWTIdentifyProviderService { preferred_username: user.username, profile: `${this.config.url}/@${user.username}`, picture: user.avatarUrl ?? undefined, - email: profile.emailVerified ? profile.email : undefined, + email: profile.emailVerified ? normalizeEmailAddress(profile.email) : undefined, email_verified: profile.emailVerified, mfa_enabled: profile.twoFactorEnabled, updated_at: Math.floor((user.updatedAt?.getTime() ?? user.createdAt.getTime()) / 1000), diff --git a/packages/backend/src/server/sso/SAMLIdentifyProviderService.ts b/packages/backend/src/server/sso/SAMLIdentifyProviderService.ts index b5f35ddf3d..96c32291fe 100644 --- a/packages/backend/src/server/sso/SAMLIdentifyProviderService.ts +++ b/packages/backend/src/server/sso/SAMLIdentifyProviderService.ts @@ -26,6 +26,7 @@ import { RoleService } from '@/core/RoleService.js'; import type { MiLocalUser } from '@/models/User.js'; import { bindThis } from '@/decorators.js'; import { DI } from '@/di-symbols.js'; +import { normalizeEmailAddress } from '@/misc/normalize-email-address.js'; import type { FastifyInstance } from 'fastify'; @Injectable() @@ -440,7 +441,7 @@ export class SAMLIdentifyProviderService { }, 'saml:Subject': { 'saml:NameID': profile.emailVerified - ? { '@Format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', '#text': profile.email } + ? { '@Format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', '#text': normalizeEmailAddress(profile.email) } : { '@Format': 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', '#text': user.id }, 'saml:SubjectConfirmation': { '@Method': 'urn:oasis:names:tc:SAML:2.0:cm:bearer', @@ -531,24 +532,14 @@ export class SAMLIdentifyProviderService { '#text': user.avatarUrl, }, }] : []), - ...(profile.emailVerified ? [ - { - '@Name': 'mail', - '@NameFormat': 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic', - 'saml:AttributeValue': { - '@xsi:type': 'xs:string', - '#text': profile.email, - }, + ...(profile.emailVerified ? [{ + '@Name': 'email', + '@NameFormat': 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic', + 'saml:AttributeValue': { + '@xsi:type': 'xs:string', + '#text': normalizeEmailAddress(profile.email), }, - { - '@Name': 'email', - '@NameFormat': 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic', - 'saml:AttributeValue': { - '@xsi:type': 'xs:string', - '#text': profile.email, - }, - }, - ] : []), + }] : []), { '@Name': 'email_verified', '@NameFormat': 'urn:oasis:names:tc:SAML:2.0:attrname-format:basic',