diff --git a/api/src/main/java/io/grpc/ServerCall.java b/api/src/main/java/io/grpc/ServerCall.java
index d391cb5c79a..40bcd2f3718 100644
--- a/api/src/main/java/io/grpc/ServerCall.java
+++ b/api/src/main/java/io/grpc/ServerCall.java
@@ -211,6 +211,21 @@ public void setCompression(String compressor) {
// noop
}
+ /**
+ * Returns the level of security guarantee in communications
+ *
+ *
Determining the level of security offered by the transport for RPCs on server-side.
+ * This can be approximated by looking for the SSLSession, but that doesn't work for ALTS and
+ * maybe some future TLS approaches. May return a lower security level when it cannot be
+ * determined precisely.
+ *
+ * @return non-{@code null} SecurityLevel enum
+ */
+ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4692")
+ public SecurityLevel getSecurityLevel() {
+ return SecurityLevel.NONE;
+ }
+
/**
* Returns properties of a single call.
*
diff --git a/core/src/main/java/io/grpc/internal/ServerCallImpl.java b/core/src/main/java/io/grpc/internal/ServerCallImpl.java
index b31aadd08a9..fc218bcb37b 100644
--- a/core/src/main/java/io/grpc/internal/ServerCallImpl.java
+++ b/core/src/main/java/io/grpc/internal/ServerCallImpl.java
@@ -19,6 +19,7 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import static io.grpc.internal.GrpcAttributes.ATTR_SECURITY_LEVEL;
import static io.grpc.internal.GrpcUtil.ACCEPT_ENCODING_SPLITTER;
import static io.grpc.internal.GrpcUtil.CONTENT_LENGTH_KEY;
import static io.grpc.internal.GrpcUtil.MESSAGE_ACCEPT_ENCODING_KEY;
@@ -36,6 +37,7 @@
import io.grpc.InternalDecompressorRegistry;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
+import io.grpc.SecurityLevel;
import io.grpc.ServerCall;
import io.grpc.Status;
import io.perfmark.PerfMark;
@@ -250,6 +252,16 @@ public MethodDescriptor getMethodDescriptor() {
return method;
}
+ @Override
+ public SecurityLevel getSecurityLevel() {
+ final Attributes attributes = getAttributes();
+ if (attributes == null) {
+ return super.getSecurityLevel();
+ }
+ final SecurityLevel securityLevel = attributes.get(ATTR_SECURITY_LEVEL);
+ return securityLevel == null ? super.getSecurityLevel() : securityLevel;
+ }
+
/**
* Close the {@link ServerStream} because an internal error occurred. Allow the application to
* run until completion, but silently ignore interactions with the {@link ServerStream} from now
diff --git a/core/src/test/java/io/grpc/internal/ServerCallImplTest.java b/core/src/test/java/io/grpc/internal/ServerCallImplTest.java
index 9c25f474804..e7205f17f20 100644
--- a/core/src/test/java/io/grpc/internal/ServerCallImplTest.java
+++ b/core/src/test/java/io/grpc/internal/ServerCallImplTest.java
@@ -33,6 +33,7 @@
import static org.mockito.Mockito.when;
import com.google.common.io.CharStreams;
+import io.grpc.Attributes;
import io.grpc.CompressorRegistry;
import io.grpc.Context;
import io.grpc.DecompressorRegistry;
@@ -41,6 +42,7 @@
import io.grpc.MethodDescriptor;
import io.grpc.MethodDescriptor.Marshaller;
import io.grpc.MethodDescriptor.MethodType;
+import io.grpc.SecurityLevel;
import io.grpc.ServerCall;
import io.grpc.Status;
import io.grpc.internal.ServerCallImpl.ServerStreamListenerImpl;
@@ -352,6 +354,23 @@ public void getNullAuthority() {
verify(stream).getAuthority();
}
+ @Test
+ public void getSecurityLevel() {
+ Attributes attributes = Attributes.newBuilder()
+ .set(GrpcAttributes.ATTR_SECURITY_LEVEL, SecurityLevel.INTEGRITY).build();
+ when(stream.getAttributes()).thenReturn(attributes);
+ assertEquals(SecurityLevel.INTEGRITY, call.getSecurityLevel());
+ verify(stream).getAttributes();
+ }
+
+ @Test
+ public void getNullSecurityLevel() {
+ when(stream.getAttributes()).thenReturn(null);
+ assertEquals(SecurityLevel.NONE, call.getSecurityLevel());
+ verify(stream).getAttributes();
+ }
+
+
@Test
public void setMessageCompression() {
call.setMessageCompression(true);