
net.nemerosa.ontrack.extension.oidc.settings.OIDCSettingsServiceImpl.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ontrack-extension-oidc Show documentation
Show all versions of ontrack-extension-oidc Show documentation
Ontrack module: ontrack-extension-oidc
The newest version!
package net.nemerosa.ontrack.extension.oidc.settings
import net.nemerosa.ontrack.common.Document
import net.nemerosa.ontrack.model.Ack
import net.nemerosa.ontrack.model.security.EncryptionService
import net.nemerosa.ontrack.model.security.GlobalSettings
import net.nemerosa.ontrack.model.security.SecurityService
import net.nemerosa.ontrack.model.structure.NameDescription
import net.nemerosa.ontrack.model.support.DocumentsRepository
import net.nemerosa.ontrack.model.support.StorageService
import net.nemerosa.ontrack.model.support.retrieve
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.concurrent.ConcurrentHashMap
@Service
@Transactional
class OIDCSettingsServiceImpl(
private val securityService: SecurityService,
private val storageService: StorageService,
private val encryptionService: EncryptionService,
private val documentsRepository: DocumentsRepository
) : OIDCSettingsService {
/**
* Provider listeners
*/
private val providerListeners = mutableListOf()
/**
* Settings listeners
*/
private val listeners = mutableListOf()
/**
* Caching the list of providers
*/
private val providersCache = ConcurrentHashMap>()
override val cachedProviders: List
get() = providersCache.getOrPut(CACHE_KEY) {
providers
}
override val cachedProviderNames: List
get() = securityService.asAdmin {
cachedProviders.map {
NameDescription(it.id, it.name)
}
}
override val providers: List
get() {
securityService.checkGlobalFunction(GlobalSettings::class.java)
return storageService.getData(OIDC_PROVIDERS_STORE, StoredOntrackOIDCProvider::class.java)
.values
.sortedBy { it.id }
.map { decrypt(it) }
}
override fun createProvider(input: OntrackOIDCProvider): OntrackOIDCProvider {
securityService.checkGlobalFunction(GlobalSettings::class.java)
if (storageService.exists(OIDC_PROVIDERS_STORE, input.id)) {
throw OntrackOIDCProviderIDAlreadyExistsException(input.id)
} else {
storageService.store(OIDC_PROVIDERS_STORE, input.id, encrypt(input))
clearCache()
return input
}
}
override fun deleteProvider(id: String): Ack {
securityService.checkGlobalFunction(GlobalSettings::class.java)
val provider = getProviderById(id)
return if (provider != null) {
// Cleanup
cleanupForProvider(provider)
// Actual deletion
storageService.delete(OIDC_PROVIDERS_STORE, id)
clearCache()
Ack.OK
} else {
Ack.NOK
}
}
/**
* Cleanup of accounts and group mappings.
*/
private fun cleanupForProvider(provider: OntrackOIDCProvider) {
providerListeners.forEach { it.onOIDCProviderDeleted(provider) }
}
override fun getProviderById(id: String): OntrackOIDCProvider? {
securityService.checkGlobalFunction(GlobalSettings::class.java)
return storageService.retrieve(OIDC_PROVIDERS_STORE, id)?.let {
decrypt(it)
}
}
override fun updateProvider(input: OntrackOIDCProvider): OntrackOIDCProvider {
securityService.checkGlobalFunction(GlobalSettings::class.java)
val existing = storageService.retrieve(OIDC_PROVIDERS_STORE, input.id)
?.let { decrypt(it) }
?: throw OntrackOIDCProviderIDNotFoundException(input.id)
val record = OntrackOIDCProvider(
id = input.id,
name = input.name,
description = input.description,
issuerId = input.issuerId,
clientId = input.clientId,
clientSecret = input.clientSecret.ifBlank {
existing.clientSecret
},
groupFilter = input.groupFilter,
forceHttps = input.forceHttps,
disabled = input.disabled,
)
storageService.store(OIDC_PROVIDERS_STORE, input.id, encrypt(record))
clearCache()
return record
}
override fun getProviderImage(id: String): Document? {
checkProviderId(id)
return documentsRepository.loadDocument(OIDC_PROVIDERS_IMAGES, id)
}
override fun hasProviderImage(id: String): Boolean {
checkProviderId(id)
return documentsRepository.documentExists(OIDC_PROVIDERS_IMAGES, id)
}
override fun setProviderImage(id: String, image: Document?) {
securityService.checkGlobalFunction(GlobalSettings::class.java)
checkProviderId(id)
if (image != null) {
documentsRepository.storeDocument(OIDC_PROVIDERS_IMAGES, id, image)
} else {
documentsRepository.deleteDocument(OIDC_PROVIDERS_IMAGES, id)
}
}
private fun checkProviderId(id: String) {
if (!storageService.exists(OIDC_PROVIDERS_STORE, id)) {
throw OntrackOIDCProviderIDNotFoundException(id)
}
}
private fun clearCache() {
providersCache.clear()
notifySettingsListeners()
}
private fun notifySettingsListeners() {
listeners.forEach {
it.onOidcSettingsChanged()
}
}
override fun addOidcSettingsListener(listener: OIDCSettingsListener) {
listeners += listener
}
override fun addOidcProviderListener(oidcProviderListener: OIDCProviderListener) {
providerListeners += oidcProviderListener
}
companion object {
/**
* Cache unique key
*/
private const val CACHE_KEY = "0"
/**
* Name of the store for the storage of the data
*/
private val OIDC_PROVIDERS_STORE = OntrackOIDCProvider::class.java.name
/**
* Name of the store for the images
*/
private val OIDC_PROVIDERS_IMAGES = OntrackOIDCProvider::class.java.name
}
/**
* Stored object
*/
private data class StoredOntrackOIDCProvider(
val id: String,
val name: String,
val description: String,
val issuerId: String,
val clientId: String,
val clientEncryptedSecret: String,
val groupFilter: String?,
val forceHttps: Boolean,
val disabled: Boolean,
)
private fun decrypt(stored: StoredOntrackOIDCProvider) = OntrackOIDCProvider(
id = stored.id,
name = stored.name,
description = stored.description,
issuerId = stored.issuerId,
clientId = stored.clientId,
clientSecret = encryptionService.decrypt(stored.clientEncryptedSecret) ?: "",
groupFilter = stored.groupFilter,
forceHttps = stored.forceHttps,
disabled = stored.disabled,
)
private fun encrypt(input: OntrackOIDCProvider) = StoredOntrackOIDCProvider(
id = input.id,
name = input.name,
description = input.description,
issuerId = input.issuerId,
clientId = input.clientId,
clientEncryptedSecret = (encryptionService.encrypt(input.clientSecret)
?: throw OntrackOIDCProviderCannotEncryptSecretException()),
groupFilter = input.groupFilter,
forceHttps = input.forceHttps,
disabled = input.disabled,
)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy