All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.komune.im.f2.space.lib.SpaceAggregateService.kt Maven / Gradle / Ivy

There is a newer version: 0.17.0
Show newest version
package io.komune.im.f2.space.lib

import io.komune.im.api.config.bean.ImAuthenticationProvider
import io.komune.im.commons.auth.withAuth
import io.komune.im.core.client.api.ClientCoreAggregateService
import io.komune.im.core.client.api.ClientCoreFinderService
import io.komune.im.core.client.domain.command.ClientGrantClientRolesCommand
import io.komune.im.core.commons.CoreService
import io.komune.im.f2.space.domain.command.SpaceDefineCommand
import io.komune.im.f2.space.domain.command.SpaceDefinedEvent
import io.komune.im.f2.space.domain.command.SpaceDeleteCommand
import io.komune.im.f2.space.domain.command.SpaceDeletedEvent
import io.komune.im.infra.redis.CacheName
import org.keycloak.representations.idm.RealmRepresentation
import org.keycloak.representations.userprofile.config.UPConfig
import org.springframework.stereotype.Service
import jakarta.ws.rs.NotFoundException as JakartaNotFoundException

@Service
class SpaceAggregateService(
    private val clientCoreAggregateService: ClientCoreAggregateService,
    private val clientCoreFinderService: ClientCoreFinderService,
    private val authenticationResolver: ImAuthenticationProvider
) : CoreService(CacheName.Space) {


    companion object {
        const val ACCESS_TOKEN_LIFESPAN = 28800
        const val SSO_SESSSION_IDLE_TIMEOUT = 604800
        const val SSO_SESSION_MAX_LIFESPAN = 259200
        const val ACTION_TOKEN_GENERATED_BY_USER_LIFESPAN = 900
        const val IS_VERIFY_EMAIL = true
        const val ID_RESET_PASSWORD_ALLOWED = true
        const val PASSWORD_POLICY = "length(8)"
        const val BASE_THEME = "keycloak"
        const val IS_INTERNATIONALIZATION_ENABLED = true
    }

    suspend fun define(
        command: SpaceDefineCommand
    ): SpaceDefinedEvent = withAuth(authenticationResolver.getAuth(), "master") {
        try {
            update(command)
        } catch (e: JakartaNotFoundException) {
            create(command)
        }

        SpaceDefinedEvent(
            identifier = command.identifier,
        )
    }

    suspend fun delete(command: SpaceDeleteCommand): SpaceDeletedEvent = mutate(command.id) {
        val client = keycloakClientProvider.get()
        client.realm(command.id).remove()
        SpaceDeletedEvent(command.id)
    }

    private suspend fun create(command: SpaceDefineCommand) {
        val client = keycloakClientProvider.get()

        val realm = RealmRepresentation()
            .applyBaseConfig()
            .apply(command)

        client.realms().create(realm)

        val authClientId = clientCoreFinderService.getByIdentifier(client.auth.clientId).id
        val realmClientId = clientCoreFinderService.getByIdentifier("${command.identifier}-realm").id
        val realmClientRoles = clientCoreFinderService.listClientRoles(realmClientId)
        ClientGrantClientRolesCommand(
            id = authClientId,
            providerClientId = realmClientId,
            roles = realmClientRoles
        ).let { clientCoreAggregateService.grantClientRoles(it) }

        enableUserAttributes(realm.realm)

        keycloakClientProvider.reset()
    }

    private suspend fun enableUserAttributes(realm: String) {
        val client = keycloakClientProvider.get(realm)
        val upConfiguration = client.userProfile().configuration
        upConfiguration.unmanagedAttributePolicy = UPConfig.UnmanagedAttributePolicy.ENABLED
        client.userProfile().update(upConfiguration)
    }

    private suspend fun update(command: SpaceDefineCommand) {
        val client = keycloakClientProvider.get()
        val realm = client.realm(command.identifier)
            .toRepresentation()
            .apply(command)
        client.realm(command.identifier).update(realm)
    }

    private fun RealmRepresentation.applyBaseConfig() = apply {
        isEnabled = true
        isInternationalizationEnabled = IS_INTERNATIONALIZATION_ENABLED

        accessTokenLifespan = ACCESS_TOKEN_LIFESPAN
        ssoSessionIdleTimeout = SSO_SESSSION_IDLE_TIMEOUT
        ssoSessionMaxLifespan = SSO_SESSION_MAX_LIFESPAN
        actionTokenGeneratedByUserLifespan = ACTION_TOKEN_GENERATED_BY_USER_LIFESPAN

        isVerifyEmail = IS_VERIFY_EMAIL
        isResetPasswordAllowed = ID_RESET_PASSWORD_ALLOWED
        passwordPolicy = PASSWORD_POLICY

        loginTheme = BASE_THEME
        accountTheme = BASE_THEME
        adminTheme = BASE_THEME
        emailTheme = BASE_THEME
    }

    private fun RealmRepresentation.apply(command: SpaceDefineCommand) = apply {
        realm = command.identifier
        displayName = command.identifier
        smtpServer = command.smtp
        loginTheme = command.theme
        emailTheme = command.theme
        supportedLocales = command.locales?.toSet()
        defaultLocale = command.locales?.firstOrNull()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy