From 3bc148f7eaf8531e28900ca080795dc2a68753ac Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer Date: Tue, 7 May 2024 08:58:00 +0200 Subject: refactor: move classes into package 'security' --- .../dnpm/etl/processor/config/AppConfiguration.kt | 4 +- .../processor/config/AppSecurityConfiguration.kt | 2 +- .../dnpm/etl/processor/security/TokenService.kt | 92 ++++++++++++++++++++++ .../dnpm/etl/processor/security/UserRoleService.kt | 58 ++++++++++++++ .../dnpm/etl/processor/services/TokenService.kt | 92 ---------------------- .../dnpm/etl/processor/services/UserRoleService.kt | 61 -------------- .../dev/dnpm/etl/processor/web/ConfigController.kt | 6 +- 7 files changed, 156 insertions(+), 159 deletions(-) create mode 100644 src/main/kotlin/dev/dnpm/etl/processor/security/TokenService.kt create mode 100644 src/main/kotlin/dev/dnpm/etl/processor/security/UserRoleService.kt delete mode 100644 src/main/kotlin/dev/dnpm/etl/processor/services/TokenService.kt delete mode 100644 src/main/kotlin/dev/dnpm/etl/processor/services/UserRoleService.kt (limited to 'src/main') diff --git a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt index 6ebcadd..5fc1120 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/config/AppConfiguration.kt @@ -28,8 +28,8 @@ import dev.dnpm.etl.processor.pseudonym.AnonymizingGenerator import dev.dnpm.etl.processor.pseudonym.Generator import dev.dnpm.etl.processor.pseudonym.GpasPseudonymGenerator import dev.dnpm.etl.processor.pseudonym.PseudonymizeService -import dev.dnpm.etl.processor.services.TokenRepository -import dev.dnpm.etl.processor.services.TokenService +import dev.dnpm.etl.processor.security.TokenRepository +import dev.dnpm.etl.processor.security.TokenService import dev.dnpm.etl.processor.services.Transformation import dev.dnpm.etl.processor.services.TransformationService import org.apache.hc.client5.http.impl.classic.HttpClients diff --git a/src/main/kotlin/dev/dnpm/etl/processor/config/AppSecurityConfiguration.kt b/src/main/kotlin/dev/dnpm/etl/processor/config/AppSecurityConfiguration.kt index c377555..0da9398 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/config/AppSecurityConfiguration.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/config/AppSecurityConfiguration.kt @@ -21,7 +21,7 @@ package dev.dnpm.etl.processor.config import dev.dnpm.etl.processor.security.UserRole import dev.dnpm.etl.processor.security.UserRoleRepository -import dev.dnpm.etl.processor.services.UserRoleService +import dev.dnpm.etl.processor.security.UserRoleService import org.slf4j.LoggerFactory import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.context.properties.EnableConfigurationProperties diff --git a/src/main/kotlin/dev/dnpm/etl/processor/security/TokenService.kt b/src/main/kotlin/dev/dnpm/etl/processor/security/TokenService.kt new file mode 100644 index 0000000..44b04e8 --- /dev/null +++ b/src/main/kotlin/dev/dnpm/etl/processor/security/TokenService.kt @@ -0,0 +1,92 @@ +/* + * This file is part of ETL-Processor + * + * Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package dev.dnpm.etl.processor.security + +import jakarta.annotation.PostConstruct +import org.springframework.data.annotation.Id +import org.springframework.data.relational.core.mapping.Table +import org.springframework.data.repository.CrudRepository +import org.springframework.data.repository.findByIdOrNull +import org.springframework.security.core.userdetails.User +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.provisioning.InMemoryUserDetailsManager +import java.time.Instant +import java.util.* + +class TokenService( + private val userDetailsManager: InMemoryUserDetailsManager, + private val passwordEncoder: PasswordEncoder, + private val tokenRepository: TokenRepository +) { + + @PostConstruct + fun setup() { + tokenRepository.findAll().forEach { + userDetailsManager.createUser( + User.withUsername(it.username) + .password(it.password) + .roles("MTBFILE") + .build() + ) + } + } + + fun addToken(name: String): Result { + val username = name.lowercase().replace("""[^a-z0-9]""".toRegex(), "") + if (userDetailsManager.userExists(username)) { + return Result.failure(RuntimeException("Cannot use token name")) + } + + val password = Base64.getEncoder().encodeToString(UUID.randomUUID().toString().encodeToByteArray()) + val encodedPassword = passwordEncoder.encode(password).toString() + + userDetailsManager.createUser( + User.withUsername(username) + .password(encodedPassword) + .roles("MTBFILE") + .build() + ) + + tokenRepository.save(Token(name = name, username = username, password = encodedPassword)) + + return Result.success("$username:$password") + } + + fun deleteToken(id: Long) { + val token = tokenRepository.findByIdOrNull(id) ?: return + userDetailsManager.deleteUser(token.username) + tokenRepository.delete(token) + } + + fun findAll(): List { + return tokenRepository.findAll().toList() + } +} + +@Table("token") +data class Token( + @Id val id: Long? = null, + val name: String, + val username: String, + val password: String, + val createdAt: Instant = Instant.now() +) + +interface TokenRepository : CrudRepository \ No newline at end of file diff --git a/src/main/kotlin/dev/dnpm/etl/processor/security/UserRoleService.kt b/src/main/kotlin/dev/dnpm/etl/processor/security/UserRoleService.kt new file mode 100644 index 0000000..174f8a9 --- /dev/null +++ b/src/main/kotlin/dev/dnpm/etl/processor/security/UserRoleService.kt @@ -0,0 +1,58 @@ +/* + * This file is part of ETL-Processor + * + * Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package dev.dnpm.etl.processor.security + +import org.springframework.data.repository.findByIdOrNull +import org.springframework.security.core.session.SessionRegistry +import org.springframework.security.oauth2.core.oidc.user.OidcUser + +class UserRoleService( + private val userRoleRepository: UserRoleRepository, + private val sessionRegistry: SessionRegistry +) { + fun updateUserRole(id: Long, role: Role) { + val userRole = userRoleRepository.findByIdOrNull(id) ?: return + userRole.role = role + userRoleRepository.save(userRole) + expireSessionFor(userRole.username) + } + + fun deleteUserRole(id: Long) { + val userRole = userRoleRepository.findByIdOrNull(id) ?: return + userRoleRepository.delete(userRole) + expireSessionFor(userRole.username) + } + + fun findAll(): List { + return userRoleRepository.findAll().toList() + } + + private fun expireSessionFor(username: String) { + sessionRegistry.allPrincipals + .filterIsInstance() + .filter { it.preferredUsername == username } + .flatMap { + sessionRegistry.getAllSessions(it, true) + } + .onEach { + it.expireNow() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/dnpm/etl/processor/services/TokenService.kt b/src/main/kotlin/dev/dnpm/etl/processor/services/TokenService.kt deleted file mode 100644 index f084408..0000000 --- a/src/main/kotlin/dev/dnpm/etl/processor/services/TokenService.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of ETL-Processor - * - * Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package dev.dnpm.etl.processor.services - -import jakarta.annotation.PostConstruct -import org.springframework.data.annotation.Id -import org.springframework.data.relational.core.mapping.Table -import org.springframework.data.repository.CrudRepository -import org.springframework.data.repository.findByIdOrNull -import org.springframework.security.core.userdetails.User -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.security.provisioning.InMemoryUserDetailsManager -import java.time.Instant -import java.util.* - -class TokenService( - private val userDetailsManager: InMemoryUserDetailsManager, - private val passwordEncoder: PasswordEncoder, - private val tokenRepository: TokenRepository -) { - - @PostConstruct - fun setup() { - tokenRepository.findAll().forEach { - userDetailsManager.createUser( - User.withUsername(it.username) - .password(it.password) - .roles("MTBFILE") - .build() - ) - } - } - - fun addToken(name: String): Result { - val username = name.lowercase().replace("""[^a-z0-9]""".toRegex(), "") - if (userDetailsManager.userExists(username)) { - return Result.failure(RuntimeException("Cannot use token name")) - } - - val password = Base64.getEncoder().encodeToString(UUID.randomUUID().toString().encodeToByteArray()) - val encodedPassword = passwordEncoder.encode(password).toString() - - userDetailsManager.createUser( - User.withUsername(username) - .password(encodedPassword) - .roles("MTBFILE") - .build() - ) - - tokenRepository.save(Token(name = name, username = username, password = encodedPassword)) - - return Result.success("$username:$password") - } - - fun deleteToken(id: Long) { - val token = tokenRepository.findByIdOrNull(id) ?: return - userDetailsManager.deleteUser(token.username) - tokenRepository.delete(token) - } - - fun findAll(): List { - return tokenRepository.findAll().toList() - } -} - -@Table("token") -data class Token( - @Id val id: Long? = null, - val name: String, - val username: String, - val password: String, - val createdAt: Instant = Instant.now() -) - -interface TokenRepository : CrudRepository \ No newline at end of file diff --git a/src/main/kotlin/dev/dnpm/etl/processor/services/UserRoleService.kt b/src/main/kotlin/dev/dnpm/etl/processor/services/UserRoleService.kt deleted file mode 100644 index 6649f7d..0000000 --- a/src/main/kotlin/dev/dnpm/etl/processor/services/UserRoleService.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of ETL-Processor - * - * Copyright (c) 2024 Comprehensive Cancer Center Mainfranken, Datenintegrationszentrum Philipps-Universität Marburg and Contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package dev.dnpm.etl.processor.services - -import dev.dnpm.etl.processor.security.Role -import dev.dnpm.etl.processor.security.UserRole -import dev.dnpm.etl.processor.security.UserRoleRepository -import org.springframework.data.repository.findByIdOrNull -import org.springframework.security.core.session.SessionRegistry -import org.springframework.security.oauth2.core.oidc.user.OidcUser - -class UserRoleService( - private val userRoleRepository: UserRoleRepository, - private val sessionRegistry: SessionRegistry -) { - fun updateUserRole(id: Long, role: Role) { - val userRole = userRoleRepository.findByIdOrNull(id) ?: return - userRole.role = role - userRoleRepository.save(userRole) - expireSessionFor(userRole.username) - } - - fun deleteUserRole(id: Long) { - val userRole = userRoleRepository.findByIdOrNull(id) ?: return - userRoleRepository.delete(userRole) - expireSessionFor(userRole.username) - } - - fun findAll(): List { - return userRoleRepository.findAll().toList() - } - - private fun expireSessionFor(username: String) { - sessionRegistry.allPrincipals - .filterIsInstance() - .filter { it.preferredUsername == username } - .flatMap { - sessionRegistry.getAllSessions(it, true) - } - .onEach { - it.expireNow() - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/dev/dnpm/etl/processor/web/ConfigController.kt b/src/main/kotlin/dev/dnpm/etl/processor/web/ConfigController.kt index 4e101eb..165535f 100644 --- a/src/main/kotlin/dev/dnpm/etl/processor/web/ConfigController.kt +++ b/src/main/kotlin/dev/dnpm/etl/processor/web/ConfigController.kt @@ -27,10 +27,10 @@ import dev.dnpm.etl.processor.output.MtbFileSender import dev.dnpm.etl.processor.pseudonym.Generator import dev.dnpm.etl.processor.security.Role import dev.dnpm.etl.processor.security.UserRole -import dev.dnpm.etl.processor.services.Token -import dev.dnpm.etl.processor.services.TokenService +import dev.dnpm.etl.processor.security.Token +import dev.dnpm.etl.processor.security.TokenService import dev.dnpm.etl.processor.services.TransformationService -import dev.dnpm.etl.processor.services.UserRoleService +import dev.dnpm.etl.processor.security.UserRoleService import org.springframework.beans.factory.annotation.Qualifier import org.springframework.http.MediaType import org.springframework.http.codec.ServerSentEvent -- cgit v1.2.3