Skip to content

Commit

Permalink
runtime-v2: add @sensitivedata annotation to hide task method paramet…
Browse files Browse the repository at this point in the history
…ers (#263)
  • Loading branch information
brig authored Dec 18, 2020
1 parent 4fdf30b commit 46ea7f6
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ public CryptoTaskV2(Context context) {
this.processOrg = projectInfo != null ? projectInfo.orgName() : null;
}

public String exportAsString(String orgName, String name, String password) throws Exception {
public String exportAsString(String orgName, String name, @SensitiveData String password) throws Exception {
return secretService.exportAsString(orgName, name, password);
}

public Map<String, String> exportKeyAsFile(String orgName, String name, String password) throws Exception {
public Map<String, String> exportKeyAsFile(String orgName, String name, @SensitiveData String password) throws Exception {
KeyPair keyPair = secretService.exportKeyAsFile(orgName, name, password);

Path baseDir = workDir;
Expand All @@ -76,7 +76,7 @@ public Map<String, String> exportKeyAsFile(String orgName, String name, String p
return m;
}

public Map<String, String> exportCredentials(String orgName, String name, String password) throws Exception {
public Map<String, String> exportCredentials(String orgName, String name, @SensitiveData String password) throws Exception {
UsernamePassword credentials = secretService.exportCredentials(orgName, name, password);

Map<String, String> m = new HashMap<>();
Expand All @@ -85,7 +85,7 @@ public Map<String, String> exportCredentials(String orgName, String name, String
return m;
}

public String exportAsFile(String orgName, String name, String password) throws Exception {
public String exportAsFile(String orgName, String name, @SensitiveData String password) throws Exception {
Path path = secretService.exportAsFile(orgName, name, password);
return workDir.relativize(path).toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.walmartlabs.concord.runtime.v2.model.Expression;
import com.walmartlabs.concord.runtime.v2.model.Step;
import com.walmartlabs.concord.runtime.v2.runner.el.MethodNotFoundException;
import com.walmartlabs.concord.runtime.v2.runner.tasks.ImmutableMethod;
import com.walmartlabs.concord.runtime.v2.runner.tasks.TaskCallInterceptor;
import com.walmartlabs.concord.runtime.v2.sdk.Context;
import com.walmartlabs.concord.runtime.v2.sdk.Task;
Expand Down Expand Up @@ -67,7 +66,7 @@ public Object invoke(ELContext elContext, Object base, Object method, Class<?>[]

TaskCallInterceptor interceptor = context.execution().runtime().getService(TaskCallInterceptor.class);
try {
return interceptor.invoke(callContext, getMethod(method, params),
return interceptor.invoke(callContext, Method.of(base, (String)method, Arrays.asList(params)),
() -> super.invoke(elContext, base, method, paramTypes, params));
} catch (javax.el.MethodNotFoundException e) {
throw new MethodNotFoundException(base, method, paramTypes);
Expand All @@ -83,13 +82,6 @@ public Object invoke(ELContext elContext, Object base, Object method, Class<?>[]
}
}

private static Method getMethod(Object method, Object[] params) {
return ImmutableMethod.builder()
.name((String)method)
.arguments(Arrays.asList(params))
.build();
}

private static String getName(Object task) {
Named n = ReflectionUtils.findAnnotation(task.getClass(), Named.class);
if (n != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,12 @@
import com.walmartlabs.concord.runtime.v2.model.Step;
import com.walmartlabs.concord.runtime.v2.runner.tasks.TaskCallEvent;
import com.walmartlabs.concord.runtime.v2.runner.tasks.TaskCallListener;
import com.walmartlabs.concord.runtime.v2.sdk.Context;
import com.walmartlabs.concord.runtime.v2.sdk.ProcessConfiguration;
import com.walmartlabs.concord.runtime.v2.sdk.TaskResult;
import com.walmartlabs.concord.runtime.v2.sdk.Variables;
import com.walmartlabs.concord.runtime.v2.sdk.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import java.lang.annotation.Annotation;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.*;
Expand All @@ -49,6 +47,8 @@ public class TaskCallEventRecordingListener implements TaskCallListener {

private static final Logger log = LoggerFactory.getLogger(TaskCallEventRecordingListener.class);

private static final String MASK = "***";

private final ProcessEventsApi eventsApi;
private final InstanceId processInstanceId;
private final EventConfiguration eventConfiguration;
Expand All @@ -68,7 +68,7 @@ public void onEvent(TaskCallEvent event) {

List<Object> inVars = event.input();
if (inVars != null && eventConfiguration.recordTaskInVars()) {
Map<String, Object> vars = maskVars(convertInput(inVars), eventConfiguration.inVarsBlacklist());
Map<String, Object> vars = maskVars(convertInput(hideSensitiveData(inVars, event.inputAnnotations())), eventConfiguration.inVarsBlacklist());
if (eventConfiguration.truncateInVars()) {
vars = ObjectTruncater.truncateMap(vars, eventConfiguration.truncateMaxStringLength(), eventConfiguration.truncateMaxArrayLength(), eventConfiguration.truncateMaxDepth());
}
Expand Down Expand Up @@ -154,7 +154,7 @@ static Map<String, Object> maskVars(Map<String, Object> vars, Collection<String>
String[] path = b.split("\\.");
if (ConfigurationUtils.has(result, path)) {
Map<String, Object> m = ensureModifiable(result, path.length - 1, path);
m.put(path[path.length - 1], "***");
m.put(path[path.length - 1], MASK);
}
}
return result;
Expand Down Expand Up @@ -206,4 +206,20 @@ private static Map<String, Object> convertInput(List<Object> input) {

return result;
}

private static List<Object> hideSensitiveData(List<Object> input, List<List<Annotation>> annotations) {
if (annotations.isEmpty()) {
return input;
}

List<Object> result = new ArrayList<>(input);
for (int i = 0; i < result.size(); i++) {
List<Annotation> a = annotations.get(i);
boolean hasSensitiveData = a.stream().anyMatch(v -> v.annotationType() == SensitiveData.class);
if (hasSensitiveData) {
result.set(i, MASK);
}
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import javax.annotation.Nullable;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
Expand All @@ -51,6 +52,12 @@ default List<Object> input() {
return Collections.emptyList();
}

@AllowNulls
@Value.Default
default List<List<Annotation>> inputAnnotations() {
return Collections.emptyList();
}

UUID correlationId();

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* =====
*/

import com.sun.el.util.ReflectionUtil;
import com.walmartlabs.concord.common.AllowNulls;
import com.walmartlabs.concord.runtime.v2.model.ProcessDefinition;
import com.walmartlabs.concord.runtime.v2.model.Step;
Expand All @@ -28,11 +29,10 @@

import javax.inject.Inject;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.lang.annotation.Annotation;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;

/**
* Intercepts task calls and notifies {@link TaskCallListener}s.
Expand Down Expand Up @@ -95,6 +95,7 @@ private static ImmutableTaskCallEvent.Builder eventBuilder(Phase phase, Method m
.correlationId(ctx.correlationId())
.currentStep(ctx.currentStep())
.input(method.arguments())
.inputAnnotations(method.annotations())
.methodName(method.name())
.processDefinition(ctx.processDefinition())
.taskName(ctx.taskName());
Expand All @@ -112,12 +113,27 @@ default List<Object> arguments() {
return Collections.emptyList();
}

static Method of(String name, Object... arguments) {
@AllowNulls
@Value.Default
default List<List<Annotation>> annotations() {
return Collections.emptyList();
}

static Method of(Object base, String methodName, List<Object> params) {
List<List<Annotation>> annotations = Collections.emptyList();
java.lang.reflect.Method m = ReflectionUtil.findMethod(base.getClass(), methodName, null, params.toArray());
if (m != null) {
annotations = Arrays.stream(m.getParameterAnnotations())
.map(Arrays::asList)
.collect(Collectors.toList());
}
return ImmutableMethod.builder()
.name(name)
.addArguments(arguments)
.name(methodName)
.arguments(params)
.annotations(annotations)
.build();
}

}

@Value.Immutable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.walmartlabs.concord.svm.State;
import com.walmartlabs.concord.svm.ThreadId;

import java.util.Collections;
import java.util.Objects;

import static com.walmartlabs.concord.runtime.v2.runner.tasks.TaskCallInterceptor.CallContext;
Expand Down Expand Up @@ -79,7 +80,7 @@ protected void execute(Runtime runtime, State state, ThreadId threadId) {

TaskResult result;
try {
result = interceptor.invoke(callContext, Method.of("execute", input),
result = interceptor.invoke(callContext, Method.of(t, "execute", Collections.singletonList(input)),
() -> t.execute(input));
} catch (RuntimeException e) {
throw e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.walmartlabs.concord.svm.State;
import com.walmartlabs.concord.svm.ThreadId;

import java.util.Collections;
import java.util.UUID;

public class TaskResumeCommand extends StepCommand<TaskCall> {
Expand Down Expand Up @@ -76,7 +77,7 @@ protected void execute(Runtime runtime, State state, ThreadId threadId) {

TaskResult result;
try {
result = interceptor.invoke(callContext, TaskCallInterceptor.Method.of("resume", event),
result = interceptor.invoke(callContext, TaskCallInterceptor.Method.of(rt, "resume", Collections.singletonList(event)),
() -> rt.resume(event));
} catch (RuntimeException e) {
throw e;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.walmartlabs.concord.runtime.v2.sdk;

/*-
* *****
* Concord
* -----
* Copyright (C) 2017 - 2020 Walmart Inc.
* -----
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =====
*/

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.PARAMETER;

/**
* This annotation can be used to prevent task arguments values from
* being recorded in process events.
* <p/>
* Currently, it is applicable only for task methods called directly
* via expressions. For example:
* <pre>{@code
* flows:
* default:
* - "${crypto.exportAsString('myOrg', 'mySecret', 'mySecretPassword')}"
* }</pre>
* Assuming the task method has the third argument annotated with
* {@link SensitiveData}, running this flow will result with
* the third argument's value being masked in process events.
*/
@Target({PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveData {
}

0 comments on commit 46ea7f6

Please sign in to comment.