diff --git a/sdk/pom.xml b/sdk/pom.xml index ebc02e516..efbc58811 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -84,6 +84,12 @@ 1.3.2 test + + com.github.stefanbirkner + system-rules + 1.19.0 + test + org.junit.jupiter junit-jupiter-engine diff --git a/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java b/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java index 527117708..79581a7c4 100644 --- a/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java +++ b/sdk/src/main/java/io/dapr/client/DaprClientGrpc.java @@ -21,6 +21,8 @@ import io.dapr.client.domain.SaveStateRequest; import io.dapr.client.domain.State; import io.dapr.client.domain.StateOptions; import io.dapr.serializer.DaprObjectSerializer; +import io.dapr.utils.Constants; +import io.dapr.utils.Properties; import io.dapr.utils.TypeRef; import io.dapr.v1.CommonProtos; import io.dapr.v1.DaprGrpc; @@ -32,6 +34,7 @@ import io.grpc.ClientInterceptor; import io.grpc.Context; import io.grpc.ForwardingClientCall; import io.grpc.Metadata; +import io.grpc.Metadata.Key; import io.grpc.MethodDescriptor; import io.opencensus.implcore.trace.propagation.PropagationComponentImpl; import io.opencensus.implcore.trace.propagation.TraceContextFormat; @@ -483,8 +486,14 @@ public class DaprClientGrpc extends AbstractDaprClient { SpanContext opencensusSpanContext = extractOpenCensusSpanContext(context); if (opencensusSpanContext != null) { byte[] grpcTraceBin = OPENCENSUS_BINARY_FORMAT.toByteArray(opencensusSpanContext); - headers.put(Metadata.Key.of("grpc-trace-bin", Metadata.BINARY_BYTE_MARSHALLER), grpcTraceBin); + headers.put(Key.of("grpc-trace-bin", Metadata.BINARY_BYTE_MARSHALLER), grpcTraceBin); } + + String daprApiToken = Properties.DAPR_API_TOKEN.get(); + if (daprApiToken != null) { + headers.put(Key.of(Constants.DAPR_API_TOKEN_HEADER, Metadata.ASCII_STRING_MARSHALLER), daprApiToken); + } + super.start(responseListener, headers); } }; diff --git a/sdk/src/main/java/io/dapr/client/DaprHttp.java b/sdk/src/main/java/io/dapr/client/DaprHttp.java index 73e33946c..7962c0be2 100644 --- a/sdk/src/main/java/io/dapr/client/DaprHttp.java +++ b/sdk/src/main/java/io/dapr/client/DaprHttp.java @@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.dapr.exceptions.DaprError; import io.dapr.exceptions.DaprException; import io.dapr.utils.Constants; +import io.dapr.utils.Properties; import io.grpc.Context; import io.opentelemetry.OpenTelemetry; import io.opentelemetry.context.propagation.HttpTextFormat; @@ -258,6 +259,12 @@ public class DaprHttp implements Closeable { } else { requestBuilder.method(method, body); } + + String daprApiToken = Properties.DAPR_API_TOKEN.get(); + if (daprApiToken != null) { + requestBuilder.addHeader(Constants.DAPR_API_TOKEN_HEADER, daprApiToken); + } + if (headers != null) { Optional.ofNullable(headers.entrySet()).orElse(Collections.emptySet()).stream() .forEach(header -> { @@ -308,4 +315,4 @@ public class DaprHttp implements Closeable { return EMPTY_BYTES; } -} +} \ No newline at end of file diff --git a/sdk/src/main/java/io/dapr/utils/Constants.java b/sdk/src/main/java/io/dapr/utils/Constants.java index 481463052..218fa9259 100644 --- a/sdk/src/main/java/io/dapr/utils/Constants.java +++ b/sdk/src/main/java/io/dapr/utils/Constants.java @@ -60,6 +60,16 @@ public final class Constants { */ public static final String ACTOR_TIMER_RELATIVE_URL_FORMAT = ACTORS_BASE_URL + "/%s/%s/timers/%s"; + /** + * Environment variable name for dapr api token. + */ + public static final String DAPR_API_TOKEN = "DAPR_API_TOKEN"; + + /** + * Header name for the dapr api token environment variable name. + */ + public static final String DAPR_API_TOKEN_HEADER = "dapr-api-token"; + /** * Base path to invoke methods. */ diff --git a/sdk/src/main/java/io/dapr/utils/Properties.java b/sdk/src/main/java/io/dapr/utils/Properties.java index 2f0ce7774..6009c3005 100644 --- a/sdk/src/main/java/io/dapr/utils/Properties.java +++ b/sdk/src/main/java/io/dapr/utils/Properties.java @@ -35,6 +35,13 @@ public class Properties { */ private static final String DEFAULT_STRING_CHARSET = StandardCharsets.UTF_8.name(); + /** + * API token for Dapr after checking system property and environment variable. + */ + public static final Supplier DAPR_API_TOKEN = () -> getStringOrDefault( + "dapr.api.token", + Constants.DAPR_API_TOKEN, null); + /** * HTTP port for Dapr after checking system property and environment variable. */ @@ -70,7 +77,7 @@ public class Properties { * * @return Integer from system property (1st) or env variable (2nd) or default (last). */ - public static Integer getIntOrDefault(String propName, String envName, Integer defaultValue) { + private static Integer getIntOrDefault(String propName, String envName, Integer defaultValue) { return getValueOrDefault(propName, envName, defaultValue, s -> Integer.valueOf(s)); } @@ -82,7 +89,7 @@ public class Properties { * * @return Boolean from system property (1st) or env variable (2nd) or default (last). */ - public static Boolean getBooleanOrDefault(String propName, String envName, Boolean defaultValue) { + private static Boolean getBooleanOrDefault(String propName, String envName, Boolean defaultValue) { return getValueOrDefault(propName, envName, defaultValue, s -> Boolean.valueOf(s)); } @@ -94,7 +101,7 @@ public class Properties { * * @return String from system property (1st) or env variable (2nd) or default (last). */ - public static String getStringOrDefault(String propName, String envName, String defaultValue) { + private static String getStringOrDefault(String propName, String envName, String defaultValue) { return getValueOrDefault(propName, envName, defaultValue, s -> s); } diff --git a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java index 57726827f..ba2415935 100644 --- a/sdk/src/test/java/io/dapr/client/DaprHttpTest.java +++ b/sdk/src/test/java/io/dapr/client/DaprHttpTest.java @@ -6,6 +6,7 @@ package io.dapr.client; import io.dapr.exceptions.DaprException; import io.dapr.utils.Constants; +import io.dapr.utils.Properties; import io.grpc.Context; import okhttp3.MediaType; import okhttp3.OkHttpClient; @@ -13,6 +14,8 @@ import okhttp3.ResponseBody; import okhttp3.mock.Behavior; import okhttp3.mock.MockInterceptor; import org.junit.Before; +import org.junit.contrib.java.lang.system.EnvironmentVariables; +import org.junit.Rule; import org.junit.Test; import reactor.core.publisher.Mono; @@ -27,6 +30,9 @@ import static org.junit.Assert.fail; public class DaprHttpTest { + @Rule + public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + private static final String EXPECTED_RESULT = "{\"data\":\"ewoJCSJwcm9wZXJ0eUEiOiAidmFsdWVBIiwKCQkicHJvcGVydHlCIjogInZhbHVlQiIKCX0=\"}"; @@ -42,6 +48,38 @@ public class DaprHttpTest { okHttpClient = new OkHttpClient.Builder().addInterceptor(mockInterceptor).build(); } + @Test + public void invokeApi_daprApiToken_present() throws IOException { + mockInterceptor.addRule() + .post("http://127.0.0.1:3500/v1.0/state") + .hasHeader(Constants.DAPR_API_TOKEN_HEADER) + .respond(serializer.serialize(EXPECTED_RESULT)); + environmentVariables.set(Constants.DAPR_API_TOKEN, "xyz"); + assertEquals("xyz", Properties.DAPR_API_TOKEN.get()); + DaprHttp daprHttp = new DaprHttp(3500, okHttpClient); + Mono mono = + daprHttp.invokeApi("POST", "v1.0/state", null, (byte[]) null, null, Context.current()); + DaprHttp.Response response = mono.block(); + String body = serializer.deserialize(response.getBody(), String.class); + assertEquals(EXPECTED_RESULT, body); + } + + @Test + public void invokeApi_daprApiToken_absent() throws IOException { + mockInterceptor.addRule() + .post("http://127.0.0.1:3500/v1.0/state") + .not() + .hasHeader(Constants.DAPR_API_TOKEN_HEADER) + .respond(serializer.serialize(EXPECTED_RESULT)); + assertNull(Properties.DAPR_API_TOKEN.get()); + DaprHttp daprHttp = new DaprHttp(3500, okHttpClient); + Mono mono = + daprHttp.invokeApi("POST", "v1.0/state", null, (byte[]) null, null, Context.current()); + DaprHttp.Response response = mono.block(); + String body = serializer.deserialize(response.getBody(), String.class); + assertEquals(EXPECTED_RESULT, body); + } + @Test public void invokeMethod() throws IOException { Map headers = new HashMap<>();