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 267f935f13..18d41533e4 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 @@ -8,13 +8,12 @@ import io.tolgee.exceptions.AuthenticationException import io.tolgee.model.UserAccount import io.tolgee.model.enums.ThirdPartyAuthType import io.tolgee.security.thirdParty.data.OAuthUserDetails -import io.tolgee.service.AuthProviderChangeRequestService import io.tolgee.service.organization.OrganizationRoleService import io.tolgee.service.security.SignUpService import io.tolgee.service.security.UserAccountService import io.tolgee.util.addMinutes import org.springframework.stereotype.Component -import java.util.Date +import java.util.* @Component class OAuthUserHandler( @@ -24,8 +23,6 @@ class OAuthUserHandler( private val ssoGlobalProperties: SsoGlobalProperties, private val userAccountService: UserAccountService, private val currentDateProvider: CurrentDateProvider, - private val authenticationProperties: AuthenticationProperties, - private val authProviderChangeRequestService: AuthProviderChangeRequestService, private val userConflictManager: UserConflictManager, ) { fun findOrCreateUser( @@ -114,26 +111,10 @@ class OAuthUserHandler( userResponse.tenant?.domain, userResponse.sub, userResponse.refreshToken, - calculateExpirationDate(), + ssoCurrentExpiration(thirdPartyAuthType), ) } - private fun changeAuthProvider( - user: UserAccount, - thirdPartyAuthType: ThirdPartyAuthType, - userDetails: OAuthUserDetails, - ): UserAccount { - user.thirdPartyAuthType = thirdPartyAuthType - user.accountType = UserAccount.AccountType.THIRD_PARTY - user.thirdPartyAuthId = userDetails.sub - user.ssoTenant = userDetails.tenant - if (thirdPartyAuthType == ThirdPartyAuthType.SSO) { - updateRefreshToken(user, userDetails.refreshToken) - updateSsoSessionExpiry(user) - } - return userAccountService.save(user) - } - fun updateRefreshToken( userAccount: UserAccount, refreshToken: String?, diff --git a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/UserConflictManager.kt b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/UserConflictManager.kt index 3973afcb9c..26ddd6521c 100644 --- a/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/UserConflictManager.kt +++ b/backend/api/src/main/kotlin/io/tolgee/security/thirdParty/UserConflictManager.kt @@ -37,7 +37,7 @@ class UserConflictManager( calculateExpirationDate = calculateExpirationDate, ) val request = authProviderChangeRequestService.create(requestData) - throw AuthenticationException(Message.USERNAME_ALREADY_EXISTS, listOf(request?.id)) + throw AuthenticationException(Message.USERNAME_ALREADY_EXISTS, params = listOf(request?.id)) } fun resolveRequestIfExist(user: Optional) { diff --git a/backend/app/src/test/kotlin/io/tolgee/ChangeAuthTypeTest.kt b/backend/app/src/test/kotlin/io/tolgee/ChangeAuthTypeTest.kt index 0dcd4be983..10f8ea0c5d 100644 --- a/backend/app/src/test/kotlin/io/tolgee/ChangeAuthTypeTest.kt +++ b/backend/app/src/test/kotlin/io/tolgee/ChangeAuthTypeTest.kt @@ -5,10 +5,12 @@ import com.fasterxml.jackson.module.kotlin.readValue import com.nimbusds.jose.proc.SecurityContext import com.nimbusds.jwt.proc.ConfigurableJWTProcessor import io.tolgee.configuration.tolgee.SsoGlobalProperties +import io.tolgee.constants.Feature import io.tolgee.constants.Message import io.tolgee.development.testDataBuilder.data.ChangeAuthTypeTestData import io.tolgee.dtos.request.AuthProviderChangeRequestDto -import io.tolgee.ee.service.TenantService +import io.tolgee.ee.component.PublicEnabledFeaturesProvider +import io.tolgee.ee.service.sso.TenantService import io.tolgee.model.UserAccount import io.tolgee.model.enums.ThirdPartyAuthType import io.tolgee.service.AuthProviderChangeRequestService @@ -56,10 +58,14 @@ class ChangeAuthTypeTest : AbstractControllerTest() { private val googleAuthUtil: GoogleAuthUtil by lazy { GoogleAuthUtil(tolgeeProperties, authMvc, restTemplate) } private val ssoUtil: SsoAuthUtil by lazy { SsoAuthUtil(authMvc, restTemplate, tenantService, jwtProcessor) } + @Autowired + private lateinit var enabledFeaturesProvider: PublicEnabledFeaturesProvider + @BeforeAll fun init() { changeAuthTypeTestData = ChangeAuthTypeTestData() testDataService.saveTestData(changeAuthTypeTestData.root) + enabledFeaturesProvider.forceEnabled = setOf(Feature.SSO) } @Test @@ -192,9 +198,9 @@ class ChangeAuthTypeTest : AbstractControllerTest() { assertThat(successResponse.status).isEqualTo(200) user = userAccountService.get(googleAuthUtil.userResponseWithExisingEmail.email!!) - assertThat(user.thirdPartyAuthType).isEqualTo(ThirdPartyAuthType.SSO) + assertThat(user.thirdPartyAuthType).isEqualTo(ThirdPartyAuthType.SSO_GLOBAL) assertThat(user.accountType).isEqualTo(UserAccount.AccountType.THIRD_PARTY) - assertThat(user.ssoTenant?.domain).isEqualTo(domain) + //assertThat(user.ssoTenant?.domain).isEqualTo(domain) assertThat(user.ssoSessionExpiry).isNotNull() assertThat(user.ssoRefreshToken).isNotNull() } @@ -220,9 +226,9 @@ class ChangeAuthTypeTest : AbstractControllerTest() { doAuthentication(changeAuthTypeTestData.userExisting.username, "admin") val user = userAccountService.get(changeAuthTypeTestData.userExisting.username) - assertThat(user.thirdPartyAuthType).isEqualTo(ThirdPartyAuthType.SSO) + assertThat(user.thirdPartyAuthType).isEqualTo(ThirdPartyAuthType.SSO_GLOBAL) assertThat(user.accountType).isEqualTo(UserAccount.AccountType.THIRD_PARTY) - assertThat(user.ssoTenant?.domain).isEqualTo(domain) + //assertThat(user.ssoTenant?.domain).isEqualTo(domain) assertThat(user.ssoSessionExpiry).isNotNull() assertThat(user.ssoRefreshToken).isNotNull() } @@ -232,8 +238,8 @@ class ChangeAuthTypeTest : AbstractControllerTest() { ssoGlobalProperties.domain = domain ssoGlobalProperties.clientId = "clientId" ssoGlobalProperties.clientSecret = "clientSecret" - ssoGlobalProperties.authorizationUrl = "authorizationUri" - ssoGlobalProperties.tokenUrl = "http://tokenUri" + ssoGlobalProperties.authorizationUri = "authorizationUri" + ssoGlobalProperties.tokenUri = "http://tokenUri" ssoGlobalProperties.jwkSetUri = "http://jwkSetUri" } diff --git a/backend/app/src/test/kotlin/io/tolgee/util/SsoAuthUtil.kt b/backend/app/src/test/kotlin/io/tolgee/util/SsoAuthUtil.kt index ba0c2cacb4..4cbc443d3f 100644 --- a/backend/app/src/test/kotlin/io/tolgee/util/SsoAuthUtil.kt +++ b/backend/app/src/test/kotlin/io/tolgee/util/SsoAuthUtil.kt @@ -8,7 +8,7 @@ import com.nimbusds.jwt.JWTClaimsSet import com.nimbusds.jwt.SignedJWT import com.nimbusds.jwt.proc.ConfigurableJWTProcessor import io.tolgee.ee.data.OAuth2TokenResponse -import io.tolgee.ee.service.TenantService +import io.tolgee.ee.service.sso.TenantService import org.mockito.kotlin.any import org.mockito.kotlin.eq import org.mockito.kotlin.isNull @@ -93,7 +93,7 @@ class SsoAuthUtil( jwtClaims: JWTClaimsSet = jwtClaimsSet, ): MvcResult { val receivedCode = "fake_access_token" - val tenant = tenantService?.getByDomain(registrationId)!! + val tenant = tenantService?.getEnabledConfigByDomain(registrationId)!! // mock token exchange whenever( restTemplate?.exchange( @@ -110,7 +110,7 @@ class SsoAuthUtil( return authMvc!! .perform( MockMvcRequestBuilders.get( - "/v2/public/oauth2/callback/$registrationId?code=$receivedCode&redirect_uri=redirect_uri", + "/api/public/authorize_oauth/sso?code=$receivedCode&redirect_uri=redirect_uri&domain=$registrationId", ), ).andReturn() } diff --git a/backend/data/src/main/kotlin/io/tolgee/exceptions/AuthenticationException.kt b/backend/data/src/main/kotlin/io/tolgee/exceptions/AuthenticationException.kt index c026acc16a..9ff5d7fef4 100644 --- a/backend/data/src/main/kotlin/io/tolgee/exceptions/AuthenticationException.kt +++ b/backend/data/src/main/kotlin/io/tolgee/exceptions/AuthenticationException.kt @@ -6,9 +6,8 @@ import org.springframework.web.bind.annotation.ResponseStatus import java.io.Serializable @ResponseStatus(HttpStatus.UNAUTHORIZED) -open class AuthenticationException(message: Message) : ErrorException(message) { -class AuthenticationException( - message: io.tolgee.constants.Message, +open class AuthenticationException( + message: Message, params: List? = null, ) : ErrorException(message, params) { override val httpStatus: HttpStatus diff --git a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt index cfce1ef0d5..56e570b9a1 100644 --- a/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt +++ b/backend/data/src/main/kotlin/io/tolgee/model/UserAccount.kt @@ -8,24 +8,12 @@ import io.tolgee.model.enums.ThirdPartyAuthType import io.tolgee.model.slackIntegration.SlackConfig import io.tolgee.model.slackIntegration.SlackUserConnection import io.tolgee.model.task.Task -import jakarta.persistence.CascadeType -import jakarta.persistence.Column -import jakarta.persistence.Convert -import jakarta.persistence.Entity -import jakarta.persistence.EnumType -import jakarta.persistence.Enumerated -import jakarta.persistence.FetchType -import jakarta.persistence.GeneratedValue -import jakarta.persistence.GenerationType -import jakarta.persistence.Id -import jakarta.persistence.ManyToMany -import jakarta.persistence.OneToMany -import jakarta.persistence.OneToOne -import jakarta.persistence.OrderBy +import jakarta.persistence.* import jakarta.validation.constraints.NotBlank import org.hibernate.annotations.ColumnDefault import org.hibernate.annotations.Type import java.util.* +import kotlin.jvm.Transient @Entity @ActivityLoggedEntity @@ -66,9 +54,6 @@ data class UserAccount( @OneToOne(mappedBy = "userAccount") var authProviderChangeRequest: AuthProviderChangeRequest? = null - @ManyToOne - var ssoTenant: SsoTenant? = null - @Column(name = "sso_refresh_token", columnDefinition = "TEXT") var ssoRefreshToken: String? = null diff --git a/backend/data/src/main/kotlin/io/tolgee/service/AuthProviderChangeRequestService.kt b/backend/data/src/main/kotlin/io/tolgee/service/AuthProviderChangeRequestService.kt index 77f89d18c7..5d10811a2f 100644 --- a/backend/data/src/main/kotlin/io/tolgee/service/AuthProviderChangeRequestService.kt +++ b/backend/data/src/main/kotlin/io/tolgee/service/AuthProviderChangeRequestService.kt @@ -8,20 +8,15 @@ import io.tolgee.model.AuthProviderChangeRequest import io.tolgee.model.UserAccount import io.tolgee.repository.AuthProviderChangeRequestRepository import io.tolgee.service.security.UserAccountService -import jakarta.persistence.EntityManager import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Propagation import org.springframework.transaction.annotation.Transactional -import org.springframework.transaction.support.TransactionTemplate import java.util.* @Service class AuthProviderChangeRequestService( private val authProviderChangeRequestRepository: AuthProviderChangeRequestRepository, private val userAccountService: UserAccountService, - private val tenantService: EeSsoTenantService, - private val transactionTemplate: TransactionTemplate, - private val entityManager: EntityManager, ) { fun getById(id: Long): AuthProviderChangeRequest = findById(id).orElseGet { throw NotFoundException() } @@ -75,12 +70,6 @@ class AuthProviderChangeRequestService( authProviderChangeRequestRepository.findByUserAccountAndIsConfirmed(userAccount, true).ifPresent { userAccount.accountType = it.newAccountType userAccount.thirdPartyAuthType = it.newAuthProvider - userAccount.ssoTenant = - if (it.newSsoDomain != null) { - tenantService.getByDomain(it.newSsoDomain!!) - } else { - null - } userAccount.thirdPartyAuthId = it.newSub userAccount.ssoRefreshToken = it.ssoRefreshToken userAccount.ssoSessionExpiry = it.ssoExpiration diff --git a/ee/backend/app/src/main/kotlin/io/tolgee/ee/service/sso/TenantService.kt b/ee/backend/app/src/main/kotlin/io/tolgee/ee/service/sso/TenantService.kt index 68b4354a38..e21fab3953 100644 --- a/ee/backend/app/src/main/kotlin/io/tolgee/ee/service/sso/TenantService.kt +++ b/ee/backend/app/src/main/kotlin/io/tolgee/ee/service/sso/TenantService.kt @@ -10,6 +10,7 @@ import io.tolgee.model.SsoTenant import io.tolgee.repository.TenantRepository import io.tolgee.security.thirdParty.SsoTenantConfig import io.tolgee.security.thirdParty.SsoTenantConfig.Companion.toConfig +import io.tolgee.service.EeSsoTenantService import org.springframework.stereotype.Service @Service @@ -17,10 +18,10 @@ class TenantService( private val tenantRepository: TenantRepository, private val ssoGlobalProperties: SsoGlobalProperties, private val ssoLocalProperties: SsoLocalProperties, -) { +) : EeSsoTenantService{ fun getById(id: Long): SsoTenant = tenantRepository.findById(id).orElseThrow { NotFoundException() } - fun getByDomain(domain: String): SsoTenant { + override fun getByDomain(domain: String): SsoTenant { return tenantRepository.findByDomain(domain) ?: throw NotFoundException() }