@@ -140,11 +140,11 @@ plugins {
protobuf {
protoc {
- artifact = "com.google.protobuf:protoc:3.19.1"
+ artifact = "com.google.protobuf:protoc:3.19.2"
}
plugins {
grpc {
- artifact = 'io.grpc:protoc-gen-grpc-java:1.43.1'
+ artifact = 'io.grpc:protoc-gen-grpc-java:1.45.0'
}
}
generateProtoTasks {
@@ -173,11 +173,11 @@ plugins {
protobuf {
protoc {
- artifact = "com.google.protobuf:protoc:3.19.1"
+ artifact = "com.google.protobuf:protoc:3.19.2"
}
plugins {
grpc {
- artifact = 'io.grpc:protoc-gen-grpc-java:1.43.1'
+ artifact = 'io.grpc:protoc-gen-grpc-java:1.45.0'
}
}
generateProtoTasks {
diff --git a/RELEASING.md b/RELEASING.md
index f2e37f312b4..b8682961234 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -85,7 +85,7 @@ would be used to create all `v1.7` tags (e.g. `v1.7.0`, `v1.7.1`).
$ echo "## gRPC Java $MAJOR.$MINOR.0 Release Notes" && echo && \
git shortlog "$(git merge-base upstream/v$MAJOR.$((MINOR-1)).x upstream/v$MAJOR.$MINOR.x)"..upstream/v$MAJOR.$MINOR.x | cat && \
echo && echo && echo "Backported commits in previous release:" && \
- git cherry -v v$MAJOR.$((MINOR-1)).0 upstream/v$MAJOR.$MINOR.x | grep ^-
+ git log --oneline "$(git merge-base v$MAJOR.$((MINOR-1)).0 upstream/v$MAJOR.$MINOR.x)"..v$MAJOR.$((MINOR-1)).0^
```
Tagging the Release
@@ -133,7 +133,7 @@ Tagging the Release
$ git commit -a -m "Bump version to $MAJOR.$MINOR.$((PATCH+1))-SNAPSHOT"
```
6. Go through PR review and push the release tag and updated release branch to
- GitHub:
+ GitHub (DO NOT click the merge button on the GitHub page):
```bash
$ git checkout v$MAJOR.$MINOR.x
diff --git a/alts/build.gradle b/alts/build.gradle
index 8c467f51c12..a056799d4f0 100644
--- a/alts/build.gradle
+++ b/alts/build.gradle
@@ -9,9 +9,6 @@ plugins {
description = "gRPC: ALTS"
-sourceCompatibility = 1.7
-targetCompatibility = 1.7
-
evaluationDependsOn(project(':grpc-core').path)
dependencies {
@@ -65,14 +62,14 @@ javadoc {
}
jar {
- // Must use a different classifier to avoid conflicting with shadowJar
- classifier = 'original'
+ // Must use a different archiveClassifier to avoid conflicting with shadowJar
+ archiveClassifier = 'original'
}
// We want to use grpc-netty-shaded instead of grpc-netty. But we also want our
// source to work with Bazel, so we rewrite the code as part of the build.
shadowJar {
- classifier = null
+ archiveClassifier = null
dependencies {
exclude(dependency {true})
}
diff --git a/alts/src/main/java/io/grpc/alts/internal/ChannelCrypterNetty.java b/alts/src/main/java/io/grpc/alts/internal/ChannelCrypterNetty.java
index 4164560e7a0..e2e7d4046fb 100644
--- a/alts/src/main/java/io/grpc/alts/internal/ChannelCrypterNetty.java
+++ b/alts/src/main/java/io/grpc/alts/internal/ChannelCrypterNetty.java
@@ -21,8 +21,8 @@
import java.util.List;
/**
- * A @{code ChannelCrypterNetty} performs stateful encryption and decryption of independent input
- * and output streams. Both decrypt and encrypt gather their input from a list of Netty @{link
+ * A {@code ChannelCrypterNetty} performs stateful encryption and decryption of independent input
+ * and output streams. Both decrypt and encrypt gather their input from a list of Netty {@link
* ByteBuf} instances.
*
* Note that we provide implementations of this interface that provide integrity only and
diff --git a/alts/src/test/java/io/grpc/alts/internal/TsiTest.java b/alts/src/test/java/io/grpc/alts/internal/TsiTest.java
index f677a44a754..f75fb7fcee0 100644
--- a/alts/src/test/java/io/grpc/alts/internal/TsiTest.java
+++ b/alts/src/test/java/io/grpc/alts/internal/TsiTest.java
@@ -34,13 +34,13 @@
import java.util.List;
import javax.crypto.AEADBadTagException;
-/** Utility class that provides tests for implementations of @{link TsiHandshaker}. */
+/** Utility class that provides tests for implementations of {@link TsiHandshaker}. */
public final class TsiTest {
private static final String DECRYPTION_FAILURE_RE = "Tag mismatch!|BAD_DECRYPT";
private TsiTest() {}
- /** A @{code TsiHandshaker} pair for running tests. */
+ /** A {@code TsiHandshaker} pair for running tests. */
public static class Handshakers {
private final TsiHandshaker client;
private final TsiHandshaker server;
diff --git a/android-interop-testing/build.gradle b/android-interop-testing/build.gradle
index b18d84e2625..e40507e6a3b 100644
--- a/android-interop-testing/build.gradle
+++ b/android-interop-testing/build.gradle
@@ -76,8 +76,8 @@ dependencies {
compileOnly libraries.javax_annotation
- androidTestImplementation 'androidx.test:rules:1.1.0-alpha1'
- androidTestImplementation 'androidx.test:runner:1.1.0-alpha1'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3',
+ 'androidx.test:runner:1.4.0'
}
// Checkstyle doesn't run automatically with android
@@ -102,6 +102,10 @@ tasks.withType(JavaCompile) {
"-Xlint:-cast"
]
appendToProperty(it.options.errorprone.excludedPaths, ".*/R.java", "|")
+ appendToProperty(
+ it.options.errorprone.excludedPaths,
+ ".*/src/generated/.*",
+ "|")
// Reuses source code from grpc-interop-testing, which targets Java 7 (no method references)
options.errorprone.check("UnnecessaryAnonymousClass", CheckSeverity.OFF)
}
diff --git a/android-interop-testing/src/androidTest/AndroidManifest.xml b/android-interop-testing/src/androidTest/AndroidManifest.xml
index 916a1c04332..9c59d201eff 100644
--- a/android-interop-testing/src/androidTest/AndroidManifest.xml
+++ b/android-interop-testing/src/androidTest/AndroidManifest.xml
@@ -6,8 +6,8 @@
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="io.grpc.android.integrationtest" />
-
-
+
diff --git a/android-interop-testing/src/androidTest/java/io/grpc/android/integrationtest/InteropInstrumentationTest.java b/android-interop-testing/src/androidTest/java/io/grpc/android/integrationtest/InteropInstrumentationTest.java
index abcf9e08593..5d76f1c0a6e 100644
--- a/android-interop-testing/src/androidTest/java/io/grpc/android/integrationtest/InteropInstrumentationTest.java
+++ b/android-interop-testing/src/androidTest/java/io/grpc/android/integrationtest/InteropInstrumentationTest.java
@@ -16,11 +16,12 @@
package io.grpc.android.integrationtest;
-import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertEquals;
import android.util.Log;
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import com.google.android.gms.security.ProviderInstaller;
@@ -59,7 +60,7 @@ public void setUp() throws Exception {
if (useTls) {
try {
- ProviderInstaller.installIfNeeded(InstrumentationRegistry.getTargetContext());
+ ProviderInstaller.installIfNeeded(ApplicationProvider.getApplicationContext());
} catch (GooglePlayServicesRepairableException e) {
// The provider is helpful, but it is possible to succeed without it.
// Hope that the system-provided libraries are new enough.
@@ -110,7 +111,7 @@ public void onComplete(String result) {
};
InputStream testCa;
if (useTestCa) {
- testCa = InstrumentationRegistry.getTargetContext().getResources().openRawResource(R.raw.ca);
+ testCa = ApplicationProvider.getApplicationContext().getResources().openRawResource(R.raw.ca);
} else {
testCa = null;
}
diff --git a/android/build.gradle b/android/build.gradle
index b0916f9e04c..7e32ac5ca2f 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -59,12 +59,12 @@ task javadocs(type: Javadoc) {
}
task javadocJar(type: Jar, dependsOn: javadocs) {
- classifier = 'javadoc'
+ archiveClassifier = 'javadoc'
from javadocs.destinationDir
}
task sourcesJar(type: Jar) {
- classifier = 'sources'
+ archiveClassifier = 'sources'
from android.sourceSets.main.java.srcDirs
}
diff --git a/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java b/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java
index 8c69ca68b5f..dadab1c830c 100644
--- a/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java
+++ b/android/src/main/java/io/grpc/android/AndroidChannelBuilder.java
@@ -27,6 +27,7 @@
import android.util.Log;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
+import com.google.errorprone.annotations.InlineMe;
import io.grpc.CallOptions;
import io.grpc.ClientCall;
import io.grpc.ConnectivityState;
@@ -90,6 +91,9 @@ public static AndroidChannelBuilder forAddress(String name, int port) {
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/6043")
@Deprecated
+ @InlineMe(
+ replacement = "AndroidChannelBuilder.usingBuilder(builder)",
+ imports = "io.grpc.android.AndroidChannelBuilder")
public static AndroidChannelBuilder fromBuilder(ManagedChannelBuilder> builder) {
return usingBuilder(builder);
}
@@ -293,6 +297,13 @@ private class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback
public void onAvailable(Network network) {
delegate.enterIdle();
}
+
+ @Override
+ public void onBlockedStatusChanged(Network network, boolean blocked) {
+ if (!blocked) {
+ delegate.enterIdle();
+ }
+ }
}
/** Respond to network changes. Only used on API levels < 24. */
diff --git a/api/build.gradle b/api/build.gradle
index 1348e49ad60..9f5e6163153 100644
--- a/api/build.gradle
+++ b/api/build.gradle
@@ -12,9 +12,9 @@ evaluationDependsOn(project(':grpc-context').path)
dependencies {
api project(':grpc-context'),
- libraries.jsr305
- implementation libraries.guava,
+ libraries.jsr305,
libraries.errorprone
+ implementation libraries.guava
testImplementation project(':grpc-context').sourceSets.test.output,
project(':grpc-testing'),
@@ -25,7 +25,7 @@ dependencies {
jmh project(':grpc-core')
signature "org.codehaus.mojo.signature:java17:1.0@signature"
- signature "net.sf.androidscents.signature:android-api-level-19:4.4.2_r4@signature"
+ signature "net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature"
}
javadoc {
diff --git a/api/src/jmh/java/io/grpc/StatusBenchmark.java b/api/src/jmh/java/io/grpc/StatusBenchmark.java
index 846682c3298..e3f087c6204 100644
--- a/api/src/jmh/java/io/grpc/StatusBenchmark.java
+++ b/api/src/jmh/java/io/grpc/StatusBenchmark.java
@@ -16,7 +16,7 @@
package io.grpc;
-import java.nio.charset.StandardCharsets;
+import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
@@ -57,7 +57,7 @@ public byte[] messageEncodeEscape() {
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public String messageDecodePlain() {
return Status.MESSAGE_KEY.parseBytes(
- "Unexpected RST in stream".getBytes(StandardCharsets.US_ASCII));
+ "Unexpected RST in stream".getBytes(Charset.forName("US-ASCII")));
}
/**
@@ -68,7 +68,7 @@ public String messageDecodePlain() {
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public String messageDecodeEscape() {
return Status.MESSAGE_KEY.parseBytes(
- "Some Error%10Wasabi and Horseradish are the same".getBytes(StandardCharsets.US_ASCII));
+ "Some Error%10Wasabi and Horseradish are the same".getBytes(Charset.forName("US-ASCII")));
}
/**
@@ -88,7 +88,7 @@ public byte[] codeEncode() {
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public Status codeDecode() {
- return Status.CODE_KEY.parseBytes("15".getBytes(StandardCharsets.US_ASCII));
+ return Status.CODE_KEY.parseBytes("15".getBytes(Charset.forName("US-ASCII")));
}
}
diff --git a/api/src/main/java/io/grpc/Attributes.java b/api/src/main/java/io/grpc/Attributes.java
index b70cc2bc8c3..26c2a72f909 100644
--- a/api/src/main/java/io/grpc/Attributes.java
+++ b/api/src/main/java/io/grpc/Attributes.java
@@ -46,11 +46,13 @@
@Immutable
public final class Attributes {
- private final Map, Object> data;
+ private final IdentityHashMap, Object> data;
- public static final Attributes EMPTY = new Attributes(Collections., Object>emptyMap());
+ private static final IdentityHashMap, Object> EMPTY_MAP =
+ new IdentityHashMap, Object>();
+ public static final Attributes EMPTY = new Attributes(EMPTY_MAP);
- private Attributes(Map, Object> data) {
+ private Attributes(IdentityHashMap, Object> data) {
assert data != null;
this.data = data;
}
@@ -212,14 +214,14 @@ public int hashCode() {
*/
public static final class Builder {
private Attributes base;
- private Map, Object> newdata;
+ private IdentityHashMap, Object> newdata;
private Builder(Attributes base) {
assert base != null;
this.base = base;
}
- private Map, Object> data(int size) {
+ private IdentityHashMap, Object> data(int size) {
if (newdata == null) {
newdata = new IdentityHashMap<>(size);
}
@@ -241,7 +243,7 @@ public Builder set(Key key, T value) {
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/5777")
public Builder discard(Key key) {
if (base.data.containsKey(key)) {
- Map, Object> newBaseData = new IdentityHashMap<>(base.data);
+ IdentityHashMap, Object> newBaseData = new IdentityHashMap<>(base.data);
newBaseData.remove(key);
base = new Attributes(newBaseData);
}
diff --git a/api/src/main/java/io/grpc/CallOptions.java b/api/src/main/java/io/grpc/CallOptions.java
index c7504a6506a..5c05d5b7bd7 100644
--- a/api/src/main/java/io/grpc/CallOptions.java
+++ b/api/src/main/java/io/grpc/CallOptions.java
@@ -358,6 +358,11 @@ public T getOption(Key key) {
return key.defaultValue;
}
+ /**
+ * Returns the executor override to use for this specific call, or {@code null} if there is no
+ * override. The executor is only for servicing this one call, so is not safe to use after
+ * {@link ClientCall.Listener#onClose}.
+ */
@Nullable
public Executor getExecutor() {
return executor;
diff --git a/api/src/main/java/io/grpc/DecompressorRegistry.java b/api/src/main/java/io/grpc/DecompressorRegistry.java
index b2669d3c0fc..ea0433d8d0a 100644
--- a/api/src/main/java/io/grpc/DecompressorRegistry.java
+++ b/api/src/main/java/io/grpc/DecompressorRegistry.java
@@ -20,7 +20,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Joiner;
-import java.nio.charset.StandardCharsets;
+import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -85,7 +85,7 @@ private DecompressorRegistry(Decompressor d, boolean advertised, DecompressorReg
decompressors = Collections.unmodifiableMap(newDecompressors);
advertisedDecompressors = ACCEPT_ENCODING_JOINER.join(getAdvertisedMessageEncodings())
- .getBytes(StandardCharsets.US_ASCII);
+ .getBytes(Charset.forName("US-ASCII"));
}
private DecompressorRegistry() {
diff --git a/api/src/main/java/io/grpc/InternalManagedChannelProvider.java b/api/src/main/java/io/grpc/InternalManagedChannelProvider.java
new file mode 100644
index 00000000000..076b5464b7e
--- /dev/null
+++ b/api/src/main/java/io/grpc/InternalManagedChannelProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 The gRPC Authors
+ *
+ * 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.
+ */
+
+package io.grpc;
+
+import io.grpc.ManagedChannelProvider.NewChannelBuilderResult;
+
+/** Internal accessor for {@link ManagedChannelProvider}. */
+@Internal
+public final class InternalManagedChannelProvider {
+
+ private InternalManagedChannelProvider() {
+ }
+
+ public static ManagedChannelBuilder> builderForAddress(ManagedChannelProvider provider,
+ String name, int port) {
+ return provider.builderForAddress(name, port);
+ }
+
+ public static ManagedChannelBuilder> builderForTarget(ManagedChannelProvider provider,
+ String target) {
+ return provider.builderForTarget(target);
+ }
+
+ public static NewChannelBuilderResult newChannelBuilder(ManagedChannelProvider provider,
+ String target, ChannelCredentials creds) {
+ return provider.newChannelBuilder(target, creds);
+ }
+}
diff --git a/api/src/main/java/io/grpc/InternalMetadata.java b/api/src/main/java/io/grpc/InternalMetadata.java
index cb98ad752b2..2823882952f 100644
--- a/api/src/main/java/io/grpc/InternalMetadata.java
+++ b/api/src/main/java/io/grpc/InternalMetadata.java
@@ -20,7 +20,6 @@
import io.grpc.Metadata.AsciiMarshaller;
import io.grpc.Metadata.BinaryStreamMarshaller;
import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
/**
* Internal {@link Metadata} accessor. This is intended for use by io.grpc.internal, and the
@@ -43,7 +42,7 @@ public interface TrustedAsciiMarshaller extends Metadata.TrustedAsciiMarshall
* Copy of StandardCharsets, which is only available on Java 1.7 and above.
*/
@Internal
- public static final Charset US_ASCII = StandardCharsets.US_ASCII;
+ public static final Charset US_ASCII = Charset.forName("US-ASCII");
/**
* An instance of base64 encoder that omits padding.
diff --git a/api/src/main/java/io/grpc/InternalServerProvider.java b/api/src/main/java/io/grpc/InternalServerProvider.java
new file mode 100644
index 00000000000..d8c1d77fe76
--- /dev/null
+++ b/api/src/main/java/io/grpc/InternalServerProvider.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 The gRPC Authors
+ *
+ * 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.
+ */
+
+package io.grpc;
+
+import io.grpc.ServerProvider.NewServerBuilderResult;
+
+/** Internal accessor for {@link ServerProvider}. */
+@Internal
+public final class InternalServerProvider {
+
+ private InternalServerProvider() {
+ }
+
+ public static ServerBuilder> builderForPort(ServerProvider provider, int port) {
+ return provider.builderForPort(port);
+ }
+
+ public static NewServerBuilderResult newServerBuilderForPort(ServerProvider provider, int port,
+ ServerCredentials creds) {
+ return provider.newServerBuilderForPort(port, creds);
+ }
+}
diff --git a/api/src/main/java/io/grpc/NameResolver.java b/api/src/main/java/io/grpc/NameResolver.java
index f4c05aa6a64..78b35a14e38 100644
--- a/api/src/main/java/io/grpc/NameResolver.java
+++ b/api/src/main/java/io/grpc/NameResolver.java
@@ -21,6 +21,7 @@
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
+import com.google.errorprone.annotations.InlineMe;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -204,6 +205,10 @@ public abstract static class Listener2 implements Listener {
*/
@Override
@Deprecated
+ @InlineMe(
+ replacement = "this.onResult(ResolutionResult.newBuilder().setAddresses(servers)"
+ + ".setAttributes(attributes).build())",
+ imports = "io.grpc.NameResolver.ResolutionResult")
public final void onAddresses(
List servers, @ResolutionResultAttr Attributes attributes) {
// TODO(jihuncho) need to promote Listener2 if we want to use ConfigOrError
diff --git a/api/src/test/java/io/grpc/StatusTest.java b/api/src/test/java/io/grpc/StatusTest.java
index aca5dc8ee66..9abeba436f7 100644
--- a/api/src/test/java/io/grpc/StatusTest.java
+++ b/api/src/test/java/io/grpc/StatusTest.java
@@ -21,8 +21,6 @@
import io.grpc.Status.Code;
import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -30,7 +28,7 @@
/** Unit tests for {@link Status}. */
@RunWith(JUnit4.class)
public class StatusTest {
- private final Charset ascii = StandardCharsets.US_ASCII;
+ private final Charset ascii = Charset.forName("US-ASCII");
@Test
public void verifyExceptionMessage() {
diff --git a/auth/build.gradle b/auth/build.gradle
index 791402fce59..233de359b49 100644
--- a/auth/build.gradle
+++ b/auth/build.gradle
@@ -14,5 +14,5 @@ dependencies {
testImplementation project(':grpc-testing'),
libraries.google_auth_oauth2_http
signature "org.codehaus.mojo.signature:java17:1.0@signature"
- signature "net.sf.androidscents.signature:android-api-level-19:4.4.2_r4@signature"
+ signature "net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature"
}
diff --git a/authz/build.gradle b/authz/build.gradle
new file mode 100644
index 00000000000..f6110a5850c
--- /dev/null
+++ b/authz/build.gradle
@@ -0,0 +1,77 @@
+plugins {
+ id "java-library"
+ id "maven-publish"
+
+ id "com.github.johnrengelman.shadow"
+ id "com.google.protobuf"
+ id "ru.vyarus.animalsniffer"
+}
+
+description = "gRPC: Authorization"
+
+dependencies {
+ implementation project(':grpc-protobuf'),
+ project(':grpc-core')
+
+ annotationProcessor libraries.autovalue
+ compileOnly libraries.javax_annotation
+
+ testImplementation project(':grpc-testing'),
+ project(':grpc-testing-proto')
+ testImplementation (libraries.guava_testlib) {
+ exclude group: 'junit', module: 'junit'
+ }
+
+ def xdsDependency = implementation project(':grpc-xds')
+ shadow configurations.implementation.getDependencies().minus([xdsDependency])
+ shadow project(path: ':grpc-xds', configuration: 'shadow')
+
+ signature "org.codehaus.mojo.signature:java17:1.0@signature"
+}
+
+jar {
+ classifier = 'original'
+}
+
+// TODO(ashithasantosh): Remove javadoc exclusion on adding authorization
+// interceptor implementations.
+javadoc {
+ exclude "io/grpc/authz/*"
+}
+
+shadowJar {
+ classifier = null
+ dependencies {
+ exclude(dependency {true})
+ }
+ relocate 'io.grpc.xds', 'io.grpc.xds.shaded.io.grpc.xds'
+ relocate 'udpa.annotations', 'io.grpc.xds.shaded.udpa.annotations'
+ relocate 'com.github.udpa', 'io.grpc.xds.shaded.com.github.udpa'
+ relocate 'envoy.annotations', 'io.grpc.xds.shaded.envoy.annotations'
+ relocate 'io.envoyproxy', 'io.grpc.xds.shaded.io.envoyproxy'
+ relocate 'com.google.api.expr', 'io.grpc.xds.shaded.com.google.api.expr'
+}
+
+publishing {
+ publications {
+ maven(MavenPublication) {
+ // We want this to throw an exception if it isn't working
+ def originalJar = artifacts.find { dep -> dep.classifier == 'original'}
+ artifacts.remove(originalJar)
+
+ pom.withXml {
+ def dependenciesNode = new Node(null, 'dependencies')
+ project.configurations.shadow.allDependencies.each { dep ->
+ def dependencyNode = dependenciesNode.appendNode('dependency')
+ dependencyNode.appendNode('groupId', dep.group)
+ dependencyNode.appendNode('artifactId', dep.name)
+ dependencyNode.appendNode('version', dep.version)
+ dependencyNode.appendNode('scope', 'compile')
+ }
+ asNode().dependencies[0].replaceNode(dependenciesNode)
+ }
+ }
+ }
+}
+
+[publishMavenPublicationToMavenRepository]*.onlyIf {false}
diff --git a/authz/src/main/java/io/grpc/authz/AuthorizationPolicyTranslator.java b/authz/src/main/java/io/grpc/authz/AuthorizationPolicyTranslator.java
new file mode 100644
index 00000000000..1637af737ad
--- /dev/null
+++ b/authz/src/main/java/io/grpc/authz/AuthorizationPolicyTranslator.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2021 The gRPC Authors
+ *
+ * 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.
+ */
+
+package io.grpc.authz;
+
+import com.google.common.collect.ImmutableList;
+import io.envoyproxy.envoy.config.rbac.v3.Permission;
+import io.envoyproxy.envoy.config.rbac.v3.Policy;
+import io.envoyproxy.envoy.config.rbac.v3.Principal;
+import io.envoyproxy.envoy.config.rbac.v3.Principal.Authenticated;
+import io.envoyproxy.envoy.config.rbac.v3.RBAC;
+import io.envoyproxy.envoy.config.rbac.v3.RBAC.Action;
+import io.envoyproxy.envoy.config.route.v3.HeaderMatcher;
+import io.envoyproxy.envoy.type.matcher.v3.PathMatcher;
+import io.envoyproxy.envoy.type.matcher.v3.RegexMatcher;
+import io.envoyproxy.envoy.type.matcher.v3.StringMatcher;
+import io.grpc.internal.JsonParser;
+import io.grpc.internal.JsonUtil;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Translates a gRPC authorization policy in JSON string to Envoy RBAC policies.
+ */
+class AuthorizationPolicyTranslator {
+ private static final ImmutableList UNSUPPORTED_HEADERS = ImmutableList.of(
+ "host", "connection", "keep-alive", "proxy-authenticate", "proxy-authorization",
+ "te", "trailer", "transfer-encoding", "upgrade");
+
+ private static StringMatcher getStringMatcher(String value) {
+ if (value.equals("*")) {
+ return StringMatcher.newBuilder().setSafeRegex(
+ RegexMatcher.newBuilder().setRegex(".+").build()).build();
+ } else if (value.startsWith("*")) {
+ return StringMatcher.newBuilder().setSuffix(value.substring(1)).build();
+ } else if (value.endsWith("*")) {
+ return StringMatcher.newBuilder().setPrefix(value.substring(0, value.length() - 1)).build();
+ }
+ return StringMatcher.newBuilder().setExact(value).build();
+ }
+
+ private static Principal parseSource(Map source) {
+ List principalsList = JsonUtil.getListOfStrings(source, "principals");
+ if (principalsList == null || principalsList.isEmpty()) {
+ return Principal.newBuilder().setAny(true).build();
+ }
+ Principal.Set.Builder principalsSet = Principal.Set.newBuilder();
+ for (String principal: principalsList) {
+ principalsSet.addIds(
+ Principal.newBuilder().setAuthenticated(
+ Authenticated.newBuilder().setPrincipalName(
+ getStringMatcher(principal)).build()).build());
+ }
+ return Principal.newBuilder().setOrIds(principalsSet.build()).build();
+ }
+
+ private static Permission parseHeader(Map header) throws IllegalArgumentException {
+ String key = JsonUtil.getString(header, "key");
+ if (key == null || key.isEmpty()) {
+ throw new IllegalArgumentException("\"key\" is absent or empty");
+ }
+ if (key.charAt(0) == ':'
+ || key.startsWith("grpc-")
+ || UNSUPPORTED_HEADERS.contains(key.toLowerCase())) {
+ throw new IllegalArgumentException(String.format("Unsupported \"key\" %s", key));
+ }
+ List valuesList = JsonUtil.getListOfStrings(header, "values");
+ if (valuesList == null || valuesList.isEmpty()) {
+ throw new IllegalArgumentException("\"values\" is absent or empty");
+ }
+ Permission.Set.Builder orSet = Permission.Set.newBuilder();
+ for (String value: valuesList) {
+ orSet.addRules(
+ Permission.newBuilder().setHeader(
+ HeaderMatcher.newBuilder()
+ .setName(key)
+ .setStringMatch(getStringMatcher(value)).build()).build());
+ }
+ return Permission.newBuilder().setOrRules(orSet.build()).build();
+ }
+
+ private static Permission parseRequest(Map request) throws IllegalArgumentException {
+ Permission.Set.Builder andSet = Permission.Set.newBuilder();
+ List pathsList = JsonUtil.getListOfStrings(request, "paths");
+ if (pathsList != null && !pathsList.isEmpty()) {
+ Permission.Set.Builder pathsSet = Permission.Set.newBuilder();
+ for (String path: pathsList) {
+ pathsSet.addRules(
+ Permission.newBuilder().setUrlPath(
+ PathMatcher.newBuilder().setPath(
+ getStringMatcher(path)).build()).build());
+ }
+ andSet.addRules(Permission.newBuilder().setOrRules(pathsSet.build()).build());
+ }
+ List