diff --git a/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt index 2b70bb1eda..c809fcdce6 100644 --- a/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt +++ b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/config/WebSecurityConfig.kt @@ -4,6 +4,8 @@ package com.saveourtool.save.authservice.config +import com.saveourtool.save.authservice.security.ConvertingAuthenticationManager +import com.saveourtool.save.authservice.security.CustomAuthenticationBasicConverter import com.saveourtool.save.authservice.utils.roleHierarchy import com.saveourtool.save.v1 @@ -14,10 +16,12 @@ import org.springframework.http.HttpStatus import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity +import org.springframework.security.config.web.server.SecurityWebFiltersOrder import org.springframework.security.config.web.server.ServerHttpSecurity import org.springframework.security.crypto.factory.PasswordEncoderFactories import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.security.web.server.SecurityWebFilterChain +import org.springframework.security.web.server.authentication.AuthenticationWebFilter import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint import javax.annotation.PostConstruct @@ -27,6 +31,8 @@ import javax.annotation.PostConstruct @Profile("secure") @Suppress("MISSING_KDOC_TOP_LEVEL", "MISSING_KDOC_CLASS_ELEMENTS", "MISSING_KDOC_ON_FUNCTION") class WebSecurityConfig( + private val authenticationManager: ConvertingAuthenticationManager, + private val customAuthenticationBasicConverter: CustomAuthenticationBasicConverter, @Autowired private var defaultMethodSecurityExpressionHandler: DefaultMethodSecurityExpressionHandler ) { @Bean @@ -51,6 +57,12 @@ class WebSecurityConfig( // FixMe: Properly support CSRF protection https://github.com/saveourtool/save-cloud/issues/34 csrf().disable() } + .addFilterBefore( + AuthenticationWebFilter(authenticationManager).apply { + setServerAuthenticationConverter(customAuthenticationBasicConverter) + }, + SecurityWebFiltersOrder.HTTP_BASIC, + ) .exceptionHandling { it.authenticationEntryPoint( HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED) diff --git a/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/security/ConvertingAuthenticationManager.kt b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/security/ConvertingAuthenticationManager.kt index 919e45f219..e92543225c 100644 --- a/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/security/ConvertingAuthenticationManager.kt +++ b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/security/ConvertingAuthenticationManager.kt @@ -10,6 +10,7 @@ import org.springframework.security.authentication.BadCredentialsException import org.springframework.security.authentication.ReactiveAuthenticationManager import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.Authentication +import org.springframework.security.core.authority.AuthorityUtils import org.springframework.stereotype.Component import reactor.core.publisher.Mono import reactor.kotlin.core.publisher.switchIfEmpty @@ -51,7 +52,7 @@ class ConvertingAuthenticationManager( UsernamePasswordAuthenticationToken.authenticated( authentication.principal, authentication.credentials, - authentication.authorities, + AuthorityUtils.commaSeparatedStringToAuthorityList(role), ).apply { details = AuthenticationDetails( id = requiredId(), diff --git a/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/security/CustomAuthenticationBasicConverter.kt b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/security/CustomAuthenticationBasicConverter.kt new file mode 100644 index 0000000000..a76c3a3eb9 --- /dev/null +++ b/authentication-service/src/main/kotlin/com/saveourtool/save/authservice/security/CustomAuthenticationBasicConverter.kt @@ -0,0 +1,35 @@ +package com.saveourtool.save.authservice.security + +import com.saveourtool.save.authservice.utils.AuthenticationDetails +import com.saveourtool.save.utils.AUTHORIZATION_SOURCE +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.web.server.authentication.ServerAuthenticationConverter +import org.springframework.security.web.server.authentication.ServerHttpBasicAuthenticationConverter +import org.springframework.stereotype.Component +import org.springframework.web.server.ServerWebExchange +import reactor.core.publisher.Mono + +/** + * Implementation of [ServerAuthenticationConverter] that embeds user identity source into [UsernamePasswordAuthenticationToken] + */ +@Component +class CustomAuthenticationBasicConverter : ServerHttpBasicAuthenticationConverter(), + ServerAuthenticationConverter { + /** + * Convert exchange, received from gateway into UsernamePasswordAuthenticationToken, specify source identity, laid + * by gateway into X-Authorization-Source header + */ + @Suppress("TOO_MANY_LINES_IN_LAMBDA") + override fun convert(exchange: ServerWebExchange): Mono = super.convert(exchange).map { authentication -> + val name = (authentication as UsernamePasswordAuthenticationToken).principal as String + UsernamePasswordAuthenticationToken( + name, + authentication.credentials as String + ).apply { + details = AuthenticationDetails( + id = -1L, + ) + } + } +} \ No newline at end of file diff --git a/save-backend/src/main/kotlin/com/saveourtool/save/backend/configs/WebSecurityConfig.kt b/save-backend/src/main/kotlin/com/saveourtool/save/backend/configs/WebSecurityConfig.kt index 8a44dd0fc2..ed697a83bf 100644 --- a/save-backend/src/main/kotlin/com/saveourtool/save/backend/configs/WebSecurityConfig.kt +++ b/save-backend/src/main/kotlin/com/saveourtool/save/backend/configs/WebSecurityConfig.kt @@ -8,6 +8,7 @@ import com.saveourtool.save.authservice.config.NoopWebSecurityConfig import com.saveourtool.save.authservice.config.WebSecurityConfig import com.saveourtool.save.authservice.repository.AuthenticationUserRepository import com.saveourtool.save.authservice.security.ConvertingAuthenticationManager +import com.saveourtool.save.authservice.security.CustomAuthenticationBasicConverter import com.saveourtool.save.authservice.service.AuthenticationUserDetailsService import org.springframework.context.annotation.Import @@ -22,6 +23,7 @@ import org.springframework.security.config.annotation.web.reactive.EnableWebFlux @Import( WebSecurityConfig::class, ConvertingAuthenticationManager::class, + CustomAuthenticationBasicConverter::class, AuthenticationUserDetailsService::class, AuthenticationUserRepository::class, )