chore(sso): clearer sso user taken error (#4054)
* chore(sso): clearer error * fix(sso): safe user information
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user