#8 Les configurations sécuritaires retournent leur informations sans leur contenu
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
ae5c19faca
commit
689dbdc412
|
@ -3,23 +3,24 @@ package dev.fyloz.colorrecipesexplorer
|
|||
import dev.fyloz.colorrecipesexplorer.databasemanager.CreDatabase
|
||||
import dev.fyloz.colorrecipesexplorer.databasemanager.databaseContext
|
||||
import dev.fyloz.colorrecipesexplorer.databasemanager.databaseUpdaterProperties
|
||||
import dev.fyloz.colorrecipesexplorer.model.Configuration
|
||||
import dev.fyloz.colorrecipesexplorer.model.ConfigurationType
|
||||
import dev.fyloz.colorrecipesexplorer.service.config.ConfigurationService
|
||||
import org.slf4j.Logger
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.context.annotation.DependsOn
|
||||
import org.springframework.context.annotation.Profile
|
||||
import org.springframework.core.env.ConfigurableEnvironment
|
||||
import javax.sql.DataSource
|
||||
import org.springframework.context.annotation.Configuration as SpringConfiguration
|
||||
|
||||
const val SUPPORTED_DATABASE_VERSION = 5
|
||||
const val ENV_VAR_ENABLE_DATABASE_UPDATE_NAME = "CRE_ENABLE_DB_UPDATE"
|
||||
val DATABASE_NAME_REGEX = Regex("(\\w+)$")
|
||||
|
||||
@Profile("!emergency")
|
||||
@Configuration
|
||||
@SpringConfiguration
|
||||
@DependsOn("configurationsInitializer", "configurationService")
|
||||
class DataSourceConfiguration {
|
||||
@Bean(name = ["dataSource"])
|
||||
|
@ -29,7 +30,8 @@ class DataSourceConfiguration {
|
|||
configurationService: ConfigurationService
|
||||
): DataSource {
|
||||
fun getConfiguration(type: ConfigurationType) =
|
||||
configurationService.get(type).content
|
||||
if (type.secure) configurationService.getSecure(type)
|
||||
else configurationService.getContent(type)
|
||||
|
||||
val databaseUrl = "jdbc:" + getConfiguration(ConfigurationType.DATABASE_URL)
|
||||
val databaseUsername = getConfiguration(ConfigurationType.DATABASE_USER)
|
||||
|
|
|
@ -81,6 +81,10 @@ fun configuration(
|
|||
configuration(type = key.toConfigurationType(), content = content)
|
||||
}
|
||||
|
||||
fun secureConfiguration(
|
||||
configuration: Configuration
|
||||
) = SecureConfiguration(configuration.type, configuration.lastUpdated)
|
||||
|
||||
enum class ConfigurationType(
|
||||
val key: String,
|
||||
val defaultContent: Any? = null,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package dev.fyloz.colorrecipesexplorer.rest
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.model.Configuration
|
||||
import dev.fyloz.colorrecipesexplorer.model.ConfigurationBase
|
||||
import dev.fyloz.colorrecipesexplorer.model.ConfigurationDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.ConfigurationImageDto
|
||||
import dev.fyloz.colorrecipesexplorer.model.account.Permission
|
||||
|
@ -20,13 +20,11 @@ class ConfigurationController(val configurationService: ConfigurationService) {
|
|||
fun getAll(@RequestParam(required = false) keys: String?, authentication: Authentication?) =
|
||||
ok(with(configurationService) {
|
||||
if (keys != null) getAll(keys) else getAll()
|
||||
}.filter {
|
||||
!it.type.secure && authentication.hasAuthority(it)
|
||||
})
|
||||
}.filter { authentication.hasAuthority(it) })
|
||||
|
||||
@GetMapping("{key}")
|
||||
fun get(@PathVariable key: String, authentication: Authentication?) = with(configurationService.get(key)) {
|
||||
if (!this.type.secure && authentication.hasAuthority(this)) ok(this) else forbidden()
|
||||
if (authentication.hasAuthority(this)) ok(this) else forbidden()
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
|
@ -48,7 +46,7 @@ class ConfigurationController(val configurationService: ConfigurationService) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun Authentication?.hasAuthority(configuration: Configuration) = when {
|
||||
private fun Authentication?.hasAuthority(configuration: ConfigurationBase) = when {
|
||||
configuration.type.public -> true
|
||||
this != null && Permission.ADMIN.toAuthority() in this.authorities -> true
|
||||
else -> false
|
||||
|
|
|
@ -59,7 +59,7 @@ class MaterialServiceImpl(
|
|||
isMixType = this.isMixType,
|
||||
materialType = this.materialType!!,
|
||||
simdutUrl = if (fileService.exists(this.simdutFilePath))
|
||||
"${configService.get(ConfigurationType.INSTANCE_URL).content}$FILE_CONTROLLER_PATH?path=${
|
||||
"${configService.getContent(ConfigurationType.INSTANCE_URL)}$FILE_CONTROLLER_PATH?path=${
|
||||
URLEncoder.encode(
|
||||
this.simdutFilePath,
|
||||
StandardCharsets.UTF_8
|
||||
|
|
|
@ -78,7 +78,7 @@ class RecipeServiceImpl(
|
|||
}.toSet(),
|
||||
this.groupsInformation,
|
||||
recipeImageService.getAllImages(this)
|
||||
.map { this.imageUrl(configService.get(ConfigurationType.INSTANCE_URL).content, it) }
|
||||
.map { this.imageUrl(configService.getContent(ConfigurationType.INSTANCE_URL), it) }
|
||||
.toSet()
|
||||
)
|
||||
|
||||
|
@ -87,7 +87,7 @@ class RecipeServiceImpl(
|
|||
repository.existsByNameAndCompany(name, company)
|
||||
|
||||
override fun isApprobationExpired(recipe: Recipe): Boolean? =
|
||||
with(Period.parse(configService.get(ConfigurationType.RECIPE_APPROBATION_EXPIRATION).content)) {
|
||||
with(Period.parse(configService.getContent(ConfigurationType.RECIPE_APPROBATION_EXPIRATION))) {
|
||||
recipe.approbationDate?.plus(this)?.isBefore(LocalDate.now())
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class TouchUpKitServiceImpl(
|
|||
touchUpKitRepository
|
||||
), TouchUpKitService {
|
||||
private val cacheGeneratedFiles by lazy {
|
||||
configService.get(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF).content == true.toString()
|
||||
configService.getContent(ConfigurationType.TOUCH_UP_KIT_CACHE_PDF) == true.toString()
|
||||
}
|
||||
|
||||
override fun idNotFoundException(id: Long) = touchUpKitIdNotFoundException(id)
|
||||
|
@ -90,7 +90,7 @@ class TouchUpKitServiceImpl(
|
|||
}
|
||||
|
||||
override fun isExpired(touchUpKit: TouchUpKit) =
|
||||
with(Period.parse(configService.get(ConfigurationType.TOUCH_UP_KIT_EXPIRATION).content)) {
|
||||
with(Period.parse(configService.getContent(ConfigurationType.TOUCH_UP_KIT_EXPIRATION))) {
|
||||
touchUpKit.completed && touchUpKit.completionDate!!.plus(this) < LocalDate.now()
|
||||
}
|
||||
|
||||
|
@ -144,5 +144,5 @@ class TouchUpKitServiceImpl(
|
|||
"$TOUCH_UP_KIT_FILES_PATH/$this.pdf"
|
||||
|
||||
private fun TouchUpKit.pdfUrl() =
|
||||
"${configService.get(ConfigurationType.INSTANCE_URL).content}$TOUCH_UP_KIT_CONTROLLER_PATH/pdf?job=$project"
|
||||
"${configService.getContent(ConfigurationType.INSTANCE_URL)}$TOUCH_UP_KIT_CONTROLLER_PATH/pdf?job=$project"
|
||||
}
|
||||
|
|
|
@ -12,22 +12,28 @@ import org.springframework.stereotype.Service
|
|||
|
||||
interface ConfigurationService {
|
||||
/** Gets all set configurations. */
|
||||
fun getAll(): List<Configuration>
|
||||
fun getAll(): List<ConfigurationBase>
|
||||
|
||||
/**
|
||||
* Gets all configurations with keys contained in the given [formattedKeyList].
|
||||
* The [formattedKeyList] contains wanted configuration keys separated by a semi-colon.
|
||||
*/
|
||||
fun getAll(formattedKeyList: String): List<Configuration>
|
||||
fun getAll(formattedKeyList: String): List<ConfigurationBase>
|
||||
|
||||
/**
|
||||
* Gets the configuration with the given [key].
|
||||
* If the [key] does not exists, an [InvalidConfigurationKeyException] will be thrown.
|
||||
*/
|
||||
fun get(key: String): Configuration
|
||||
fun get(key: String): ConfigurationBase
|
||||
|
||||
/** Gets the configuration with the given [type]. */
|
||||
fun get(type: ConfigurationType): Configuration
|
||||
fun get(type: ConfigurationType): ConfigurationBase
|
||||
|
||||
/** Gets the content of the configuration with the given [type]. */
|
||||
fun getContent(type: ConfigurationType): String
|
||||
|
||||
/** Gets the content of the secure configuration with the given [type]. Should not be accessible to the users. */
|
||||
fun getSecure(type: ConfigurationType): String
|
||||
|
||||
/** Sets the content of each configuration in the given [configurations] list. */
|
||||
fun set(configurations: List<ConfigurationDto>)
|
||||
|
@ -89,18 +95,32 @@ class ConfigurationServiceImpl(
|
|||
override fun get(key: String) =
|
||||
get(key.toConfigurationType())
|
||||
|
||||
override fun get(type: ConfigurationType): Configuration {
|
||||
override fun get(type: ConfigurationType): ConfigurationBase {
|
||||
// Encryption salt should never be returned, but cannot be set as "secure" without encrypting it
|
||||
if (type == ConfigurationType.GENERATED_ENCRYPTION_SALT) throw InvalidConfigurationKeyException(type.key)
|
||||
|
||||
val configuration = configurationSource.get(type) ?: throw ConfigurationNotSetException(type)
|
||||
return if (type.secure) {
|
||||
decryptConfiguration(configuration)
|
||||
secureConfiguration(configuration)
|
||||
} else {
|
||||
configuration
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContent(type: ConfigurationType): String {
|
||||
val configuration = get(type)
|
||||
if (configuration is SecureConfiguration) throw UnsupportedOperationException("Cannot get '${type.key}' configuration content because it is secure")
|
||||
|
||||
return (configuration as Configuration).content
|
||||
}
|
||||
|
||||
override fun getSecure(type: ConfigurationType): String {
|
||||
if (!type.secure) throw UnsupportedOperationException("Cannot get configuration of type '${type.key}' because it is not a secure configuration")
|
||||
|
||||
val configuration = configurationSource.get(type) ?: throw ConfigurationNotSetException(type)
|
||||
return decryptConfiguration(configuration).content
|
||||
}
|
||||
|
||||
override fun set(configurations: List<ConfigurationDto>) {
|
||||
configurationSource.set(
|
||||
configurations
|
||||
|
|
Loading…
Reference in New Issue