#8 Les configurations sécuritaires retournent leur informations sans leur contenu
continuous-integration/drone/push Build is passing Details

This commit is contained in:
FyloZ 2021-08-04 22:57:31 -04:00
parent ae5c19faca
commit 689dbdc412
Signed by: william
GPG Key ID: 835378AE9AF4AE97
7 changed files with 45 additions and 21 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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())
}

View File

@ -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"
}

View File

@ -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