chore(sso): clearer sso user taken error (#4054)

* chore(sso): clearer error

* fix(sso): safe user information
This commit is contained in:
Chuck Driesler
2025-02-24 11:39:36 +00:00
committed by GitHub
parent 3ef143375f
commit 66ccbe4cd7
2 changed files with 43 additions and 4 deletions
@@ -1,3 +1,5 @@
import { UserEmail } from '@/modules/core/domain/userEmails/types'
import { User } from '@/modules/core/domain/users/types'
import { BaseError } from '@/modules/shared/errors/base'
export class SsoSessionMissingOrExpiredError extends BaseError {
@@ -69,6 +71,22 @@ export class SsoUserClaimedError extends BaseError {
static defaultMessage =
'OIDC provider user already associated with another Speckle account.'
static code = 'SSO_USER_ALREADY_CLAIMED_ERROR'
constructor(params: {
currentUser: User
currentUserEmails: UserEmail[]
existingUser: User
existingUserEmail: string
}) {
super(
[
'User from SSO provider already exists as another Speckle user.',
`Currently signed in as ${params.currentUser.name}`,
`(${params.currentUserEmails.map((record) => record.email).join(',')})`,
`but attempted to sign in as ${params.existingUser.name}`,
`(${params.existingUserEmail})`
].join(' ')
)
}
}
export class SsoUserInviteRequiredError extends BaseError {
+25 -4
View File
@@ -94,7 +94,10 @@ import {
UpsertUserSsoSession
} from '@/modules/workspaces/domain/sso/operations'
import { GetUser } from '@/modules/core/domain/users/operations'
import { FindEmail } from '@/modules/core/domain/userEmails/operations'
import {
FindEmail,
FindEmailsByUserId
} from '@/modules/core/domain/userEmails/operations'
import {
buildAuthErrorRedirectUrl,
buildAuthFinalizeRedirectUrl,
@@ -288,7 +291,8 @@ export const getSsoRouter = (): Router => {
getOidcProviderUserData: getOidcProviderUserDataFactory(),
tryGetSpeckleUserData: tryGetSpeckleUserDataFactory({
findEmail: findEmailFactory({ db: trx }),
getUser: getUserFactory({ db: trx })
getUser: getUserFactory({ db: trx }),
getUserEmails: findEmailsByUserIdFactory({ db: trx })
}),
createWorkspaceUserFromSsoProfile: createWorkspaceUserFromSsoProfileFactory({
createUser: createUserFactory({
@@ -677,7 +681,15 @@ const getOidcProviderUserDataFactory =
}
const tryGetSpeckleUserDataFactory =
({ findEmail, getUser }: { findEmail: FindEmail; getUser: GetUser }) =>
({
findEmail,
getUser,
getUserEmails
}: {
findEmail: FindEmail
getUser: GetUser
getUserEmails: FindEmailsByUserId
}) =>
async (
req: Request<WorkspaceSsoAuthRequestParams>,
oidcProviderUserData: UserinfoResponse<OidcProfile>
@@ -704,7 +716,16 @@ const tryGetSpeckleUserDataFactory =
// Confirm existing user matches signed-in user, if both are present
if (!!currentSessionUser && !!existingSpeckleUser) {
if (currentSessionUser.id !== existingSpeckleUser.id) {
throw new SsoUserClaimedError()
const currentSessionUserEmails = await getUserEmails({
userId: currentSessionUser.id
})
throw new SsoUserClaimedError({
currentUser: currentSessionUser,
currentUserEmails: currentSessionUserEmails,
existingUser: existingSpeckleUser,
existingUserEmail: providerEmail
})
}
}