From c11e9a266f7fc3687cef208cd88790e8bb8e82a2 Mon Sep 17 00:00:00 2001 From: Tom Winter Date: Wed, 4 Dec 2024 09:45:49 +0100 Subject: [PATCH] feat: protect endpoints and conditional configuration --- .../aambackendservice/Application.kt | 2 + .../security/AamAuthenticationConverter.kt | 35 ++++ .../security/SecurityConfiguration.kt | 9 +- .../skill/controller/SkillAdminController.kt | 11 +- .../skill/controller/SkillController.kt | 65 ++------ .../skill/core/SkillStorage.kt | 15 -- .../skill/di/SkillConfiguration.kt | 152 +++--------------- .../skill/di/SkillConfigurationSkillLab.kt | 96 +++++++++++ ...serProfileUpdateEventQueueConfiguration.kt | 8 +- .../skill/job/SyncSkillsJob.kt | 7 + .../skill/skilllab/SkillLabSkillStorage.kt | 19 --- .../SkillLabSyncUserProfileUseCase.kt | 1 - .../src/main/resources/application.yaml | 13 +- .../src/test/resources/application-e2e.yaml | 9 +- 14 files changed, 209 insertions(+), 233 deletions(-) create mode 100644 application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/security/AamAuthenticationConverter.kt delete mode 100644 application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/core/SkillStorage.kt create mode 100644 application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfigurationSkillLab.kt delete mode 100644 application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSkillStorage.kt diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/Application.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/Application.kt index bb204d1..ac445f9 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/Application.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/Application.kt @@ -5,6 +5,7 @@ import org.springframework.boot.context.properties.ConfigurationPropertiesScan import org.springframework.boot.runApplication import org.springframework.data.jpa.repository.config.EnableJpaRepositories import org.springframework.scheduling.annotation.EnableScheduling +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RestController import java.util.* @@ -13,6 +14,7 @@ import java.util.* @ConfigurationPropertiesScan @EnableScheduling @EnableJpaRepositories +@EnableMethodSecurity class Application fun main(args: Array) { diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/security/AamAuthenticationConverter.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/security/AamAuthenticationConverter.kt new file mode 100644 index 0000000..e909d6b --- /dev/null +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/security/AamAuthenticationConverter.kt @@ -0,0 +1,35 @@ +package com.aamdigital.aambackendservice.security + +import org.springframework.core.convert.converter.Converter +import org.springframework.security.authentication.AbstractAuthenticationToken +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.oauth2.jwt.Jwt +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken +import org.springframework.stereotype.Component + +@Component +class AamAuthenticationConverter : Converter { + override fun convert(source: Jwt): AbstractAuthenticationToken { + return JwtAuthenticationToken(source, getClientAuthorities(source)) + } + + private fun getClientAuthorities(jwt: Jwt): Collection { + val realmAccessClaim = jwt.getClaimAsMap("realm_access") ?: return emptyList() + + val roles: List = if (realmAccessClaim.containsKey("roles")) { + when (val rolesClaim = realmAccessClaim["roles"]) { + is List<*> -> rolesClaim.filterIsInstance() + else -> emptyList() + } + } else { + emptyList() + } + + return roles + .filter { it.startsWith("aam_") } + .map { + SimpleGrantedAuthority("ROLE_$it") + } + } +} diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/security/SecurityConfiguration.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/security/SecurityConfiguration.kt index 5d66c74..5175155 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/security/SecurityConfiguration.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/security/SecurityConfiguration.kt @@ -16,7 +16,10 @@ import org.springframework.security.web.SecurityFilterChain class SecurityConfiguration { @Bean - fun filterChain(http: HttpSecurity): SecurityFilterChain { + fun filterChain( + http: HttpSecurity, + aamAuthenticationConverter: AamAuthenticationConverter, + ): SecurityFilterChain { http { authorizeRequests { authorize(HttpMethod.GET, "/", permitAll) @@ -45,6 +48,7 @@ class SecurityConfiguration { } oauth2ResourceServer { jwt { + jwtAuthenticationConverter = aamAuthenticationConverter authenticationEntryPoint = AamAuthenticationEntryPoint( parentEntryPoint = BearerTokenAuthenticationEntryPoint(), @@ -55,7 +59,4 @@ class SecurityConfiguration { } return http.build() } - - } - diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/controller/SkillAdminController.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/controller/SkillAdminController.kt index e6f563f..56bb004 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/controller/SkillAdminController.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/controller/SkillAdminController.kt @@ -5,7 +5,9 @@ import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesReques import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesUseCase import com.aamdigital.aambackendservice.skill.repository.SkillLabUserProfileSyncRepository import org.slf4j.LoggerFactory +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.http.ResponseEntity +import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping @@ -27,6 +29,12 @@ enum class SyncModeDto { @RestController @RequestMapping("/v1/skill") +@ConditionalOnProperty( + prefix = "features.skill-api", + name = ["mode"], + havingValue = "skilllab", + matchIfMissing = false +) class SkillAdminController( private val skillLabFetchUserProfileUpdatesUseCase: FetchUserProfileUpdatesUseCase, private val skillLabUserProfileSyncRepository: SkillLabUserProfileSyncRepository, @@ -34,8 +42,8 @@ class SkillAdminController( private val logger = LoggerFactory.getLogger(javaClass) - @GetMapping("/sync") + @PreAuthorize("hasAuthority('ROLE_aam_skill_admin')") fun fetchSyncStatus(): ResponseEntity> { val result = skillLabUserProfileSyncRepository.findAll().mapNotNull { SkillDto( @@ -48,6 +56,7 @@ class SkillAdminController( } @PostMapping("/sync/{projectId}") + @PreAuthorize("hasAuthority('ROLE_aam_skill_admin')") fun triggerSync( @PathVariable projectId: String, syncMode: SyncModeDto = SyncModeDto.DELTA, diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/controller/SkillController.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/controller/SkillController.kt index 3588077..19d4705 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/controller/SkillController.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/controller/SkillController.kt @@ -2,33 +2,36 @@ package com.aamdigital.aambackendservice.skill.controller import com.aamdigital.aambackendservice.domain.UseCaseOutcome import com.aamdigital.aambackendservice.error.HttpErrorDto -import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesRequest -import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesUseCase import com.aamdigital.aambackendservice.skill.core.SearchUserProfileRequest import com.aamdigital.aambackendservice.skill.core.SearchUserProfileUseCase import com.aamdigital.aambackendservice.skill.domain.EscoSkill import com.aamdigital.aambackendservice.skill.domain.SkillUsage import com.aamdigital.aambackendservice.skill.domain.UserProfile import com.aamdigital.aambackendservice.skill.repository.SkillLabUserProfileRepository -import com.aamdigital.aambackendservice.skill.skilllab.SkillLabFetchUserProfileUpdatesErrorCode +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity +import org.springframework.security.access.prepost.PreAuthorize import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.PostMapping -import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/v1/skill") +@ConditionalOnProperty( + prefix = "features.skill-api", + name = ["mode"], + havingValue = "skilllab", + matchIfMissing = false +) class SkillController( - private val fetchUserProfileUpdatesUseCase: FetchUserProfileUpdatesUseCase, // todo needs no-op implementation - private val searchUserProfileUseCase: SearchUserProfileUseCase, // todo needs no-op implementation - private val userProfileRepository: SkillLabUserProfileRepository + private val searchUserProfileUseCase: SearchUserProfileUseCase, + private val userProfileRepository: SkillLabUserProfileRepository, ) { @GetMapping("/user-profile") + @PreAuthorize("hasAnyAuthority('ROLE_aam_skill_reader')") fun fetchUserProfiles( fullName: String = "", email: String = "", @@ -45,14 +48,6 @@ class SkillController( return when (result) { is UseCaseOutcome.Failure<*> -> { when (result.errorCode) { -// SkillLabFetchUserProfileUpdatesErrorCode.EXTERNAL_SYSTEM_ERROR -// -> ResponseEntity.internalServerError().body( -// HttpErrorDto( -// errorCode = result.errorCode.toString(), -// errorMessage = result.errorMessage -// ) -// ) - else -> ResponseEntity.badRequest().body( ResponseEntity.internalServerError().body( HttpErrorDto( @@ -72,6 +67,7 @@ class SkillController( } @GetMapping("/user-profile/{id}") + @PreAuthorize("hasAuthority('ROLE_aam_skill_reader')") fun fetchUserProfile( @PathVariable id: String, ): ResponseEntity { @@ -103,41 +99,4 @@ class SkillController( ) } } - - @PostMapping - fun fetchUserProfileUpdates( - @RequestBody request: FetchUserProfileUpdatesRequest, - ): ResponseEntity { - val result = fetchUserProfileUpdatesUseCase.run( - request = request - ) - - return when (result) { - is UseCaseOutcome.Failure<*> -> { - when (result.errorCode) { - SkillLabFetchUserProfileUpdatesErrorCode.EXTERNAL_SYSTEM_ERROR - -> ResponseEntity.internalServerError().body( - HttpErrorDto( - errorCode = result.errorCode.toString(), - errorMessage = result.errorMessage - ) - ) - - else -> ResponseEntity.badRequest().body( - ResponseEntity.internalServerError().body( - HttpErrorDto( - errorCode = result.errorCode.toString(), - errorMessage = result.errorMessage - ) - ) - ) - } - ResponseEntity.badRequest().body( - result.errorMessage - ) - } - - is UseCaseOutcome.Success<*> -> ResponseEntity.ok().body(result.data) - } - } } diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/core/SkillStorage.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/core/SkillStorage.kt deleted file mode 100644 index 409d967..0000000 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/core/SkillStorage.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.aamdigital.aambackendservice.skill.core - -import com.aamdigital.aambackendservice.domain.DomainReference -import com.aamdigital.aambackendservice.error.AamException -import com.aamdigital.aambackendservice.skill.domain.EscoSkill -import org.springframework.data.domain.Pageable - -interface SkillStorage { - - @Throws(AamException::class) - fun fetchSkill(externalIdentifier: DomainReference): EscoSkill - - @Throws(AamException::class) - fun fetchSkills(pageable: Pageable): List -} diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfiguration.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfiguration.kt index 6e65dd1..9059104 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfiguration.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfiguration.kt @@ -1,35 +1,29 @@ package com.aamdigital.aambackendservice.skill.di -import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesUseCase -import com.aamdigital.aambackendservice.skill.core.SearchUserProfileUseCase -import com.aamdigital.aambackendservice.skill.core.SkillStorage -import com.aamdigital.aambackendservice.skill.core.SqlSearchUserProfileUseCase -import com.aamdigital.aambackendservice.skill.core.SyncUserProfileUseCase -import com.aamdigital.aambackendservice.skill.core.UserProfileMatcher -import com.aamdigital.aambackendservice.skill.core.UserProfileUpdatePublisher -import com.aamdigital.aambackendservice.skill.repository.SkillLabUserProfileRepository -import com.aamdigital.aambackendservice.skill.repository.SkillLabUserProfileSyncRepository -import com.aamdigital.aambackendservice.skill.skilllab.SkillLabClient -import com.aamdigital.aambackendservice.skill.skilllab.SkillLabFetchUserProfileUpdatesUseCase -import com.aamdigital.aambackendservice.skill.skilllab.SkillLabSkillStorage -import com.aamdigital.aambackendservice.skill.skilllab.SkillLabSyncUserProfileUseCase -import com.aamdigital.aambackendservice.skill.skilllab.SkillLabUserProfileMatcher -import com.fasterxml.jackson.databind.ObjectMapper -import org.springframework.beans.factory.annotation.Qualifier import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.boot.context.properties.ConfigurationProperties -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.http.HttpHeaders -import org.springframework.http.client.SimpleClientHttpRequestFactory -import org.springframework.web.client.RestClient +/** + * Configures behaviour of the skill-api. + * + * @mode skilllab + * Use SkillLab as SkillProvider, needs skilllab-api-client-configuration + * + * @mode disabled + * Disable skill-api. Endpoints are not reachable, nothing is imported. + * + */ +@ConfigurationProperties("features.skill-api") +class FeatureConfigurationSkillApi( + val mode: String, +) + @ConfigurationProperties("skilllab-api-client-configuration") @ConditionalOnProperty( - prefix = "skilllab-api-client-configuration", - name = ["enabled"], - havingValue = "true", + prefix = "features.skill-api", + name = ["mode"], + havingValue = "skilllab", matchIfMissing = false ) class SkillLabApiClientConfiguration( @@ -38,113 +32,3 @@ class SkillLabApiClientConfiguration( val projectId: String, val responseTimeoutInSeconds: Int = 30, ) - -@Configuration -class SkillConfiguration { - - @Bean(name = ["skilllab-api-client"]) - @ConditionalOnProperty( - prefix = "skilllab-api-client-configuration", - name = ["enabled"], - havingValue = "true", - matchIfMissing = false - ) - fun skillLabApiClient( - configuration: SkillLabApiClientConfiguration - ): RestClient { - val clientBuilder = RestClient.builder().baseUrl(configuration.basePath) - - clientBuilder.defaultRequest { request -> - request.headers { - it.set(HttpHeaders.AUTHORIZATION, "Bearer ${configuration.apiKey}") - } - } - - clientBuilder.requestFactory(SimpleClientHttpRequestFactory().apply { - setReadTimeout(configuration.responseTimeoutInSeconds * 1000) - setConnectTimeout(configuration.responseTimeoutInSeconds * 1000) - }) - - return clientBuilder.build() - } - - @Bean - @ConditionalOnProperty( - prefix = "skilllab-api-client-configuration", - name = ["enabled"], - havingValue = "true", - matchIfMissing = false - ) - fun skillLabClient( - @Qualifier("skilllab-api-client") restClient: RestClient, - objectMapper: ObjectMapper, - ): SkillLabClient = SkillLabClient( - http = restClient, - objectMapper = objectMapper, - ) - - @Bean - @ConditionalOnProperty( - prefix = "skilllab-api-client-configuration", - name = ["enabled"], - havingValue = "true", - matchIfMissing = false - ) - fun skillLabUserProfileStorage( - @Qualifier("skilllab-api-client") restClient: RestClient, - ): SkillStorage = SkillLabSkillStorage( - http = restClient - ) - - @Bean - @ConditionalOnProperty( - prefix = "skilllab-api-client-configuration", - name = ["enabled"], - havingValue = "true", - matchIfMissing = false - ) - fun skillLabUserProfileMatcher( - @Qualifier("skilllab-api-client") restClient: RestClient, - ): UserProfileMatcher = SkillLabUserProfileMatcher( - http = restClient - ) - - @Bean - @ConditionalOnProperty( - prefix = "skilllab-api-client-configuration", - name = ["enabled"], - havingValue = "true", - matchIfMissing = false - ) - fun skillLabFetchUserProfileUpdatedUseCase( - skillLabClient: SkillLabClient, - skillLabUserProfileSyncRepository: SkillLabUserProfileSyncRepository, - userProfileUpdatePublisher: UserProfileUpdatePublisher, - ): FetchUserProfileUpdatesUseCase = SkillLabFetchUserProfileUpdatesUseCase( - skillLabClient = skillLabClient, - skillLabUserProfileSyncRepository = skillLabUserProfileSyncRepository, - userProfileUpdatePublisher = userProfileUpdatePublisher, - ) - - @Bean - @ConditionalOnProperty( - prefix = "skilllab-api-client-configuration", - name = ["enabled"], - havingValue = "true", - matchIfMissing = false - ) - fun skillLabSyncUserProfileUseCase( - skillLabClient: SkillLabClient, - skillLabUserProfileRepository: SkillLabUserProfileRepository, - ): SyncUserProfileUseCase = SkillLabSyncUserProfileUseCase( - skillLabClient = skillLabClient, - skillLabUserProfileRepository = skillLabUserProfileRepository, - ) - - @Bean - fun sqlSearchUserProfileUseCase( - skillLabUserProfileRepository: SkillLabUserProfileRepository, - ): SearchUserProfileUseCase = SqlSearchUserProfileUseCase( - userProfileRepository = skillLabUserProfileRepository, - ) -} diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfigurationSkillLab.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfigurationSkillLab.kt new file mode 100644 index 0000000..ef1a24d --- /dev/null +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfigurationSkillLab.kt @@ -0,0 +1,96 @@ +package com.aamdigital.aambackendservice.skill.di + +import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesUseCase +import com.aamdigital.aambackendservice.skill.core.SearchUserProfileUseCase +import com.aamdigital.aambackendservice.skill.core.SqlSearchUserProfileUseCase +import com.aamdigital.aambackendservice.skill.core.SyncUserProfileUseCase +import com.aamdigital.aambackendservice.skill.core.UserProfileMatcher +import com.aamdigital.aambackendservice.skill.core.UserProfileUpdatePublisher +import com.aamdigital.aambackendservice.skill.repository.SkillLabUserProfileRepository +import com.aamdigital.aambackendservice.skill.repository.SkillLabUserProfileSyncRepository +import com.aamdigital.aambackendservice.skill.skilllab.SkillLabClient +import com.aamdigital.aambackendservice.skill.skilllab.SkillLabFetchUserProfileUpdatesUseCase +import com.aamdigital.aambackendservice.skill.skilllab.SkillLabSyncUserProfileUseCase +import com.aamdigital.aambackendservice.skill.skilllab.SkillLabUserProfileMatcher +import com.fasterxml.jackson.databind.ObjectMapper +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpHeaders +import org.springframework.http.client.SimpleClientHttpRequestFactory +import org.springframework.web.client.RestClient + + +@Configuration +@ConditionalOnProperty( + prefix = "features.skill-api", + name = ["mode"], + havingValue = "skilllab", + matchIfMissing = false +) +class SkillConfigurationSkillLab { + + @Bean(name = ["skilllab-api-client"]) + fun skillLabApiClient( + configuration: SkillLabApiClientConfiguration + ): RestClient { + val clientBuilder = RestClient.builder().baseUrl(configuration.basePath) + + clientBuilder.defaultRequest { request -> + request.headers { + it.set(HttpHeaders.AUTHORIZATION, "Bearer ${configuration.apiKey}") + } + } + + clientBuilder.requestFactory(SimpleClientHttpRequestFactory().apply { + setReadTimeout(configuration.responseTimeoutInSeconds * 1000) + setConnectTimeout(configuration.responseTimeoutInSeconds * 1000) + }) + + return clientBuilder.build() + } + + @Bean + fun skillLabClient( + @Qualifier("skilllab-api-client") restClient: RestClient, + objectMapper: ObjectMapper, + ): SkillLabClient = SkillLabClient( + http = restClient, + objectMapper = objectMapper, + ) + + @Bean + fun skillLabUserProfileMatcher( + @Qualifier("skilllab-api-client") restClient: RestClient, + ): UserProfileMatcher = SkillLabUserProfileMatcher( + http = restClient + ) + + @Bean + fun skillLabFetchUserProfileUpdatedUseCase( + skillLabClient: SkillLabClient, + skillLabUserProfileSyncRepository: SkillLabUserProfileSyncRepository, + userProfileUpdatePublisher: UserProfileUpdatePublisher, + ): FetchUserProfileUpdatesUseCase = SkillLabFetchUserProfileUpdatesUseCase( + skillLabClient = skillLabClient, + skillLabUserProfileSyncRepository = skillLabUserProfileSyncRepository, + userProfileUpdatePublisher = userProfileUpdatePublisher, + ) + + @Bean + fun skillLabSyncUserProfileUseCase( + skillLabClient: SkillLabClient, + skillLabUserProfileRepository: SkillLabUserProfileRepository, + ): SyncUserProfileUseCase = SkillLabSyncUserProfileUseCase( + skillLabClient = skillLabClient, + skillLabUserProfileRepository = skillLabUserProfileRepository, + ) + + @Bean + fun sqlSearchUserProfileUseCase( + skillLabUserProfileRepository: SkillLabUserProfileRepository, + ): SearchUserProfileUseCase = SqlSearchUserProfileUseCase( + userProfileRepository = skillLabUserProfileRepository, + ) +} diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/UserProfileUpdateEventQueueConfiguration.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/UserProfileUpdateEventQueueConfiguration.kt index 5551824..146d522 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/UserProfileUpdateEventQueueConfiguration.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/UserProfileUpdateEventQueueConfiguration.kt @@ -10,13 +10,19 @@ import com.fasterxml.jackson.databind.ObjectMapper import org.springframework.amqp.core.Queue import org.springframework.amqp.core.QueueBuilder import org.springframework.amqp.rabbit.core.RabbitTemplate +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration +@ConditionalOnProperty( + prefix = "features.skill-api", + name = ["mode"], + havingValue = "skilllab", + matchIfMissing = false +) class UserProfileUpdateEventQueueConfiguration { - // todo configuration companion object { const val USER_PROFILE_UPDATE_QUEUE = "skill.userProfile.update" } diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/job/SyncSkillsJob.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/job/SyncSkillsJob.kt index afd57e1..86629fa 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/job/SyncSkillsJob.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/job/SyncSkillsJob.kt @@ -4,10 +4,17 @@ import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesReques import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesUseCase import com.aamdigital.aambackendservice.skill.di.SkillLabApiClientConfiguration import org.slf4j.LoggerFactory +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.context.annotation.Configuration import org.springframework.scheduling.annotation.Scheduled @Configuration +@ConditionalOnProperty( + prefix = "features.skill-api", + name = ["mode"], + havingValue = "skilllab", + matchIfMissing = false +) class SyncSkillsJob( private val skillLabFetchUserProfileUpdatesUseCase: FetchUserProfileUpdatesUseCase, private val skillLabApiClientConfiguration: SkillLabApiClientConfiguration, diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSkillStorage.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSkillStorage.kt deleted file mode 100644 index bec0451..0000000 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSkillStorage.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.aamdigital.aambackendservice.skill.skilllab - -import com.aamdigital.aambackendservice.domain.DomainReference -import com.aamdigital.aambackendservice.skill.core.SkillStorage -import com.aamdigital.aambackendservice.skill.domain.EscoSkill -import org.springframework.data.domain.Pageable -import org.springframework.web.client.RestClient - -class SkillLabSkillStorage( - val http: RestClient -) : SkillStorage { - override fun fetchSkill(externalIdentifier: DomainReference): EscoSkill { - TODO("Not yet implemented") - } - - override fun fetchSkills(pageable: Pageable): List { - TODO("Not yet implemented") - } -} diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSyncUserProfileUseCase.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSyncUserProfileUseCase.kt index c0c7ab9..6fdc2d3 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSyncUserProfileUseCase.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSyncUserProfileUseCase.kt @@ -92,7 +92,6 @@ class SkillLabSyncUserProfileUseCase( ) } - private fun getSkillEntities(userProfile: SkillLabProfileDto): Set = userProfile.experiences .flatMap { it.experiencesSkills } .map { diff --git a/application/aam-backend-service/src/main/resources/application.yaml b/application/aam-backend-service/src/main/resources/application.yaml index 19c9891..48a7165 100644 --- a/application/aam-backend-service/src/main/resources/application.yaml +++ b/application/aam-backend-service/src/main/resources/application.yaml @@ -23,7 +23,6 @@ spring: multipart: max-file-size: 5MB - server: servlet: context-path: /api @@ -43,6 +42,10 @@ management: sampling: probability: 1 +features: + skill-api: + mode: disabled + # enable/disables event processing for each queue events: listener: @@ -53,6 +56,8 @@ logging: logback: rollingpolicy: max-file-size: 100MB + total-size-cap: 100MB + clean-history-on-start: true --- @@ -92,6 +97,7 @@ logging: # org.springframework.amqp.rabbit: warn # org.springframework.web: debug # org.springframework.http: debug + # org.springframework.security: debug com.aamdigital.aambackendservice: trace aam-render-api-client-configuration: @@ -114,12 +120,15 @@ sqs-client-configuration: basic-auth-password: docker skilllab-api-client-configuration: - enabled: true api-key: skilllab-api-key project-id: dummy-project base-path: http://localhost:9005/skilllab response-timeout-in-seconds: 15 +features: + skill-api: + mode: skilllab + events: listener: report-calculation: diff --git a/application/aam-backend-service/src/test/resources/application-e2e.yaml b/application/aam-backend-service/src/test/resources/application-e2e.yaml index 5b4f75a..4b8f20b 100644 --- a/application/aam-backend-service/src/test/resources/application-e2e.yaml +++ b/application/aam-backend-service/src/test/resources/application-e2e.yaml @@ -27,7 +27,7 @@ spring: server: servlet: - context-path: /api + context-path: / port: 9000 management: @@ -64,16 +64,19 @@ sqs-client-configuration: basic-auth-password: docker skilllab-api-client-configuration: - enabled: false api-key: skilllab-api-key project-id: dummy-project base-path: http://localhost:9005/skilllab # todo test container response-timeout-in-seconds: 15 +features: + skill-api: + mode: disabled + events: listener: report-calculation: - enabled: false + enabled: true database-change-detection: enabled: false