diff --git a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/GithubOAuthDelegate.kt b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/GithubOAuthDelegate.kt index 7519e83f21..29b255ec3b 100644 --- a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/GithubOAuthDelegate.kt +++ b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/GithubOAuthDelegate.kt @@ -10,6 +10,7 @@ import io.tolgee.model.enums.ThirdPartyAuthType import io.tolgee.security.authentication.JwtService import io.tolgee.security.payload.JwtAuthenticationResponse import io.tolgee.security.service.thirdParty.ThirdPartyAuthDelegate +import io.tolgee.service.TenantService import io.tolgee.service.security.AuthProviderChangeService import io.tolgee.service.security.SignUpService import io.tolgee.service.security.UserAccountService @@ -30,6 +31,7 @@ class GithubOAuthDelegate( properties: TolgeeProperties, private val signUpService: SignUpService, private val authProviderChangeService: AuthProviderChangeService, + private val tenantService: TenantService, ) : ThirdPartyAuthDelegate { private val githubConfigurationProperties: GithubAuthenticationProperties = properties.authentication.github @@ -83,31 +85,9 @@ class GithubOAuthDelegate( )?.email ?: throw AuthenticationException(Message.THIRD_PARTY_AUTH_NO_EMAIL) - val userAccount = - userAccountService.findByThirdParty(ThirdPartyAuthType.GITHUB, userResponse!!.id!!) ?: let { - userAccountService.findActive(githubEmail)?.let { - authProviderChangeService.initiateProviderChange( - AuthProviderChangeData( - it, - UserAccount.AccountType.THIRD_PARTY, - ThirdPartyAuthType.GITHUB, - userResponse.id, - ), - ) - throw AuthenticationException(Message.THIRD_PARTY_SWITCH_INITIATED) - } - - val newUserAccount = UserAccount() - newUserAccount.username = githubEmail - newUserAccount.name = userResponse.name ?: userResponse.login - newUserAccount.thirdPartyAuthId = userResponse.id - newUserAccount.thirdPartyAuthType = ThirdPartyAuthType.GITHUB - newUserAccount.accountType = UserAccount.AccountType.THIRD_PARTY - - signUpService.signUp(newUserAccount, invitationCode, null) - - newUserAccount - } + val userAccount = findAccount(githubEmail, userResponse!!, invitationCode) + + tenantService.checkSsoNotRequired(userAccount.username) val jwt = jwtService.emitToken(userAccount.id) return JwtAuthenticationResponse(jwt) @@ -123,6 +103,39 @@ class GithubOAuthDelegate( throw AuthenticationException(Message.THIRD_PARTY_AUTH_UNKNOWN_ERROR) } + fun findAccount( + githubEmail: String, + userResponse: GithubUserResponse, + invitationCode: String?, + ): UserAccount { + userAccountService.findByThirdParty(ThirdPartyAuthType.GITHUB, userResponse.id!!)?.let { + return it + } + + userAccountService.findActive(githubEmail)?.let { + authProviderChangeService.initiateProviderChange( + AuthProviderChangeData( + it, + UserAccount.AccountType.THIRD_PARTY, + ThirdPartyAuthType.GITHUB, + userResponse.id, + ), + ) + return it + } + + val newUserAccount = UserAccount() + newUserAccount.username = githubEmail + newUserAccount.name = userResponse.name ?: userResponse.login + newUserAccount.thirdPartyAuthId = userResponse.id + newUserAccount.thirdPartyAuthType = ThirdPartyAuthType.GITHUB + newUserAccount.accountType = UserAccount.AccountType.THIRD_PARTY + + signUpService.signUp(newUserAccount, invitationCode, null) + + return newUserAccount + } + class GithubEmailResponse { var email: String? = null var primary = false diff --git a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/GoogleOAuthDelegate.kt b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/GoogleOAuthDelegate.kt index e543a95896..3727c65663 100644 --- a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/GoogleOAuthDelegate.kt +++ b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/GoogleOAuthDelegate.kt @@ -10,6 +10,7 @@ import io.tolgee.model.enums.ThirdPartyAuthType import io.tolgee.security.authentication.JwtService import io.tolgee.security.payload.JwtAuthenticationResponse import io.tolgee.security.service.thirdParty.ThirdPartyAuthDelegate +import io.tolgee.service.TenantService import io.tolgee.service.security.AuthProviderChangeService import io.tolgee.service.security.SignUpService import io.tolgee.service.security.UserAccountService @@ -29,6 +30,7 @@ class GoogleOAuthDelegate( properties: TolgeeProperties, private val signUpService: SignUpService, private val authProviderChangeService: AuthProviderChangeService, + private val tenantService: TenantService, ) : ThirdPartyAuthDelegate { private val googleConfigurationProperties: GoogleAuthenticationProperties = properties.authentication.google @@ -85,33 +87,10 @@ class GoogleOAuthDelegate( } } - val googleEmail = userResponse.email ?: throw AuthenticationException(Message.THIRD_PARTY_AUTH_NO_EMAIL) - - val userAccount = - userAccountService.findByThirdParty(ThirdPartyAuthType.GOOGLE, userResponse.sub!!) ?: let { - userAccountService.findActive(googleEmail)?.let { - authProviderChangeService.initiateProviderChange( - AuthProviderChangeData( - it, - UserAccount.AccountType.THIRD_PARTY, - ThirdPartyAuthType.GOOGLE, - userResponse.sub, - ), - ) - throw AuthenticationException(Message.THIRD_PARTY_SWITCH_INITIATED) - } - - val newUserAccount = UserAccount() - newUserAccount.username = userResponse.email - ?: throw AuthenticationException(Message.THIRD_PARTY_AUTH_NO_EMAIL) - newUserAccount.name = userResponse.name ?: (userResponse.given_name + " " + userResponse.family_name) - newUserAccount.thirdPartyAuthId = userResponse.sub - newUserAccount.thirdPartyAuthType = ThirdPartyAuthType.GOOGLE - newUserAccount.accountType = UserAccount.AccountType.THIRD_PARTY - signUpService.signUp(newUserAccount, invitationCode, null) - - newUserAccount - } + val userAccount = findAccount(userResponse, invitationCode) + + tenantService.checkSsoNotRequired(userAccount.username) + val jwt = jwtService.emitToken(userAccount.id) return JwtAuthenticationResponse(jwt) } @@ -128,6 +107,39 @@ class GoogleOAuthDelegate( } } + private fun findAccount( + userResponse: GoogleUserResponse, + invitationCode: String?, + ): UserAccount { + userAccountService.findByThirdParty(ThirdPartyAuthType.GOOGLE, userResponse.sub!!)?.let { + return it + } + + val googleEmail = userResponse.email ?: throw AuthenticationException(Message.THIRD_PARTY_AUTH_NO_EMAIL) + userAccountService.findActive(googleEmail)?.let { + authProviderChangeService.initiateProviderChange( + AuthProviderChangeData( + it, + UserAccount.AccountType.THIRD_PARTY, + ThirdPartyAuthType.GOOGLE, + userResponse.sub, + ), + ) + return it + } + + val newUserAccount = UserAccount() + newUserAccount.username = userResponse.email + ?: throw AuthenticationException(Message.THIRD_PARTY_AUTH_NO_EMAIL) + newUserAccount.name = userResponse.name ?: (userResponse.given_name + " " + userResponse.family_name) + newUserAccount.thirdPartyAuthId = userResponse.sub + newUserAccount.thirdPartyAuthType = ThirdPartyAuthType.GOOGLE + newUserAccount.accountType = UserAccount.AccountType.THIRD_PARTY + signUpService.signUp(newUserAccount, invitationCode, null) + + return newUserAccount + } + @Suppress("PropertyName") class GoogleUserResponse { var sub: String? = null diff --git a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/OAuth2Delegate.kt b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/OAuth2Delegate.kt index 31b2ae2f47..f8a3db8312 100644 --- a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/OAuth2Delegate.kt +++ b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/OAuth2Delegate.kt @@ -10,6 +10,7 @@ import io.tolgee.security.authentication.JwtService import io.tolgee.security.payload.JwtAuthenticationResponse import io.tolgee.security.service.thirdParty.ThirdPartyAuthDelegate import io.tolgee.security.thirdParty.data.OAuthUserDetails +import io.tolgee.service.TenantService import org.slf4j.LoggerFactory import org.springframework.http.HttpEntity import org.springframework.http.HttpHeaders @@ -28,6 +29,7 @@ class OAuth2Delegate( private val restTemplate: RestTemplate, properties: TolgeeProperties, private val oAuthUserHandler: OAuthUserHandler, + private val tenantService: TenantService, ) : ThirdPartyAuthDelegate { private val oauth2ConfigurationProperties: OAuth2AuthenticationProperties = properties.authentication.oauth2 private val logger = LoggerFactory.getLogger(this::class.java) @@ -110,6 +112,8 @@ class OAuth2Delegate( UserAccount.AccountType.THIRD_PARTY, ) + tenantService.checkSsoNotRequired(user.username) + val jwt = jwtService.emitToken(user.id) return JwtAuthenticationResponse(jwt) } diff --git a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/OAuthUserHandler.kt b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/OAuthUserHandler.kt index f7550f0153..7cf985f9b5 100644 --- a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/OAuthUserHandler.kt +++ b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/OAuthUserHandler.kt @@ -62,7 +62,7 @@ class OAuthUserHandler( thirdPartyAuthType: ThirdPartyAuthType, accountType: UserAccount.AccountType, ): UserAccount { - val existingUserAccount = + var existingUserAccount = userAccountService.findActive(userResponse.email) if (existingUserAccount != null) { authProviderChangeService.initiateProviderChange( @@ -76,7 +76,7 @@ class OAuthUserHandler( ssoExpiration = userAccountService.getCurrentSsoExpiration(thirdPartyAuthType), ), ) - throw AuthenticationException(Message.THIRD_PARTY_SWITCH_INITIATED) + return existingUserAccount } val newUserAccount = UserAccount() diff --git a/backend/data/src/main/kotlin/io/tolgee/configuration/tolgee/SsoOrganizationsProperties.kt b/backend/data/src/main/kotlin/io/tolgee/configuration/tolgee/SsoOrganizationsProperties.kt index f13d2533b6..acd64567a9 100644 --- a/backend/data/src/main/kotlin/io/tolgee/configuration/tolgee/SsoOrganizationsProperties.kt +++ b/backend/data/src/main/kotlin/io/tolgee/configuration/tolgee/SsoOrganizationsProperties.kt @@ -31,4 +31,19 @@ class SsoOrganizationsProperties { " able to access the server after the account has been disabled or deleted in the SSO provider.", ) var sessionExpirationMinutes: Int = 10 + + @DocProperty( + description = + "Only allow listed domains to be used for SSO configuration.", + ) + var allowedDomains: List? = emptyList() + + fun isAllowed(domain: String): Boolean { + val allowed = allowedDomains + if (allowed == null) { + return true + } + + return domain in allowed + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/constants/Message.kt b/backend/data/src/main/kotlin/io/tolgee/constants/Message.kt index adebecae7f..9cf98660e2 100644 --- a/backend/data/src/main/kotlin/io/tolgee/constants/Message.kt +++ b/backend/data/src/main/kotlin/io/tolgee/constants/Message.kt @@ -258,6 +258,8 @@ enum class Message { CANNOT_SET_SSO_PROVIDER_MISSING_FIELDS, NAMESPACES_CANNOT_BE_DISABLED_WHEN_NAMESPACE_EXISTS, NAMESPACE_CANNOT_BE_USED_WHEN_FEATURE_IS_DISABLED, + SSO_DOMAIN_NOT_ALLOWED, + SSO_LOGIN_FORCED_FOR_THIS_ACCOUNT, ; val code: String diff --git a/backend/data/src/main/kotlin/io/tolgee/service/TenantService.kt b/backend/data/src/main/kotlin/io/tolgee/service/TenantService.kt index eddbebfe02..d8edbe77ad 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/TenantService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/TenantService.kt @@ -1,11 +1,15 @@ package io.tolgee.service +import io.tolgee.constants.Message import io.tolgee.dtos.sso.SsoTenantConfig import io.tolgee.dtos.sso.SsoTenantDto +import io.tolgee.exceptions.AuthenticationException import io.tolgee.model.Organization import io.tolgee.model.SsoTenant interface TenantService { + fun getEnabledConfigByDomainOrNull(domain: String): SsoTenantConfig? + fun getEnabledConfigByDomain(domain: String): SsoTenantConfig fun save(tenant: SsoTenant): SsoTenant @@ -22,4 +26,14 @@ interface TenantService { request: SsoTenantDto, organization: Organization, ): SsoTenant + + fun checkSsoNotRequired(username: String) { + val domain = username.takeIf { it.count { it == '@' } == 1 }?.split('@')?.get(1) + if (domain != null) { + val tenant = getEnabledConfigByDomainOrNull(domain) + if (tenant != null) { + throw AuthenticationException(Message.SSO_LOGIN_FORCED_FOR_THIS_ACCOUNT, listOf(domain)) + } + } + } } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/TenantServiceOssStub.kt b/backend/data/src/main/kotlin/io/tolgee/service/TenantServiceOssStub.kt index 17afaedf63..ad7640f6f7 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/TenantServiceOssStub.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/TenantServiceOssStub.kt @@ -10,6 +10,10 @@ import org.springframework.stereotype.Service @Service class TenantServiceOssStub : TenantService { + override fun getEnabledConfigByDomainOrNull(domain: String): SsoTenantConfig? { + return null + } + override fun getEnabledConfigByDomain(domain: String): SsoTenantConfig { throw NotFoundException(Message.SSO_DOMAIN_NOT_FOUND_OR_DISABLED) } diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/AuthProviderChangeService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/AuthProviderChangeService.kt index dccf2d1075..e768abed4c 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/AuthProviderChangeService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/AuthProviderChangeService.kt @@ -15,8 +15,6 @@ import io.tolgee.service.TenantService import io.tolgee.service.organization.OrganizationRoleService import io.tolgee.util.addMinutes import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Propagation -import org.springframework.transaction.annotation.Transactional @Service class AuthProviderChangeService( @@ -33,19 +31,39 @@ class AuthProviderChangeService( return getActiveAuthProviderChangeRequest(userAccount)?.asAuthProviderDto() } - @Transactional(propagation = Propagation.REQUIRES_NEW) +// @Transactional(propagation = Propagation.REQUIRES_NEW) +// fun initiateProviderChange(data: AuthProviderChangeData) { +// authProviderChangeRequestRepository.deleteByUserAccountId(data.userAccount.id) +// val expirationDate = currentDateProvider.date.addMinutes(30) +// authProviderChangeRequestRepository.save(data.asAuthProviderChangeRequest(expirationDate)) +// throw AuthenticationException(Message.THIRD_PARTY_SWITCH_INITIATED) +// } + fun initiateProviderChange(data: AuthProviderChangeData) { - authProviderChangeRequestRepository.deleteByUserAccountId(data.userAccount.id) + // This version of the function is only temporary solution and + // supports only SSO account auth provider change for now. + // It will be replaced with the version above once full + // support for auth provider change is implemented. + if (data.accountType != UserAccount.AccountType.MANAGED) { + throw AuthenticationException(Message.USERNAME_ALREADY_EXISTS) + } val expirationDate = currentDateProvider.date.addMinutes(30) - authProviderChangeRequestRepository.save(data.asAuthProviderChangeRequest(expirationDate)) + val change = data.asAuthProviderChangeRequest(expirationDate) + acceptProviderChange(change) } fun acceptProviderChange(userAccount: UserAccount) { + val req = getActiveAuthProviderChangeRequest(userAccount) ?: return + acceptProviderChange(req) + authProviderChangeRequestRepository.delete(req) + } + + fun acceptProviderChange(req: AuthProviderChangeRequest) { + val userAccount = req.userAccount ?: return throw NotFoundException() if (userAccount.accountType === UserAccount.AccountType.MANAGED) { throw AuthenticationException(Message.OPERATION_UNAVAILABLE_FOR_ACCOUNT_TYPE) } - val req = getActiveAuthProviderChangeRequest(userAccount) ?: return userAccount.apply { accountType = req.accountType thirdPartyAuthType = req.authType @@ -66,7 +84,6 @@ class AuthProviderChangeService( } organizationRoleService.setManaged(userAccount, organization, true) } - authProviderChangeRequestRepository.delete(req) } fun rejectProviderChange(userAccount: UserAccount) { diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/SignUpService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/SignUpService.kt index 6cb4ded6de..c10de5cca0 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/SignUpService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/SignUpService.kt @@ -13,6 +13,7 @@ import io.tolgee.security.authentication.JwtService import io.tolgee.security.payload.JwtAuthenticationResponse import io.tolgee.service.EmailVerificationService import io.tolgee.service.QuickStartService +import io.tolgee.service.TenantService import io.tolgee.service.invitation.InvitationService import io.tolgee.service.organization.OrganizationRoleService import io.tolgee.service.organization.OrganizationService @@ -31,6 +32,7 @@ class SignUpService( private val organizationRoleService: OrganizationRoleService, private val quickStartService: QuickStartService, private val passwordEncoder: PasswordEncoder, + private val tenantService: TenantService, ) { @Transactional fun signUp(dto: SignUpDto): JwtAuthenticationResponse? { @@ -38,6 +40,8 @@ class SignUpService( throw BadRequestException(Message.USERNAME_ALREADY_EXISTS) } + tenantService.checkSsoNotRequired(dto.email) + val user = dtoToEntity(dto) signUp(user, dto.invitationCode, dto.organizationName, dto.userSource) diff --git a/backend/data/src/main/kotlin/io/tolgee/service/security/UserCredentialsService.kt b/backend/data/src/main/kotlin/io/tolgee/service/security/UserCredentialsService.kt index 678938895e..3fc33bff11 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/security/UserCredentialsService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/security/UserCredentialsService.kt @@ -3,6 +3,7 @@ package io.tolgee.service.security import io.tolgee.constants.Message import io.tolgee.exceptions.AuthenticationException import io.tolgee.model.UserAccount +import io.tolgee.service.TenantService import org.springframework.beans.factory.annotation.Autowired import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Service @@ -10,6 +11,7 @@ import org.springframework.stereotype.Service @Service class UserCredentialsService( private val passwordEncoder: PasswordEncoder, + private val tenantService: TenantService, ) { @set:Autowired lateinit var userAccountService: UserAccountService @@ -18,6 +20,8 @@ class UserCredentialsService( username: String, password: String, ): UserAccount { + tenantService.checkSsoNotRequired(username) + val userAccount = userAccountService.findActive(username) ?: throw AuthenticationException(Message.BAD_CREDENTIALS) diff --git a/ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SsoProviderController.kt b/ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SsoProviderController.kt index 0efe8784e5..96d8f4c841 100644 --- a/ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SsoProviderController.kt +++ b/ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SsoProviderController.kt @@ -1,6 +1,7 @@ package io.tolgee.ee.api.v2.controllers import io.tolgee.component.enabledFeaturesProvider.EnabledFeaturesProvider +import io.tolgee.configuration.tolgee.TolgeeProperties import io.tolgee.constants.Feature import io.tolgee.constants.Message import io.tolgee.dtos.sso.SsoTenantDto @@ -9,6 +10,7 @@ import io.tolgee.ee.api.v2.hateoas.assemblers.SsoTenantAssembler import io.tolgee.ee.data.CreateProviderRequest import io.tolgee.exceptions.BadRequestException import io.tolgee.exceptions.NotFoundException +import io.tolgee.exceptions.PermissionException import io.tolgee.hateoas.ee.SsoTenantModel import io.tolgee.model.SsoTenant import io.tolgee.model.enums.OrganizationRoleType @@ -27,6 +29,7 @@ class SsoProviderController( private val ssoTenantAssembler: SsoTenantAssembler, private val enabledFeaturesProvider: EnabledFeaturesProvider, private val organizationService: OrganizationService, + private val properties: TolgeeProperties, ) { @RequiresOrganizationRole(role = OrganizationRoleType.OWNER) @PutMapping("") @@ -42,6 +45,10 @@ class SsoProviderController( Feature.SSO, ) + if (request.enabled && properties.authentication.ssoOrganizations.isAllowed(request.domain)) { + throw PermissionException(Message.SSO_DOMAIN_NOT_ALLOWED) + } + val organization = organizationService.get(organizationId) return ssoTenantAssembler.toModel(tenantService.createOrUpdate(request.toDto(), organization).toDto()) } diff --git a/ee/backend/app/src/main/kotlin/io/tolgee/ee/service/sso/TenantServiceImpl.kt b/ee/backend/app/src/main/kotlin/io/tolgee/ee/service/sso/TenantServiceImpl.kt index 5e661eb9bd..d704e41c90 100644 --- a/ee/backend/app/src/main/kotlin/io/tolgee/ee/service/sso/TenantServiceImpl.kt +++ b/ee/backend/app/src/main/kotlin/io/tolgee/ee/service/sso/TenantServiceImpl.kt @@ -18,18 +18,22 @@ class TenantServiceImpl( private val tenantRepository: TenantRepository, private val properties: TolgeeProperties, ) : TenantService { - override fun getEnabledConfigByDomain(domain: String): SsoTenantConfig { + override fun getEnabledConfigByDomainOrNull(domain: String): SsoTenantConfig? { return properties.authentication.ssoGlobal .takeIf { it.enabled && domain == it.domain } ?.let { ssoTenantProperties -> SsoTenantConfig(ssoTenantProperties, null) } ?: domain .takeIf { properties.authentication.ssoOrganizations.enabled } + ?.takeIf { properties.authentication.ssoOrganizations.isAllowed(it) } ?.let { tenantRepository.findEnabledByDomain(it)?.let { ssoTenantEntity -> SsoTenantConfig(ssoTenantEntity, ssoTenantEntity.organization) } } - ?: throw NotFoundException(Message.SSO_DOMAIN_NOT_FOUND_OR_DISABLED) + } + + override fun getEnabledConfigByDomain(domain: String): SsoTenantConfig { + return getEnabledConfigByDomainOrNull(domain) ?: throw NotFoundException(Message.SSO_DOMAIN_NOT_FOUND_OR_DISABLED) } override fun save(tenant: SsoTenant): SsoTenant = tenantRepository.save(tenant) diff --git a/webapp/src/globalContext/useAuthService.tsx b/webapp/src/globalContext/useAuthService.tsx index f959fe0bca..0e2c8eb548 100644 --- a/webapp/src/globalContext/useAuthService.tsx +++ b/webapp/src/globalContext/useAuthService.tsx @@ -203,6 +203,14 @@ export const useAuthService = ( authProviderChange, }; + async function loginRedirectSso(domain: string) { + localStorage.setItem(LOCAL_STORAGE_DOMAIN_KEY, domain || ''); + const state = uuidv4(); + localStorage.setItem(LOCAL_STORAGE_STATE_KEY, state); + const response = await getSsoAuthLinkByDomain(domain, state); + window.location.href = response.redirectUrl; + } + const actions = { async login(credentials: LoginRequest) { const response = await loginLoadable.mutateAsync( @@ -214,6 +222,9 @@ export const useAuthService = ( if (error.code === 'third_party_switch_initiated') { setAuthProviderChange(true); } + if (error.code === 'sso_login_forced_for_this_account') { + loginRedirectSso(error.params?.[0]); + } }, } ); @@ -242,19 +253,16 @@ export const useAuthService = ( if (error.code === 'invitation_code_does_not_exist_or_expired') { setInvitationCode(undefined); } + if (error.code === 'sso_login_forced_for_this_account') { + loginRedirectSso(error.params?.[0]); + } }, } ); setInvitationCode(undefined); await handleAfterLogin(response!); }, - async loginRedirectSso(domain: string) { - localStorage.setItem(LOCAL_STORAGE_DOMAIN_KEY, domain || ''); - const state = uuidv4(); - localStorage.setItem(LOCAL_STORAGE_STATE_KEY, state); - const response = await getSsoAuthLinkByDomain(domain, state); - window.location.href = response.redirectUrl; - }, + loginRedirectSso, getLastSsoDomain, async signUp(data: Omit) { signupLoadable.mutate( diff --git a/webapp/src/translationTools/useErrorTranslation.ts b/webapp/src/translationTools/useErrorTranslation.ts index 567ca1586f..1a4dd2b865 100644 --- a/webapp/src/translationTools/useErrorTranslation.ts +++ b/webapp/src/translationTools/useErrorTranslation.ts @@ -159,6 +159,10 @@ export function useErrorTranslation() { return t('namespace_cannot_be_used_when_feature_is_disabled'); case 'namespaces_cannot_be_disabled_when_namespace_exists': return t('namespaces_cannot_be_disabled_when_namespace_exists'); + case 'sso_domain_not_allowed': + return t('sso_domain_not_allowed'); + case 'sso_login_forced_for_this_account': + return t('sso_login_forced_for_this_account'); default: return code; }