diff --git a/orca-api/src/main/java/com/netflix/spinnaker/orca/api/pipeline/models/PipelineExecution.java b/orca-api/src/main/java/com/netflix/spinnaker/orca/api/pipeline/models/PipelineExecution.java index 80cff63bab..affe205e14 100644 --- a/orca-api/src/main/java/com/netflix/spinnaker/orca/api/pipeline/models/PipelineExecution.java +++ b/orca-api/src/main/java/com/netflix/spinnaker/orca/api/pipeline/models/PipelineExecution.java @@ -15,14 +15,14 @@ */ package com.netflix.spinnaker.orca.api.pipeline.models; -import static java.util.Arrays.asList; import static java.util.Collections.emptySet; -import com.google.common.collect.ImmutableSet; import com.netflix.spinnaker.kork.annotations.Beta; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -161,18 +161,25 @@ public void setUser(@Nullable String user) { private Collection allowedAccounts = emptySet(); public Collection getAllowedAccounts() { - return ImmutableSet.copyOf(allowedAccounts); + return allowedAccounts; } public void setAllowedAccounts(Collection allowedAccounts) { - this.allowedAccounts = ImmutableSet.copyOf(allowedAccounts); + this.allowedAccounts = Set.copyOf(allowedAccounts); } - public AuthenticationDetails() {} + public AuthenticationDetails() { + this(null, Collections.emptySet()); + } public AuthenticationDetails(String user, String... allowedAccounts) { + this(user, Set.of(allowedAccounts)); + } + + public AuthenticationDetails(String user, Collection allowedAccounts) { this.user = user; - this.allowedAccounts = asList(allowedAccounts); + this.allowedAccounts = + allowedAccounts == null ? Collections.emptySet() : Set.copyOf(allowedAccounts); } } diff --git a/orca-api/src/main/java/com/netflix/spinnaker/orca/api/pipeline/models/StageExecution.java b/orca-api/src/main/java/com/netflix/spinnaker/orca/api/pipeline/models/StageExecution.java index 240c1b0361..b67ffa6352 100644 --- a/orca-api/src/main/java/com/netflix/spinnaker/orca/api/pipeline/models/StageExecution.java +++ b/orca-api/src/main/java/com/netflix/spinnaker/orca/api/pipeline/models/StageExecution.java @@ -17,7 +17,6 @@ import static java.util.Collections.emptySet; -import com.google.common.collect.ImmutableSet; import com.netflix.spinnaker.kork.annotations.Beta; import com.netflix.spinnaker.orca.api.pipeline.SyntheticStageOwner; import java.util.*; @@ -195,11 +194,11 @@ class LastModifiedDetails { @NonNull private Long lastModifiedTime; public @Nonnull Collection getAllowedAccounts() { - return ImmutableSet.copyOf(allowedAccounts); + return Set.copyOf(allowedAccounts); } public void setAllowedAccounts(@Nonnull Collection allowedAccounts) { - this.allowedAccounts = ImmutableSet.copyOf(allowedAccounts); + this.allowedAccounts = Set.copyOf(allowedAccounts); } } } diff --git a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pollers/RestorePinnedServerGroupsPoller.java b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pollers/RestorePinnedServerGroupsPoller.java index d3bb6ec8f1..2e5ab889b8 100644 --- a/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pollers/RestorePinnedServerGroupsPoller.java +++ b/orca-clouddriver/src/main/java/com/netflix/spinnaker/orca/clouddriver/pollers/RestorePinnedServerGroupsPoller.java @@ -35,8 +35,6 @@ import com.netflix.spinnaker.orca.pipeline.persistence.ExecutionNotFoundException; import com.netflix.spinnaker.orca.pipeline.persistence.ExecutionRepository; import com.netflix.spinnaker.security.AuthenticatedRequest; -import com.netflix.spinnaker.security.User; -import groovy.util.logging.Slf4j; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -47,7 +45,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; -@Slf4j @Component @ConditionalOnExpression(value = "${pollers.restore-pinned-server-groups.enabled:false}") public class RestorePinnedServerGroupsPoller extends AbstractPollingNotificationAgent { @@ -151,19 +148,17 @@ protected void tick() { try { List> jobs = new ArrayList<>(); jobs.add(buildDeleteEntityTagsOperation(pinnedServerGroupTag)); - - User systemUser = new User(); - systemUser.setUsername(username); - systemUser.setAllowedAccounts(Collections.singletonList(pinnedServerGroupTag.account)); + var allowedAccount = Collections.singletonList(pinnedServerGroupTag.account); Optional serverGroup = - AuthenticatedRequest.propagate( + AuthenticatedRequest.runAs( + username, + allowedAccount, () -> pollerSupport.fetchServerGroup( pinnedServerGroupTag.account, pinnedServerGroupTag.location, - pinnedServerGroupTag.serverGroup), - systemUser) + pinnedServerGroupTag.serverGroup)) .call(); serverGroup.ifPresent( @@ -183,12 +178,13 @@ protected void tick() { buildCleanupOperation(pinnedServerGroupTag, serverGroup, jobs); log.info((String) cleanupOperation.get("name")); - AuthenticatedRequest.propagate( + AuthenticatedRequest.runAs( + username, + allowedAccount, () -> executionLauncher.start( ExecutionType.ORCHESTRATION, - objectMapper.writeValueAsString(cleanupOperation)), - systemUser) + objectMapper.writeValueAsString(cleanupOperation))) .call(); triggeredCounter.increment(); diff --git a/orca-core/src/main/java/com/netflix/spinnaker/orca/AuthenticatedStage.java b/orca-core/src/main/java/com/netflix/spinnaker/orca/AuthenticatedStage.java index 5406cea4f8..375a8695d4 100644 --- a/orca-core/src/main/java/com/netflix/spinnaker/orca/AuthenticatedStage.java +++ b/orca-core/src/main/java/com/netflix/spinnaker/orca/AuthenticatedStage.java @@ -15,8 +15,8 @@ */ package com.netflix.spinnaker.orca; +import com.netflix.spinnaker.orca.api.pipeline.models.PipelineExecution; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; -import com.netflix.spinnaker.security.User; import java.util.Optional; /** @@ -28,5 +28,5 @@ * module for just the User class? */ public interface AuthenticatedStage { - Optional authenticatedUser(StageExecution stage); + Optional authenticatedUser(StageExecution stage); } diff --git a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/expressions/functions/StageExpressionFunctionProvider.java b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/expressions/functions/StageExpressionFunctionProvider.java index 107d45a994..20fb5fd900 100644 --- a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/expressions/functions/StageExpressionFunctionProvider.java +++ b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/expressions/functions/StageExpressionFunctionProvider.java @@ -24,6 +24,7 @@ import com.netflix.spinnaker.orca.api.pipeline.models.PipelineExecution; import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; import java.util.Arrays; +import java.util.Optional; import java.util.function.Predicate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -53,6 +54,8 @@ public Functions getFunctions() { PipelineExecution.class, "execution", "The execution containing the currently executing stage")), + new FunctionDefinition( + "currentUser", "Looks up the current authenticated user within the execution context."), new FunctionDefinition( "stageByRefId", "Locates and returns a stage with the given refId", @@ -106,6 +109,14 @@ public static StageExecution currentStage(PipelineExecution execution) { new SpelHelperFunctionException("No stage found with id '" + currentStageId + "'")); } + /** @return the current authenticated user in the Execution or anonymous. */ + @SuppressWarnings("unused") + public static String currentUser() { + return Optional.ofNullable(ExecutionContext.get()) + .map(ExecutionContext::getAuthenticatedUser) + .orElse("anonymous"); + } + /** * Finds a Stage by refId. This function should only be used by programmatic pipeline generators, * as refIds are fragile and may change from execution-to-execution. @@ -186,6 +197,7 @@ public static String judgment(PipelineExecution execution, String id) { } /** Alias to judgment */ + @SuppressWarnings("unused") public static String judgement(PipelineExecution execution, String id) { return judgment(execution, id); } diff --git a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/model/PipelineExecutionImpl.java b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/model/PipelineExecutionImpl.java index 384e56dec6..1339efe858 100644 --- a/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/model/PipelineExecutionImpl.java +++ b/orca-core/src/main/java/com/netflix/spinnaker/orca/pipeline/model/PipelineExecutionImpl.java @@ -33,7 +33,6 @@ import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution; import com.netflix.spinnaker.orca.api.pipeline.models.Trigger; import com.netflix.spinnaker.security.AuthenticatedRequest; -import com.netflix.spinnaker.security.User; import de.huxhorn.sulky.ulid.ULID; import java.io.Serializable; import java.util.ArrayList; @@ -435,17 +434,5 @@ public static Optional build() { return Optional.empty(); } - - public static Optional toKorkUser(AuthenticationDetails authentication) { - return Optional.ofNullable(authentication) - .map(AuthenticationDetails::getUser) - .map( - it -> { - User user = new User(); - user.setEmail(it); - user.setAllowedAccounts(authentication.getAllowedAccounts()); - return user; - }); - } } } diff --git a/orca-echo/src/main/groovy/com/netflix/spinnaker/orca/echo/pipeline/ManualJudgmentStage.groovy b/orca-echo/src/main/groovy/com/netflix/spinnaker/orca/echo/pipeline/ManualJudgmentStage.groovy index 97731e7f80..5f61847868 100644 --- a/orca-echo/src/main/groovy/com/netflix/spinnaker/orca/echo/pipeline/ManualJudgmentStage.groovy +++ b/orca-echo/src/main/groovy/com/netflix/spinnaker/orca/echo/pipeline/ManualJudgmentStage.groovy @@ -21,9 +21,11 @@ import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonIgnore import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus import com.netflix.spinnaker.orca.api.pipeline.OverridableTimeoutRetryableTask +import com.netflix.spinnaker.orca.api.pipeline.models.PipelineExecution import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution import com.netflix.spinnaker.orca.api.pipeline.TaskResult import com.netflix.spinnaker.orca.echo.util.ManualJudgmentAuthorization +import com.netflix.spinnaker.orca.pipeline.model.PipelineExecutionImpl import javax.annotation.Nonnull import java.util.concurrent.TimeUnit @@ -32,7 +34,6 @@ import com.netflix.spinnaker.orca.* import com.netflix.spinnaker.orca.echo.EchoService import com.netflix.spinnaker.orca.api.pipeline.graph.StageDefinitionBuilder import com.netflix.spinnaker.orca.api.pipeline.graph.TaskNode -import com.netflix.spinnaker.security.User import groovy.util.logging.Slf4j import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component @@ -53,17 +54,16 @@ class ManualJudgmentStage implements StageDefinitionBuilder, AuthenticatedStage } @Override - Optional authenticatedUser(StageExecution stage) { + Optional authenticatedUser(StageExecution stage) { def stageData = stage.mapTo(StageData) if (stageData.state != StageData.State.CONTINUE || !stage.lastModified?.user || !stageData.propagateAuthenticationContext) { return Optional.empty() } - def user = new User() - user.setAllowedAccounts(stage.lastModified.allowedAccounts) - user.setUsername(stage.lastModified.user) - user.setEmail(stage.lastModified.user) - return Optional.of(user.asImmutable()) + return Optional.of( + new PipelineExecution.AuthenticationDetails( + stage.lastModified.user, + stage.lastModified.allowedAccounts)); } @Slf4j diff --git a/orca-echo/src/main/groovy/com/netflix/spinnaker/orca/echo/spring/EchoNotifyingExecutionListener.groovy b/orca-echo/src/main/groovy/com/netflix/spinnaker/orca/echo/spring/EchoNotifyingExecutionListener.groovy index 99834fb4c9..2da2b6c01a 100644 --- a/orca-echo/src/main/groovy/com/netflix/spinnaker/orca/echo/spring/EchoNotifyingExecutionListener.groovy +++ b/orca-echo/src/main/groovy/com/netflix/spinnaker/orca/echo/spring/EchoNotifyingExecutionListener.groovy @@ -23,7 +23,6 @@ import com.netflix.spinnaker.orca.front50.Front50Service import com.netflix.spinnaker.orca.front50.model.ApplicationNotifications import com.netflix.spinnaker.orca.listeners.ExecutionListener import com.netflix.spinnaker.orca.listeners.Persister -import com.netflix.spinnaker.orca.pipeline.model.PipelineExecutionImpl import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor import com.netflix.spinnaker.security.AuthenticatedRequest import groovy.transform.CompileStatic @@ -121,12 +120,12 @@ class EchoNotifyingExecutionListener implements ExecutionListener { * @param pipeline */ private void addApplicationNotifications(PipelineExecution pipeline) { - def user = PipelineExecutionImpl.AuthenticationHelper.toKorkUser(pipeline.getAuthentication()) + def user = pipeline.authentication?.user ApplicationNotifications notifications - if (user?.isPresent()) { - notifications = AuthenticatedRequest.propagate({ + if (user) { + notifications = AuthenticatedRequest.runAs(user, pipeline.authentication.allowedAccounts ?: [] as Collection, { front50Service.getApplicationNotifications(pipeline.application) - }, user.get()).call() + }).call() } else { notifications = AuthenticatedRequest.allowAnonymous({ front50Service.getApplicationNotifications(pipeline.application) diff --git a/orca-echo/src/test/groovy/com/netflix/spinnaker/orca/echo/pipeline/ManualJudgmentStageSpec.groovy b/orca-echo/src/test/groovy/com/netflix/spinnaker/orca/echo/pipeline/ManualJudgmentStageSpec.groovy index 47969c7bfc..a64325789e 100644 --- a/orca-echo/src/test/groovy/com/netflix/spinnaker/orca/echo/pipeline/ManualJudgmentStageSpec.groovy +++ b/orca-echo/src/test/groovy/com/netflix/spinnaker/orca/echo/pipeline/ManualJudgmentStageSpec.groovy @@ -236,7 +236,7 @@ class ManualJudgmentStageSpec extends Specification { then: authenticatedUser.isPresent() == isPresent - !isPresent || (authenticatedUser.get().username == "modifiedUser" && authenticatedUser.get().allowedAccounts == ["group1"]) + !isPresent || (authenticatedUser.get().user == "modifiedUser" && authenticatedUser.get().allowedAccounts.toList() == ["group1"]) where: judgmentStatus | propagateAuthenticationContext || isPresent diff --git a/orca-echo/src/test/groovy/com/netflix/spinnaker/orca/echo/spring/EchoNotifyingPipelineExecutionListenerSpec.groovy b/orca-echo/src/test/groovy/com/netflix/spinnaker/orca/echo/spring/EchoNotifyingPipelineExecutionListenerSpec.groovy index e1d9470147..90eb9da359 100644 --- a/orca-echo/src/test/groovy/com/netflix/spinnaker/orca/echo/spring/EchoNotifyingPipelineExecutionListenerSpec.groovy +++ b/orca-echo/src/test/groovy/com/netflix/spinnaker/orca/echo/spring/EchoNotifyingPipelineExecutionListenerSpec.groovy @@ -225,7 +225,7 @@ class EchoNotifyingPipelineExecutionListenerSpec extends Specification { 1 * front50Service.getApplicationNotifications("myapp") >> { assert MDC.get(Header.USER.header) == "user@schibsted.com" - assert MDC.get(Header.ACCOUNTS.header) == "someAccount,anotherAccount" + assert MDC.get(Header.ACCOUNTS.header).split(",").toList().toSorted() == ["anotheraccount", "someaccount"] return notifications } 1 * echoService.recordEvent(_) diff --git a/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarter.groovy b/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarter.groovy index ebbad69997..f7692eca1b 100644 --- a/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarter.groovy +++ b/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarter.groovy @@ -28,7 +28,6 @@ import com.netflix.spinnaker.orca.pipeline.ExecutionLauncher import com.netflix.spinnaker.orca.pipeline.util.ArtifactUtils import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor import com.netflix.spinnaker.security.AuthenticatedRequest -import com.netflix.spinnaker.security.User import groovy.util.logging.Slf4j import org.springframework.beans.BeansException import org.springframework.beans.factory.annotation.Autowired @@ -70,7 +69,7 @@ class DependentPipelineStarter implements ApplicationContextAware { PipelineExecution parentPipeline, Map suppliedParameters, String parentPipelineStageId, - User principal) { + PipelineExecution.AuthenticationDetails authenticationDetails) { def json = objectMapper.writeValueAsString(pipelineConfig) if (pipelineConfig.disabled) { @@ -81,7 +80,7 @@ class DependentPipelineStarter implements ApplicationContextAware { pipelineConfig.trigger = [ type : "pipeline", - user : principal?.username ?: user ?: "[anonymous]", + user : authenticationDetails?.user ?: user ?: "[anonymous]", parentExecution : parentPipeline, parentPipelineStageId: parentPipelineStageId, parameters : [:], @@ -153,11 +152,11 @@ class DependentPipelineStarter implements ApplicationContextAware { log.info('running pipeline {}:{}', pipelineConfig.id, json) log.debug("Source thread: MDC user: " + AuthenticatedRequest.getAuthenticationHeaders() + - ", principal: " + principal?.toString()) + ", principal: " + authenticationDetails?.toString()) Callable callable if (artifactError == null) { - callable = AuthenticatedRequest.propagate({ + callable = { log.debug("Destination thread user: " + AuthenticatedRequest.getAuthenticationHeaders()) return executionLauncher().start(PIPELINE, json).with { Id id = registry.createId("pipelines.triggered") @@ -166,15 +165,17 @@ class DependentPipelineStarter implements ApplicationContextAware { registry.counter(id).increment() return it } - } as Callable, true, principal) + } as Callable } else { - callable = AuthenticatedRequest.propagate({ + callable = { log.debug("Destination thread user: " + AuthenticatedRequest.getAuthenticationHeaders()) return executionLauncher().fail(PIPELINE, json, artifactError) - } as Callable, true, principal) + } as Callable } - def pipeline = callable.call() + def pipeline = authenticationDetails?.user ? + AuthenticatedRequest.runAs(authenticationDetails.user, authenticationDetails.allowedAccounts, callable).call() : + AuthenticatedRequest.propagate(callable).call() log.info('executing dependent pipeline {}', pipeline.id) return pipeline diff --git a/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/spring/DependentPipelineExecutionListener.groovy b/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/spring/DependentPipelineExecutionListener.groovy index 421172d8dc..37ebbb4d0a 100644 --- a/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/spring/DependentPipelineExecutionListener.groovy +++ b/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/spring/DependentPipelineExecutionListener.groovy @@ -28,7 +28,6 @@ import com.netflix.spinnaker.orca.listeners.Persister import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor import com.netflix.spinnaker.orca.pipelinetemplate.V2Util import com.netflix.spinnaker.security.AuthenticatedRequest -import com.netflix.spinnaker.security.User import groovy.transform.CompileDynamic import groovy.util.logging.Slf4j import org.springframework.beans.factory.annotation.Autowired @@ -101,11 +100,10 @@ class DependentPipelineExecutionListener implements ExecutionListener { trigger.pipeline == execution.pipelineConfigId && trigger.status.contains(status) ) { - User authenticatedUser = null + PipelineExecution.AuthenticationDetails authenticatedUser = null if (fiatStatus.enabled && trigger.runAsUser) { - authenticatedUser = new User() - authenticatedUser.setEmail(trigger.runAsUser) + authenticatedUser = new PipelineExecution.AuthenticationDetails(trigger.runAsUser) } dependentPipelineStarter.trigger( diff --git a/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/tasks/StartPipelineTask.groovy b/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/tasks/StartPipelineTask.groovy index f5cb535332..b2b85df9db 100644 --- a/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/tasks/StartPipelineTask.groovy +++ b/orca-front50/src/main/groovy/com/netflix/spinnaker/orca/front50/tasks/StartPipelineTask.groovy @@ -25,11 +25,9 @@ import com.netflix.spinnaker.orca.api.pipeline.TaskResult import com.netflix.spinnaker.orca.extensionpoint.pipeline.ExecutionPreprocessor import com.netflix.spinnaker.orca.front50.DependentPipelineStarter import com.netflix.spinnaker.orca.front50.Front50Service -import com.netflix.spinnaker.orca.pipeline.model.PipelineExecutionImpl import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor import com.netflix.spinnaker.orca.pipelinetemplate.V2Util import com.netflix.spinnaker.security.AuthenticatedRequest -import com.netflix.spinnaker.security.User import groovy.util.logging.Slf4j import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component @@ -82,7 +80,7 @@ class StartPipelineTask implements Task { pipelineConfig = V2Util.planPipeline(contextParameterProcessor, executionPreprocessors, pipelineConfig) } - def parameters = stage.context.pipelineParameters ?: [:] + Map parameters = stage.context.pipelineParameters ?: [:] if (isStrategy) { def deploymentDetails = stage.context.deploymentDetails?.collect { Map it -> @@ -110,7 +108,7 @@ class StartPipelineTask implements Task { def pipeline = dependentPipelineStarter.trigger( pipelineConfig, - stage.context.user, + stage.context.user as String, stage.execution, parameters, stage.id, @@ -126,15 +124,15 @@ class StartPipelineTask implements Task { // // In the case of the implicit pipeline invocation, the MDC is empty, which is why we fall back // to Execution.AuthenticationDetails of the parent pipeline. - User getUser(PipelineExecution parentPipeline) { + PipelineExecution.AuthenticationDetails getUser(PipelineExecution parentPipeline) { def korkUsername = AuthenticatedRequest.getSpinnakerUser() if (korkUsername.isPresent()) { def korkAccounts = AuthenticatedRequest.getSpinnakerAccounts().orElse("") - return new User(email: korkUsername.get(), allowedAccounts: korkAccounts?.split(",")?.toList() ?: []).asImmutable() + return new PipelineExecution.AuthenticationDetails(korkUsername.get(), korkAccounts.split(",")) } if (parentPipeline.authentication?.user) { - return PipelineExecutionImpl.AuthenticationHelper.toKorkUser(parentPipeline.authentication).get() + return parentPipeline.authentication } return null diff --git a/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarterSpec.groovy b/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarterSpec.groovy index 62ee2a77ce..9c7e398540 100644 --- a/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarterSpec.groovy +++ b/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/DependentPipelineStarterSpec.groovy @@ -39,7 +39,6 @@ import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.handler.v2.V2SchemaH import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.model.PipelineTemplate import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.model.TemplateConfiguration import com.netflix.spinnaker.orca.pipelinetemplate.v1schema.render.JinjaRenderer -import com.netflix.spinnaker.security.User import org.slf4j.MDC import org.springframework.context.ApplicationContext import org.springframework.context.support.StaticApplicationContext @@ -405,10 +404,8 @@ class DependentPipelineStarterSpec extends Specification { result.trigger.parameters.a == true } - private static User buildAuthenticatedUser(String email, List allowedAccounts) { - def authenticatedUser = new User() - authenticatedUser.setEmail(email) - authenticatedUser.setAllowedAccounts(allowedAccounts) + private static PipelineExecution.AuthenticationDetails buildAuthenticatedUser(String email, List allowedAccounts) { + def authenticatedUser = new PipelineExecution.AuthenticationDetails(email, allowedAccounts) return authenticatedUser } diff --git a/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/spring/DependentPipelineExecutionListenerSpec.groovy b/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/spring/DependentPipelineExecutionListenerSpec.groovy index 5a2fe03075..abdb6d3609 100644 --- a/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/spring/DependentPipelineExecutionListenerSpec.groovy +++ b/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/spring/DependentPipelineExecutionListenerSpec.groovy @@ -18,13 +18,13 @@ package com.netflix.spinnaker.orca.front50.spring import com.netflix.spinnaker.fiat.shared.FiatStatus import com.netflix.spinnaker.orca.api.pipeline.models.ExecutionStatus +import com.netflix.spinnaker.orca.api.pipeline.models.PipelineExecution import com.netflix.spinnaker.orca.api.pipeline.models.TaskExecution import com.netflix.spinnaker.orca.front50.DependentPipelineStarter import com.netflix.spinnaker.orca.front50.Front50Service import com.netflix.spinnaker.orca.front50.pipeline.PipelineStage import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor import com.netflix.spinnaker.orca.pipelinetemplate.V2Util -import com.netflix.spinnaker.security.User import spock.lang.Specification import spock.lang.Subject @@ -75,7 +75,7 @@ class DependentPipelineExecutionListenerSpec extends Specification { then: 1 * dependentPipelineStarter.trigger(_, _, _, _, _, null) - 1 * dependentPipelineStarter.trigger(_, _, _, _, _, { User user -> user.email == "my_run_as_user" }) + 1 * dependentPipelineStarter.trigger(_, _, _, _, _, { PipelineExecution.AuthenticationDetails user -> user.user == "my_run_as_user" }) where: status << [ExecutionStatus.SUCCEEDED, ExecutionStatus.TERMINAL] @@ -100,7 +100,7 @@ class DependentPipelineExecutionListenerSpec extends Specification { then: 2 * dependentPipelineStarter.trigger(_, _, _, _, _, null) - 1 * dependentPipelineStarter.trigger(_, _, _, _, _, { User user -> user.email == "my_run_as_user" }) + 1 * dependentPipelineStarter.trigger(_, _, _, _, _, { PipelineExecution.AuthenticationDetails user -> user.user == "my_run_as_user" }) where: status << [ExecutionStatus.SUCCEEDED, ExecutionStatus.TERMINAL] diff --git a/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/tasks/StartPipelineTaskSpec.groovy b/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/tasks/StartPipelineTaskSpec.groovy index 8cb29e1af2..d701ea74f5 100644 --- a/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/tasks/StartPipelineTaskSpec.groovy +++ b/orca-front50/src/test/groovy/com/netflix/spinnaker/orca/front50/tasks/StartPipelineTaskSpec.groovy @@ -21,7 +21,6 @@ import com.netflix.spinnaker.orca.extensionpoint.pipeline.ExecutionPreprocessor import com.netflix.spinnaker.orca.front50.DependentPipelineStarter import com.netflix.spinnaker.orca.front50.Front50Service import com.netflix.spinnaker.orca.pipeline.util.ContextParameterProcessor -import com.netflix.spinnaker.security.User import spock.lang.Specification import spock.lang.Subject import spock.lang.Unroll @@ -68,7 +67,7 @@ class StartPipelineTaskSpec extends Specification { def gotContext def parentPipelineStageId - User authenticatedUser + AuthenticationDetails authenticatedUser when: def result = task.execute(stage) @@ -100,11 +99,11 @@ class StartPipelineTaskSpec extends Specification { ] parentPipelineStageId == stage.id - authenticatedUser?.email == expectedAuthenticatedEmail + authenticatedUser?.user == expectedAuthenticatedUsername authenticatedUser?.allowedAccounts?.toList() == expectedAuthenticatedAllowedAccounts where: - authentication || expectedAuthenticatedEmail || expectedAuthenticatedAllowedAccounts + authentication || expectedAuthenticatedUsername || expectedAuthenticatedAllowedAccounts null || null || null new AuthenticationDetails( "authenticated_user", diff --git a/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/handler/AuthenticationAware.kt b/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/handler/AuthenticationAware.kt index c8971ac155..2e1d200085 100644 --- a/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/handler/AuthenticationAware.kt +++ b/orca-queue/src/main/kotlin/com/netflix/spinnaker/orca/q/handler/AuthenticationAware.kt @@ -21,7 +21,7 @@ import com.netflix.spinnaker.orca.ExecutionContext import com.netflix.spinnaker.orca.api.pipeline.models.StageExecution import com.netflix.spinnaker.orca.pipeline.util.StageNavigator import com.netflix.spinnaker.security.AuthenticatedRequest -import com.netflix.spinnaker.security.User +import org.apache.commons.lang3.StringUtils interface AuthenticationAware { @@ -33,16 +33,13 @@ interface AuthenticationAware { .firstOrNull { it.stageBuilder is AuthenticatedStage } ?.let { (it.stageBuilder as AuthenticatedStage).authenticatedUser(it.stage).orElse(null) } - val currentUser = authenticatedUser ?: User().apply { - email = execution.authentication?.user - allowedAccounts = execution.authentication?.allowedAccounts - } + val currentUser = authenticatedUser ?: execution.authentication try { ExecutionContext.set( ExecutionContext( execution.application, - currentUser.username, + currentUser?.user, execution.type.name.toLowerCase(), execution.id, this.id, @@ -50,7 +47,11 @@ interface AuthenticationAware { this.startTime ) ) - AuthenticatedRequest.propagate(block, false, currentUser).call() + if (StringUtils.isNotBlank(currentUser?.user)) { + AuthenticatedRequest.runAs(currentUser.user, currentUser.allowedAccounts, false, block).call() + } else { + AuthenticatedRequest.propagate(block, false).call() + } } finally { ExecutionContext.clear() }