From 5fa05c0d1fbad91384838cb2304591b88986250d Mon Sep 17 00:00:00 2001 From: Justin Field Date: Fri, 12 Mar 2021 11:09:31 -0800 Subject: [PATCH] feature: add spring security context to root stage in canary and standalone canary pipelines if enabled (#834) --- .../kayenta/canary/ExecutionMapper.java | 21 +++++++++++++++++- .../service/CanaryAnalysisService.java | 22 ++++++++++++++++--- .../controllers/BaseControllerTest.java | 3 ++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/kayenta-core/src/main/java/com/netflix/kayenta/canary/ExecutionMapper.java b/kayenta-core/src/main/java/com/netflix/kayenta/canary/ExecutionMapper.java index 086e1f2d6..7a8febedd 100644 --- a/kayenta-core/src/main/java/com/netflix/kayenta/canary/ExecutionMapper.java +++ b/kayenta-core/src/main/java/com/netflix/kayenta/canary/ExecutionMapper.java @@ -44,6 +44,8 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; @Component @@ -58,6 +60,7 @@ public class ExecutionMapper { private final List canaryScopeFactories; private final ExecutionLauncher executionLauncher; private final ExecutionRepository executionRepository; + private final boolean includeAuthentication; private final Id pipelineRunId; private final Id failureId; @@ -69,13 +72,17 @@ public ExecutionMapper( String currentInstanceId, Optional> canaryScopeFactories, ExecutionLauncher executionLauncher, - ExecutionRepository executionRepository) { + ExecutionRepository executionRepository, + @Value("${kayenta.include-spring-security-authentication-in-pipeline-context:false}") + boolean includeAuthentication) { + this.objectMapper = objectMapper; this.registry = registry; this.currentInstanceId = currentInstanceId; this.canaryScopeFactories = canaryScopeFactories.orElseGet(Collections::emptyList); this.executionLauncher = executionLauncher; this.executionRepository = executionRepository; + this.includeAuthentication = includeAuthentication; this.pipelineRunId = registry.createId("canary.pipelines.initiated"); this.failureId = registry.createId("canary.pipelines.startupFailed"); @@ -402,6 +409,12 @@ public CanaryExecutionResponse buildExecution( mapBuilder.put("parentPipelineExecutionId", parentPipelineExecutionId); } + if (includeAuthentication) { + ofNullable(SecurityContextHolder.getContext().getAuthentication()) + .ifPresent( + authentication -> mapBuilder.put("springSecurityAuthentication", authentication)); + } + HashMap setupCanaryContext = Maps.newHashMap(mapBuilder.build()); if (resolvedConfigurationAccountName != null) { setupCanaryContext.put("configurationAccountName", resolvedConfigurationAccountName); @@ -533,6 +546,12 @@ public CanaryExecutionResponse buildJudgeComparisonExecution( mapBuilder.put("parentPipelineExecutionId", parentPipelineExecutionId); } + if (includeAuthentication) { + ofNullable(SecurityContextHolder.getContext().getAuthentication()) + .ifPresent( + authentication -> mapBuilder.put("springSecurityAuthentication", authentication)); + } + HashMap setupCanaryContext = Maps.newHashMap(mapBuilder.build()); if (resolvedConfigurationAccountName != null) { diff --git a/kayenta-standalone-canary-analysis/src/main/java/com/netflix/kayenta/standalonecanaryanalysis/service/CanaryAnalysisService.java b/kayenta-standalone-canary-analysis/src/main/java/com/netflix/kayenta/standalonecanaryanalysis/service/CanaryAnalysisService.java index c9edc8f22..6a8a1544b 100644 --- a/kayenta-standalone-canary-analysis/src/main/java/com/netflix/kayenta/standalonecanaryanalysis/service/CanaryAnalysisService.java +++ b/kayenta-standalone-canary-analysis/src/main/java/com/netflix/kayenta/standalonecanaryanalysis/service/CanaryAnalysisService.java @@ -17,6 +17,7 @@ package com.netflix.kayenta.standalonecanaryanalysis.service; import static com.netflix.kayenta.standalonecanaryanalysis.orca.task.GenerateCanaryAnalysisResultTask.CANARY_ANALYSIS_EXECUTION_RESULT; +import static java.util.Optional.ofNullable; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableMap; @@ -46,6 +47,8 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; /** Service that handles starting and mapping Canary Analysis StageExecution pipelines. */ @@ -61,6 +64,7 @@ public class CanaryAnalysisService { private final StorageServiceRepository storageServiceRepository; private final ObjectMapper kayentaObjectMapper; private final AccountCredentialsRepository accountCredentialsRepository; + private final boolean includeAuthentication; @Autowired public CanaryAnalysisService( @@ -68,13 +72,16 @@ public CanaryAnalysisService( ExecutionRepository executionRepository, StorageServiceRepository storageServiceRepository, ObjectMapper kayentaObjectMapper, - AccountCredentialsRepository accountCredentialsRepository) { + AccountCredentialsRepository accountCredentialsRepository, + @Value("${kayenta.include-spring-security-authentication-in-pipeline-context:false}") + boolean includeAuthentication) { this.executionLauncher = executionLauncher; this.executionRepository = executionRepository; this.storageServiceRepository = storageServiceRepository; this.kayentaObjectMapper = kayentaObjectMapper; this.accountCredentialsRepository = accountCredentialsRepository; + this.includeAuthentication = includeAuthentication; } /** @@ -88,6 +95,16 @@ public CanaryAnalysisExecutionResponse initiateCanaryAnalysisExecution( String application = canaryAnalysisConfig.getApplication(); + var mapBuilder = + new ImmutableMap.Builder() + .put(CANARY_ANALYSIS_CONFIG_CONTEXT_KEY, canaryAnalysisConfig); + + if (includeAuthentication) { + ofNullable(SecurityContextHolder.getContext().getAuthentication()) + .ifPresent( + authentication -> mapBuilder.put("springSecurityAuthentication", authentication)); + } + PipelineBuilder pipelineBuilder = new PipelineBuilder(application) .withName(CANARY_ANALYSIS_PIPELINE_NAME) @@ -95,8 +112,7 @@ public CanaryAnalysisExecutionResponse initiateCanaryAnalysisExecution( .withStage( SetupAndExecuteCanariesStage.STAGE_TYPE, SetupAndExecuteCanariesStage.STAGE_DESCRIPTION, - Maps.newHashMap( - ImmutableMap.of(CANARY_ANALYSIS_CONFIG_CONTEXT_KEY, canaryAnalysisConfig))); + Maps.newHashMap(mapBuilder.build())); PipelineExecution pipeline = pipelineBuilder.withLimitConcurrent(false).build(); executionRepository.store(pipeline); diff --git a/kayenta-web/src/test/java/com/netflix/kayenta/controllers/BaseControllerTest.java b/kayenta-web/src/test/java/com/netflix/kayenta/controllers/BaseControllerTest.java index 6e25d63cd..5022e2fb9 100644 --- a/kayenta-web/src/test/java/com/netflix/kayenta/controllers/BaseControllerTest.java +++ b/kayenta-web/src/test/java/com/netflix/kayenta/controllers/BaseControllerTest.java @@ -94,7 +94,8 @@ ExecutionMapper executionMapper( "", Optional.empty(), executionLauncher, - executionRepository); + executionRepository, + false); } @Bean