Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow change auth provider #2682

Open
wants to merge 168 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
168 commits
Select commit Hold shift + click to select a range
a52e18e
feat: create dynamic client registration
huglx Sep 2, 2024
278aa62
feat: Add a tenant to configure the dynamic configuration of providers.
huglx Sep 2, 2024
140c6df
feat: Add a controller to fetch callbacks from the provider and retur…
huglx Sep 2, 2024
b5e75b9
feat: Add a controller to dynamically configure providers
huglx Sep 2, 2024
f7b8c0a
feat: add sso login to FE
huglx Sep 2, 2024
4a14242
fix: move auth logic from controller to service
huglx Sep 6, 2024
8302d33
feat: add custom exceptions
huglx Sep 6, 2024
10a70b7
fix: add component annotation
huglx Sep 6, 2024
ac291db
feat: save domain with port if presents
huglx Sep 6, 2024
1143485
fix: change url
huglx Sep 6, 2024
d8dfdb8
fix: add more properties CreateProviderRequest
huglx Sep 6, 2024
e6a8cd3
fix: The function wasn't marked as a transaction, so it caused a data…
huglx Sep 8, 2024
fccbe74
feat: add an ability to accept invitation code to backend part
huglx Sep 11, 2024
de3cd3c
feat: add properties to enable custom logo & button text
huglx Sep 11, 2024
8d285fa
feat: add create sso provider route
huglx Sep 12, 2024
e866ebb
feat: add an ability to set custom login logo to FE
huglx Sep 12, 2024
10f4022
feat: add create sso provider links
huglx Sep 12, 2024
c468f2c
feat: pass invitationCode to BE
huglx Sep 12, 2024
bf60293
feat: display saved provider on FE
huglx Sep 16, 2024
b7297a0
feat: verify id token to improve security
huglx Sep 17, 2024
45acdfe
feat: disable/enable sso provider FE
huglx Sep 24, 2024
f1e4999
feat: also set jwk uri in ClientRegistration
huglx Sep 24, 2024
0477f25
feat: now a new user logged in via sso is a member of the organizatio…
huglx Oct 6, 2024
8a83e52
feat: refactor login form FE
huglx Oct 6, 2024
0cc553d
feat: enable/disable provider
huglx Oct 6, 2024
d21a845
feat: add function to add user to the org.
huglx Oct 6, 2024
c906b4e
feat: throw if sso provider is disabled
huglx Oct 6, 2024
40e444d
fix: code clean up
huglx Oct 6, 2024
e494b5c
chore: test
huglx Oct 6, 2024
fdfa217
feat: configuration to parse jwt token
huglx Oct 6, 2024
d0f9cb1
feat: generate ee db schema
huglx Oct 6, 2024
86a37dc
Merge remote-tracking branch 'origin/main' into ivanmanzhosov/sso-pro…
huglx Oct 6, 2024
ca6836b
feat: generate FE api schema
huglx Oct 6, 2024
31fef0c
feat: save or update provider
huglx Oct 6, 2024
9d832f0
fix: npm run prettier
huglx Oct 6, 2024
be3754c
fix: ktlint
huglx Oct 6, 2024
43b4d4a
fix: npm run prettier
huglx Oct 6, 2024
4311e68
fix: BE build
huglx Oct 6, 2024
56815f3
fix: fet rid of calling static function
huglx Oct 8, 2024
90dfeda
chore: mock everything for tests
huglx Oct 8, 2024
c02388f
fix: rename, add policy to provider's controller
huglx Oct 8, 2024
a2e70e3
fix: rename oauth2 endpoint
huglx Oct 8, 2024
bc14f1b
fix: code clean up
huglx Oct 8, 2024
a63094f
fix: use Model & ModelAssembler approach
huglx Oct 8, 2024
2b1f8c7
fix: add RequiresSuperAuthentication and change url on FE
huglx Oct 11, 2024
e943634
feat: add sso form validation
huglx Oct 11, 2024
a1c92d0
fix: refactor tenant Service
huglx Oct 11, 2024
22e6462
fix: refactor oauth service and delegate
huglx Oct 11, 2024
9069401
fix: move data class to data package
huglx Oct 11, 2024
e39a9e7
fix: delete timestamp file
huglx Oct 11, 2024
b5a7b0d
fix: edit new url on FE
huglx Oct 11, 2024
036be10
fix: npm run prettier
huglx Oct 11, 2024
333739a
fix: move dto to data package
huglx Oct 11, 2024
682a9d6
fix: rename FE link
huglx Oct 11, 2024
8b39bcc
fix: refactor auth service FE
huglx Oct 11, 2024
ccebc56
fix: refactor provider form and view
huglx Oct 11, 2024
156afd3
fix: add sso_domain in user account
huglx Oct 11, 2024
726b5ea
fix: refactor sso provider form
huglx Oct 11, 2024
d36d18c
fix: now user must type his domain
huglx Oct 11, 2024
d7f5ec5
fix: rephrase description in auth props, use local icon instead of re…
huglx Oct 11, 2024
098c602
fix: rename error messages
huglx Oct 11, 2024
2fb5794
fix: code format
huglx Oct 11, 2024
9d14caa
fix: ktlint fix
huglx Oct 11, 2024
be5752d
fix: eslint
huglx Oct 11, 2024
af7cc92
fix: eslint
huglx Oct 11, 2024
53c5735
fix: rename sso provider url
huglx Oct 13, 2024
b64d790
chore: add sso controller tests
huglx Oct 13, 2024
eaaa364
chore: add sso auth tests
huglx Oct 13, 2024
48f1e19
chore: add simple e2e test
huglx Oct 13, 2024
c965f20
fix: regenerate schema
huglx Oct 13, 2024
915a774
fix: FE prettier
huglx Oct 13, 2024
d879d48
fix: FE prettier
huglx Oct 13, 2024
0a4b9e1
fix: BE code format
huglx Oct 13, 2024
1ba0902
fix: rename link
huglx Oct 14, 2024
481d3f6
fix: rename static link
huglx Oct 14, 2024
4e9d32e
fix: rename static link e2e
huglx Oct 14, 2024
ad236eb
fix: remove unused code
huglx Oct 14, 2024
560bd01
fix: decode/encode domain in url
huglx Oct 14, 2024
41e9334
fix: store domain in localstorage instead of passing throw url
huglx Oct 14, 2024
abb886d
fix: remove unused code
huglx Oct 15, 2024
72ba29a
fix: FE prettier
huglx Oct 15, 2024
f537f59
fix: FE prettier
huglx Oct 15, 2024
923cf48
fit: remove score role from auth request
huglx Oct 18, 2024
1493068
feat: do not create user's organization on sso login
huglx Oct 21, 2024
ebec37e
chore: test sso login doesnt create user's organization
huglx Oct 21, 2024
1d7061b
feat: check if organization has sso feature
huglx Oct 21, 2024
642d6fd
feat: show banner if user doesnt have feature enabled
huglx Oct 21, 2024
1dee374
fix: prettier
huglx Oct 21, 2024
a3d655e
fix: add sso feature message
huglx Oct 21, 2024
0672f26
fix: renaming
huglx Oct 21, 2024
72b531e
fix: prettier
huglx Oct 21, 2024
f232ae6
fix: prettier
huglx Oct 21, 2024
61e5fd3
fix: remove scope
huglx Oct 21, 2024
ac207b6
feat: prevent sso user from create organizations
huglx Oct 22, 2024
53df0c0
fix: if it's sso user find by sso domain
huglx Oct 22, 2024
b8a4962
fix: change default sso login logo
huglx Oct 22, 2024
af85aff
feat: add sso valid user cache
huglx Oct 25, 2024
284d7a6
feat: add validation that user is still an employee
huglx Oct 25, 2024
e73c0aa
chore: test new validation
huglx Oct 25, 2024
6c0b685
feat: move ssoDomain from UserAccount to separate entity
huglx Oct 26, 2024
fc83174
chore: update tests
huglx Oct 26, 2024
b69c9b6
fix: use enum as ThirdPartyAuthType instead of string
huglx Oct 26, 2024
ffdcbe4
feat: prevent sso user to login
huglx Oct 26, 2024
c77ee5e
feat: prevent sso user to change password
huglx Oct 26, 2024
370a51e
feat: add global sso config
huglx Oct 27, 2024
b9681d3
chore: test global sso config
huglx Oct 27, 2024
e046416
fix: use frontend url from config, instead of saving it to db
huglx Oct 29, 2024
873324d
fix: use frontend url from config, instead of saving it to db
huglx Oct 29, 2024
a960a6c
chore: update tests
huglx Oct 29, 2024
2397931
chore: update docs property descriptions
huglx Oct 29, 2024
1cfa8df
chore: fix ktlint
huglx Oct 29, 2024
86ae87b
Merge pull request #2523 from tolgee/ivanmanzhosov/sso
Anty0 Oct 31, 2024
4914735
chore: move SsoTenant from ee repo, link user account and SsoTenant, …
huglx Nov 1, 2024
4b30714
chore: rename ssoTenant column
huglx Nov 1, 2024
44e7167
chore: rename OAuthService's function
huglx Nov 1, 2024
df24981
fix: use @Convert instead of @Enumerated to avoid incompatibility wit…
huglx Nov 1, 2024
5c77185
fix: use getEnabledByDomain instead of getByDomain to prevent using d…
huglx Nov 1, 2024
adb316d
fix: throw if native auth is disabled and login endpoint is called
huglx Nov 1, 2024
a7b2f26
chore: code cleaning
huglx Nov 1, 2024
0d88bda
fix: validate thirdPartyAuth type and handle invalid values as bad re…
huglx Nov 1, 2024
26df30a
fix: use cacheable user entity to validate sso user instead of cache …
huglx Nov 1, 2024
1c63119
fix: save global tenant in db
huglx Nov 1, 2024
4e99ce0
feat: dont auth user if it's global sso and there is no invite code
huglx Nov 1, 2024
ba4eccf
fix: add validation
huglx Nov 1, 2024
ce3bf2b
fix: ktlint check
huglx Nov 1, 2024
593f746
fix: ktlint check
huglx Nov 1, 2024
22bd59b
chore: update SsoProviderControllerTest
huglx Nov 1, 2024
5eb67cd
Merge pull request #2667 from tolgee/ivanmanzhosov/sso
Anty0 Nov 4, 2024
bfabcaf
feat: use managed accounts for sso instead of handling sso as a separ…
Anty0 Nov 1, 2024
6816c47
fix: sso license check handling
Anty0 Nov 1, 2024
ccec98b
feat: better handling of reset passowrd request for sso accounts
Anty0 Nov 1, 2024
680576d
fix: mark some functions private
Anty0 Nov 1, 2024
bbebb28
fix: lint
Anty0 Nov 1, 2024
1668eca
fix: catch correct exception
Anty0 Nov 1, 2024
563a09d
fix: build issues after rebase
Anty0 Nov 4, 2024
daf0bfb
Merge pull request #2665 from tolgee/jirikuchynka/sso
Anty0 Nov 4, 2024
e56d99c
fix: initial refractoring and structure finalization
Anty0 Nov 6, 2024
6267408
fix: configuration handling improvements
Anty0 Nov 6, 2024
5f02cc1
fix: test build
Anty0 Nov 6, 2024
4249520
Merge remote-tracking branch 'origin/main' into jirikuchynka/sso
Anty0 Nov 6, 2024
ea07d4f
fix: frontend lint
Anty0 Nov 7, 2024
52b28aa
fix: regenerate db schema migrations
Anty0 Nov 7, 2024
15bf5d6
fix: frontend stucture + organization create premissions handling
Anty0 Nov 7, 2024
6d8dd2c
fix: revert unwanted change
Anty0 Nov 7, 2024
e727670
fix: merge sso service and auth service on FE side + use proper loada…
Anty0 Nov 7, 2024
b738129
fix: small fixes and notes
Anty0 Nov 7, 2024
ee4221f
feat: wip - sso finalizace
Anty0 Nov 11, 2024
26ac923
Merge pull request #2671 from tolgee/jirikuchynka/sso
Anty0 Nov 12, 2024
ffe9bb3
feat: add entity to save auth change request
huglx Nov 8, 2024
d269a0f
chore: rebase
huglx Nov 8, 2024
ddc0a56
feat: add public endpoints to manage request
huglx Nov 8, 2024
7ff0425
feat: add params to auth exception
huglx Nov 8, 2024
740fc7e
feat: add an interface to the tenant service to use outside of the ee…
huglx Nov 8, 2024
22de5d9
feat: add view to show user request
huglx Nov 8, 2024
cf7120c
feat: redirect user to ChangeAuthProviderView if catch auth exception
huglx Nov 8, 2024
df5a599
feat: add CHANGE_AUTH_PROVIDER link
huglx Nov 8, 2024
e6de954
feat: add CHANGE_AUTH_PROVIDER route
huglx Nov 8, 2024
dfc708f
feat: add function for redirecting
huglx Nov 8, 2024
0466810
feat: add link between UserAccount and AuthProviderChangeRequest
huglx Nov 8, 2024
3097bee
fix: change logic of changing provider
huglx Nov 11, 2024
7e35d3c
fix: change logic of changing provider
huglx Nov 11, 2024
d40e55e
chore: test new behaviour
huglx Nov 11, 2024
95e11c2
chore: test new behaviour
huglx Nov 11, 2024
de625ec
chore: generate schemas
huglx Nov 11, 2024
6426f6f
chore: ktlint
huglx Nov 11, 2024
9f10844
chore: npm prettier
huglx Nov 11, 2024
3489408
fix: update code after rebase
huglx Nov 12, 2024
c7fdba5
fix: update code after rebase
huglx Nov 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import io.tolgee.model.Project
import io.tolgee.model.UserAccount
import io.tolgee.model.enums.OrganizationRoleType
import io.tolgee.model.enums.ProjectPermissionType
import io.tolgee.model.enums.ThirdPartyAuthType
import io.tolgee.model.views.UserAccountWithOrganizationRoleView
import io.tolgee.openApiDocs.OpenApiOrderExtension
import io.tolgee.security.authentication.AllowApiAccess
Expand Down Expand Up @@ -108,6 +109,11 @@ class OrganizationController(
) {
throw PermissionException()
}
if (authenticationFacade.authenticatedUserEntity.thirdPartyAuthType === ThirdPartyAuthType.SSO &&
authenticationFacade.authenticatedUser.role != UserAccount.Role.ADMIN
) {
throw PermissionException(Message.SSO_USER_CANNOT_CREATE_ORGANIZATION)
}
this.organizationService.create(dto).let {
return ResponseEntity(
organizationModelAssembler.toModel(OrganizationView.of(it, OrganizationRoleType.OWNER)),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.tolgee.configuration

import io.swagger.v3.oas.annotations.media.Schema
import io.tolgee.configuration.tolgee.AuthenticationProperties
import io.tolgee.configuration.tolgee.TolgeeProperties
import io.tolgee.constants.FileStoragePath
import io.tolgee.constants.MtServiceType
Expand All @@ -14,9 +15,11 @@ class PublicConfigurationDTO(
val version: String,
) {
val authentication: Boolean = properties.authentication.enabled
var authMethods: AuthMethodsDTO? = null
val passwordResettable: Boolean
val allowRegistrations: Boolean
val authMethods: AuthMethodsDTO? = properties.authentication.asAuthMethodsDTO()

@Deprecated("Use nativeEnabled instead", ReplaceWith("nativeEnabled"))
val passwordResettable: Boolean = properties.authentication.nativeEnabled
val allowRegistrations: Boolean = properties.authentication.registrationsAllowed
val screenshotsUrl = properties.fileStorageUrl + "/" + FileStoragePath.SCREENSHOTS
val maxUploadFileSize = properties.maxUploadFileSize
val clientSentryDsn = properties.sentry.clientDsn
Expand All @@ -28,6 +31,7 @@ class PublicConfigurationDTO(
val maxTranslationTextLength: Long = properties.maxTranslationTextLength
val recaptchaSiteKey = properties.recaptcha.siteKey
val chatwootToken = properties.chatwootToken
val nativeEnabled = properties.authentication.nativeEnabled
val capterraTracker = properties.capterraTracker
val ga4Tag = properties.ga4Tag
val postHogApiKey: String? = properties.postHog.apiKey
Expand All @@ -50,10 +54,40 @@ class PublicConfigurationDTO(
connected = properties.slack.token != null,
)

companion object {
private fun AuthenticationProperties.asAuthMethodsDTO(): AuthMethodsDTO? {
if (!enabled) {
return null
}

return AuthMethodsDTO(
OAuthPublicConfigDTO(github.clientId),
OAuthPublicConfigDTO(google.clientId),
OAuthPublicExtendsConfigDTO(
oauth2.clientId,
oauth2.authorizationUrl,
oauth2.scopes,
),
SsoGlobalPublicConfigDTO(
ssoGlobal.enabled,
ssoGlobal.clientId,
ssoGlobal.domain,
ssoGlobal.customLogoUrl,
ssoGlobal.customLoginText,
),
SsoOrganizationsPublicConfigDTO(
ssoOrganizations.enabled,
),
)
}
}

class AuthMethodsDTO(
val github: OAuthPublicConfigDTO,
val google: OAuthPublicConfigDTO,
val oauth2: OAuthPublicExtendsConfigDTO,
val ssoGlobal: SsoGlobalPublicConfigDTO,
val ssoOrganizations: SsoOrganizationsPublicConfigDTO,
)

data class OAuthPublicConfigDTO(val clientId: String?) {
Expand All @@ -68,6 +102,18 @@ class PublicConfigurationDTO(
val enabled: Boolean = !clientId.isNullOrEmpty()
}

data class SsoGlobalPublicConfigDTO(
val enabled: Boolean,
val clientId: String?,
val domain: String?,
val customLogoUrl: String?,
val customLoginText: String?,
)

data class SsoOrganizationsPublicConfigDTO(
val enabled: Boolean,
)

data class MtServicesDTO(
val defaultPrimaryService: MtServiceType?,
val services: Map<MtServiceType, MtServiceDTO>,
Expand All @@ -82,23 +128,4 @@ class PublicConfigurationDTO(
val enabled: Boolean,
val connected: Boolean,
)

init {
if (authentication) {
authMethods =
AuthMethodsDTO(
OAuthPublicConfigDTO(
properties.authentication.github.clientId,
),
OAuthPublicConfigDTO(properties.authentication.google.clientId),
OAuthPublicExtendsConfigDTO(
properties.authentication.oauth2.clientId,
properties.authentication.oauth2.authorizationUrl,
properties.authentication.oauth2.scopes,
),
)
}
passwordResettable = properties.authentication.nativeEnabled
allowRegistrations = properties.authentication.registrationsAllowed
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,38 @@ import com.fasterxml.jackson.databind.node.TextNode
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import io.tolgee.component.email.TolgeeEmailSender
import io.tolgee.configuration.tolgee.AuthenticationProperties
import io.tolgee.configuration.tolgee.TolgeeProperties
import io.tolgee.constants.Message
import io.tolgee.dtos.misc.EmailParams
import io.tolgee.dtos.request.AuthProviderChangeRequestDto
import io.tolgee.dtos.request.auth.ResetPassword
import io.tolgee.dtos.request.auth.ResetPasswordRequest
import io.tolgee.dtos.request.auth.SignUpDto
import io.tolgee.dtos.response.AuthProviderChangeResponseDto
import io.tolgee.dtos.security.LoginRequest
import io.tolgee.exceptions.AuthenticationException
import io.tolgee.exceptions.BadRequestException
import io.tolgee.exceptions.DisabledFunctionalityException
import io.tolgee.exceptions.NotFoundException
import io.tolgee.model.UserAccount
import io.tolgee.openApiDocs.OpenApiHideFromPublicDocs
import io.tolgee.security.authentication.JwtService
import io.tolgee.security.authorization.BypassEmailVerification
import io.tolgee.security.payload.JwtAuthenticationResponse
import io.tolgee.security.ratelimit.RateLimited
import io.tolgee.security.service.thirdParty.SsoDelegate
import io.tolgee.security.thirdParty.GithubOAuthDelegate
import io.tolgee.security.thirdParty.GoogleOAuthDelegate
import io.tolgee.security.thirdParty.OAuth2Delegate
import io.tolgee.service.AuthProviderChangeRequestService
import io.tolgee.service.EmailVerificationService
import io.tolgee.service.security.*
import jakarta.validation.Valid
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.NotNull
import org.apache.commons.lang3.RandomStringUtils
import org.springframework.context.annotation.Lazy
import org.springframework.http.MediaType
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.*
Expand All @@ -41,6 +49,7 @@ class PublicController(
private val githubOAuthDelegate: GithubOAuthDelegate,
private val googleOAuthDelegate: GoogleOAuthDelegate,
private val oauth2Delegate: OAuth2Delegate,
private val ssoDelegate: SsoDelegate,
private val properties: TolgeeProperties,
private val userAccountService: UserAccountService,
private val tolgeeEmailSender: TolgeeEmailSender,
Expand All @@ -49,6 +58,9 @@ class PublicController(
private val signUpService: SignUpService,
private val mfaService: MfaService,
private val userCredentialsService: UserCredentialsService,
private val authProperties: AuthenticationProperties,
@Lazy
private val authProviderChangeRequestService: AuthProviderChangeRequestService,
) {
@Operation(summary = "Generate JWT token")
@PostMapping("/generatetoken")
Expand All @@ -57,11 +69,17 @@ class PublicController(
@RequestBody @Valid
loginRequest: LoginRequest,
): JwtAuthenticationResponse {
if (!authProperties.nativeEnabled) {
throw AuthenticationException(Message.NATIVE_AUTHENTICATION_DISABLED)
}

val userAccount = userCredentialsService.checkUserCredentials(loginRequest.username, loginRequest.password)
mfaService.checkMfa(userAccount, loginRequest.otp)

// two factor passed, so we can generate super token
val jwt = jwtService.emitToken(userAccount.id, true)

authProviderChangeRequestService.resolveChangeRequestIfExist(userAccount)
return JwtAuthenticationResponse(jwt)
}

Expand All @@ -72,7 +90,32 @@ class PublicController(
@RequestBody @Valid
request: ResetPasswordRequest,
) {
if (!authProperties.nativeEnabled) {
throw DisabledFunctionalityException(Message.NATIVE_AUTHENTICATION_DISABLED)
}

val userAccount = userAccountService.findActive(request.email!!) ?: return
if (userAccount.accountType === UserAccount.AccountType.MANAGED) {
val params =
EmailParams(
to = request.email!!,
subject = "Password Reset Request - SSO Managed Account",
text =
"""
Hello! 👋<br/><br/>
We received a request to reset the password for your account. However, your account is managed by your organization and uses a single sign-on (SSO) service for login.<br/><br/>
To access your account, please use the "SSO Login" button on the Tolgee login page. No password reset is needed.<br/><br/>
If you did not make this request, you may safely ignore this email.<br/><br/>

Regards,<br/>
Tolgee
""".trimIndent(),
)

tolgeeEmailSender.sendEmail(params)
return
}

val code = RandomStringUtils.randomAlphabetic(50)
userAccountService.setResetPasswordCode(userAccount, code)

Expand Down Expand Up @@ -106,6 +149,9 @@ class PublicController(
@PathVariable("code") code: String,
@PathVariable("email") email: String,
) {
if (!authProperties.nativeEnabled) {
throw DisabledFunctionalityException(Message.NATIVE_AUTHENTICATION_DISABLED)
}
validateEmailCode(code, email)
}

Expand All @@ -116,7 +162,13 @@ class PublicController(
@RequestBody @Valid
request: ResetPassword,
) {
if (!authProperties.nativeEnabled) {
throw DisabledFunctionalityException(Message.NATIVE_AUTHENTICATION_DISABLED)
}
val userAccount = validateEmailCode(request.code!!, request.email!!)
if (userAccount.accountType === UserAccount.AccountType.MANAGED) {
throw AuthenticationException(Message.OPERATION_UNAVAILABLE_FOR_ACCOUNT_TYPE)
}
if (userAccount.accountType === UserAccount.AccountType.THIRD_PARTY) {
userAccountService.setAccountType(userAccount, UserAccount.AccountType.LOCAL)
}
Expand All @@ -138,6 +190,9 @@ class PublicController(
if (!reCaptchaValidationService.validate(dto.recaptchaToken, "")) {
throw BadRequestException(Message.INVALID_RECAPTCHA_TOKEN)
}
if (!authProperties.nativeEnabled) {
throw DisabledFunctionalityException(Message.NATIVE_AUTHENTICATION_DISABLED)
}
return signUpService.signUp(dto)
}

Expand Down Expand Up @@ -176,6 +231,7 @@ class PublicController(
@RequestParam(value = "code", required = true) code: String?,
@RequestParam(value = "redirect_uri", required = true) redirectUri: String?,
@RequestParam(value = "invitationCode", required = false) invitationCode: String?,
@RequestParam(value = "domain", required = false) domain: String?,
): JwtAuthenticationResponse {
if (properties.internal.fakeGithubLogin && code == "this_is_dummy_code") {
val user = getFakeGithubUser()
Expand All @@ -194,12 +250,29 @@ class PublicController(
oauth2Delegate.getTokenResponse(code, invitationCode, redirectUri)
}

"sso" -> {
ssoDelegate.getTokenResponse(code, invitationCode, redirectUri, domain)
}

else -> {
throw NotFoundException(Message.SERVICE_NOT_FOUND)
}
}
}

@PostMapping("/auth-provider/request-change")
fun submitOrCancelAuthProviderChangeRequest(
@RequestBody authProviderChangeRequestDto: AuthProviderChangeRequestDto,
) {
authProviderChangeRequestService.confirmOrCancel(authProviderChangeRequestDto)
}

@GetMapping("/auth-provider/get-request")
fun getAuthProviderChangeRequest(
@RequestParam("requestId") id: Long,
): AuthProviderChangeResponseDto =
AuthProviderChangeResponseDto.fromEntity(authProviderChangeRequestService.getById(id))

private fun getFakeGithubUser(): UserAccount {
val username = "[email protected]"
val user =
Expand Down
18 changes: 18 additions & 0 deletions backend/api/src/main/kotlin/io/tolgee/hateoas/ee/SsoTenantModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.tolgee.hateoas.ee

import org.springframework.hateoas.RepresentationModel
import org.springframework.hateoas.server.core.Relation
import java.io.Serializable

@Suppress("unused")
@Relation(collectionRelation = "ssoTenants", itemRelation = "ssoTenant")
class SsoTenantModel(
val authorizationUri: String,
val clientId: String,
val clientSecret: String,
val tokenUri: String,
val isEnabled: Boolean,
val jwkSetUri: String,
val domainName: String,
) : RepresentationModel<SsoTenantModel>(),
Serializable
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import io.tolgee.configuration.tolgee.TolgeeProperties
import io.tolgee.constants.Message
import io.tolgee.exceptions.AuthenticationException
import io.tolgee.model.UserAccount
import io.tolgee.model.enums.ThirdPartyAuthType
import io.tolgee.security.authentication.JwtService
import io.tolgee.security.payload.JwtAuthenticationResponse
import io.tolgee.service.security.SignUpService
import io.tolgee.service.security.UserAccountService
import org.springframework.context.annotation.Lazy
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
Expand All @@ -25,6 +27,8 @@ class GithubOAuthDelegate(
private val restTemplate: RestTemplate,
properties: TolgeeProperties,
private val signUpService: SignUpService,
@Lazy
private val userConflictManager: UserConflictManager,
) {
private val githubConfigurationProperties: GithubAuthenticationProperties = properties.authentication.github

Expand Down Expand Up @@ -74,18 +78,19 @@ class GithubOAuthDelegate(
)?.email
?: throw AuthenticationException(Message.THIRD_PARTY_AUTH_NO_EMAIL)

val userAccountOptional = userAccountService.findByThirdParty("github", userResponse!!.id!!)
val userAccountOptional = userAccountService.findByThirdParty(ThirdPartyAuthType.GITHUB, userResponse!!.id!!)
userConflictManager.resolveRequestIfExist(userAccountOptional)
val user =
userAccountOptional.orElseGet {
userAccountService.findActive(githubEmail)?.let {
throw AuthenticationException(Message.USERNAME_ALREADY_EXISTS)
manageUserNameConflict(it)
}

val newUserAccount = UserAccount()
newUserAccount.username = githubEmail
newUserAccount.name = userResponse.name ?: userResponse.login
newUserAccount.thirdPartyAuthId = userResponse.id
newUserAccount.thirdPartyAuthType = "github"
newUserAccount.thirdPartyAuthType = ThirdPartyAuthType.GITHUB
newUserAccount.accountType = UserAccount.AccountType.THIRD_PARTY

signUpService.signUp(newUserAccount, invitationCode, null)
Expand All @@ -106,6 +111,14 @@ class GithubOAuthDelegate(
throw AuthenticationException(Message.THIRD_PARTY_AUTH_UNKNOWN_ERROR)
}

private fun manageUserNameConflict(user: UserAccount) {
userConflictManager.manageUserNameConflict(
user,
ThirdPartyAuthType.GITHUB,
newAccountType = UserAccount.AccountType.THIRD_PARTY,
)
}

class GithubEmailResponse {
var email: String? = null
var primary = false
Expand Down
Loading
Loading