all: ChannelCredentials.withoutBearerTokens() and LoadBalancer.Helper API change (#7748)

API change (See go/grpc-rls-callcreds-to-server):

- Add `ChannelCredentials.withoutBearerTokens()`
- Add `createResolvingOobChannelBuilder(String, ChannelCredentials)`, `getChannelCredentials()` and `getUnsafeChannelCredentials()` for `LoadBalancer.Helper`

This PR does not include the implementation of `createResolvingOobChannelBuilder(String, ChannelCredentials)`.
This commit is contained in:
ZHANG Dapeng 2020-12-22 22:48:39 -08:00 committed by GitHub
parent e530e10648
commit 90d61178a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 395 additions and 18 deletions

View File

@ -35,4 +35,14 @@ package io.grpc;
* {@code ChoiceChannelCredentials}!).
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/7479")
public abstract class ChannelCredentials {}
public abstract class ChannelCredentials {
/**
* Returns the ChannelCredentials stripped of its CallCredentials. In the future,
* this may strip only some of the CallCredentials, preserving call credentials
* that are safe from replay attacks (e.g., if the token is bound to the
* channel's certificate).
*
* @since 1.35.0
*/
public abstract ChannelCredentials withoutBearerTokens();
}

View File

@ -16,9 +16,10 @@
package io.grpc;
import static java.util.Collections.unmodifiableList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
@ -36,22 +37,31 @@ public final class ChoiceChannelCredentials extends ChannelCredentials {
if (creds.length == 0) {
throw new IllegalArgumentException("At least one credential is required");
}
return new ChoiceChannelCredentials(creds);
}
private final List<ChannelCredentials> creds;
private ChoiceChannelCredentials(ChannelCredentials... creds) {
for (ChannelCredentials cred : creds) {
if (cred == null) {
throw new NullPointerException();
}
}
this.creds = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(creds)));
return new ChoiceChannelCredentials(unmodifiableList(new ArrayList<>(Arrays.asList(creds))));
}
private final List<ChannelCredentials> creds;
private ChoiceChannelCredentials(List<ChannelCredentials> creds) {
this.creds = creds;
}
/** Non-empty list of credentials, in preference order. */
public List<ChannelCredentials> getCredentialsList() {
return creds;
}
@Override
public ChannelCredentials withoutBearerTokens() {
List<ChannelCredentials> credsWithoutTokens = new ArrayList<>();
for (ChannelCredentials cred : creds) {
credsWithoutTokens.add(cred.withoutBearerTokens());
}
return new ChoiceChannelCredentials(unmodifiableList(credsWithoutTokens));
}
}

View File

@ -46,4 +46,9 @@ public final class CompositeChannelCredentials extends ChannelCredentials {
public CallCredentials getCallCredentials() {
return callCredentials;
}
@Override
public ChannelCredentials withoutBearerTokens() {
return channelCredentials.withoutBearerTokens();
}
}

View File

@ -24,4 +24,9 @@ public final class InsecureChannelCredentials extends ChannelCredentials {
}
private InsecureChannelCredentials() {}
@Override
public ChannelCredentials withoutBearerTokens() {
return this;
}
}

View File

@ -1060,6 +1060,24 @@ public abstract class LoadBalancer {
throw new UnsupportedOperationException("Not implemented");
}
/**
* Creates an out-of-band channel builder for LoadBalancer's own RPC needs, e.g., talking to an
* external load-balancer service, that is specified by a target string and credentials. See
* the documentation on {@link Grpc#newChannelBuilder} for the format of a target string.
*
* <p>The target string will be resolved by a {@link NameResolver} created according to the
* target string.
*
* <p>The LoadBalancer is responsible for closing unused OOB channels, and closing all OOB
* channels within {@link #shutdown}.
*
* @since 1.35.0
*/
public ManagedChannelBuilder<?> createResolvingOobChannelBuilder(
String target, ChannelCredentials creds) {
throw new UnsupportedOperationException();
}
/**
* Set a new state with a new picker to the channel.
*
@ -1157,6 +1175,26 @@ public abstract class LoadBalancer {
*/
public abstract String getAuthority();
/**
* Returns the ChannelCredentials used to construct the channel, without bearer tokens.
*
* @since 1.35.0
*/
public ChannelCredentials getChannelCredentials() {
return getUnsafeChannelCredentials().withoutBearerTokens();
}
/**
* Returns the authority string of the channel, which is derived from the DNS-style target name.
* If overridden by a load balancer, {@link #getUnsafeChannelCredentials} must also be
* overridden to call {@link #getChannelCredentials} or provide appropriate credentials.
*
* @since 1.35.0
*/
public ChannelCredentials getUnsafeChannelCredentials() {
throw new UnsupportedOperationException();
}
/**
* Returns the {@link ChannelLogger} for the Channel served by this LoadBalancer.
*

View File

@ -81,6 +81,11 @@ public final class TlsChannelCredentials extends ChannelCredentials {
}
}
@Override
public ChannelCredentials withoutBearerTokens() {
return this;
}
/**
* Features to understand TLS configuration. Additional enum values may be added in the future.
*/

View File

@ -0,0 +1,51 @@
/*
* Copyright 2020 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link ChoiceChannelCredentials}. */
@RunWith(JUnit4.class)
public class ChoiceChannelCredentialsTest {
@Test
public void withoutBearTokenGivesChoiceOfCredsWithoutToken() {
final ChannelCredentials creds1WithoutToken = mock(ChannelCredentials.class);
ChannelCredentials creds1 = new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
return creds1WithoutToken;
}
};
final ChannelCredentials creds2WithoutToken = mock(ChannelCredentials.class);
ChannelCredentials creds2 = new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
return creds2WithoutToken;
}
};
ChannelCredentials choice = ChoiceChannelCredentials.create(creds1, creds2);
ChannelCredentials choiceWithouToken = choice.withoutBearerTokens();
assertThat(choiceWithouToken).isInstanceOf(ChoiceChannelCredentials.class);
assertThat(((ChoiceChannelCredentials) choiceWithouToken).getCredentialsList())
.containsExactly(creds1WithoutToken, creds2WithoutToken);
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2020 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link CompositeChannelCredentials}. */
@RunWith(JUnit4.class)
public class CompositeChannelCredentialsTest {
@Test
public void withoutBearTokenGivesCredsWithoutCallCreds() {
ChannelCredentials channelChreds = new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
return this;
}
};
CallCredentials callCreds = mock(CallCredentials.class);
ChannelCredentials comp = CompositeChannelCredentials.create(channelChreds, callCreds);
assertThat(comp.withoutBearerTokens()).isEqualTo(channelChreds);
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2020 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 static com.google.common.truth.Truth.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link InsecureChannelCredentials}. */
@RunWith(JUnit4.class)
public class InsecureChannelCredentialsTest {
@Test
public void withoutBearTokenGivesItself() {
ChannelCredentials insecureCreds = InsecureChannelCredentials.create();
assertThat(insecureCreds.withoutBearerTokens()).isEqualTo(insecureCreds);
}
}

View File

@ -27,7 +27,12 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class ManagedChannelRegistryTest {
private String target = "testing123";
private ChannelCredentials creds = new ChannelCredentials() {};
private ChannelCredentials creds = new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
throw new UnsupportedOperationException();
}
};
@Test
public void register_unavailableProviderThrows() {

View File

@ -0,0 +1,33 @@
/*
* Copyright 2020 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 static com.google.common.truth.Truth.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link TlsChannelCredentials}. */
@RunWith(JUnit4.class)
public class TlsChannelCredentialsTest {
@Test
public void withoutBearTokenGivesItself() {
ChannelCredentials tlsCreds = TlsChannelCredentials.create();
assertThat(tlsCreds.withoutBearerTokens()).isEqualTo(tlsCreds);
}
}

View File

@ -18,6 +18,7 @@ package io.grpc.util;
import com.google.common.base.MoreObjects;
import io.grpc.Attributes;
import io.grpc.ChannelCredentials;
import io.grpc.ChannelLogger;
import io.grpc.ConnectivityState;
import io.grpc.EquivalentAddressGroup;
@ -74,6 +75,12 @@ public abstract class ForwardingLoadBalancerHelper extends LoadBalancer.Helper {
return delegate().createResolvingOobChannelBuilder(target);
}
@Override
public ManagedChannelBuilder<?> createResolvingOobChannelBuilder(
String target, ChannelCredentials creds) {
return delegate().createResolvingOobChannelBuilder(target, creds);
}
@Override
public ManagedChannel createResolvingOobChannel(String target) {
return delegate().createResolvingOobChannel(target);
@ -107,6 +114,16 @@ public abstract class ForwardingLoadBalancerHelper extends LoadBalancer.Helper {
return delegate().getAuthority();
}
@Override
public ChannelCredentials getChannelCredentials() {
return delegate().getChannelCredentials();
}
@Override
public ChannelCredentials getUnsafeChannelCredentials() {
return delegate().getUnsafeChannelCredentials();
}
@Override
public SynchronizationContext getSynchronizationContext() {
return delegate().getSynchronizationContext();

View File

@ -34,4 +34,9 @@ final class NettyChannelCredentials extends ChannelCredentials {
public ProtocolNegotiator.ClientFactory getNegotiator() {
return negotiator;
}
@Override
public ChannelCredentials withoutBearerTokens() {
return this;
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2020 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.netty;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import io.grpc.ChannelCredentials;
import io.grpc.netty.ProtocolNegotiator.ClientFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link NettyChannelCredentials}. */
@RunWith(JUnit4.class)
public class NettyChannelCredentialsTest {
@Test
public void withoutBearTokenGivesItself() {
ChannelCredentials nettyChannelCreds =
NettyChannelCredentials.create(mock(ClientFactory.class));
assertThat(nettyChannelCreds.withoutBearerTokens()).isEqualTo(nettyChannelCreds);
}
}

View File

@ -184,7 +184,12 @@ public class ProtocolNegotiatorsTest {
@Test
public void fromClient_unknown() {
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(new ChannelCredentials() {});
ProtocolNegotiators.from(new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
throw new UnsupportedOperationException();
}
});
assertThat(result.error).isNotNull();
assertThat(result.callCredentials).isNull();
assertThat(result.negotiator).isNull();
@ -252,7 +257,12 @@ public class ProtocolNegotiatorsTest {
public void fromClient_choice() {
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(ChoiceChannelCredentials.create(
new ChannelCredentials() {},
new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
throw new UnsupportedOperationException();
}
},
TlsChannelCredentials.create(),
InsecureChannelCredentials.create()));
assertThat(result.error).isNull();
@ -262,7 +272,12 @@ public class ProtocolNegotiatorsTest {
result = ProtocolNegotiators.from(ChoiceChannelCredentials.create(
InsecureChannelCredentials.create(),
new ChannelCredentials() {},
new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
throw new UnsupportedOperationException();
}
},
TlsChannelCredentials.create()));
assertThat(result.error).isNull();
assertThat(result.callCredentials).isNull();
@ -274,7 +289,12 @@ public class ProtocolNegotiatorsTest {
public void fromClient_choice_unknown() {
ProtocolNegotiators.FromChannelCredentialsResult result =
ProtocolNegotiators.from(ChoiceChannelCredentials.create(
new ChannelCredentials() {}));
new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
throw new UnsupportedOperationException();
}
}));
assertThat(result.error).isNotNull();
assertThat(result.callCredentials).isNull();
assertThat(result.negotiator).isNull();

View File

@ -40,5 +40,10 @@ public final class SslSocketFactoryChannelCredentials {
public SSLSocketFactory getFactory() {
return factory;
}
@Override
public io.grpc.ChannelCredentials withoutBearerTokens() {
return this;
}
}
}

View File

@ -125,7 +125,12 @@ public class OkHttpChannelBuilderTest {
@Test
public void sslSocketFactoryFrom_unknown() {
OkHttpChannelBuilder.SslSocketFactoryResult result =
OkHttpChannelBuilder.sslSocketFactoryFrom(new ChannelCredentials() {});
OkHttpChannelBuilder.sslSocketFactoryFrom(new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
throw new UnsupportedOperationException();
}
});
assertThat(result.error).isNotNull();
assertThat(result.callCredentials).isNull();
assertThat(result.factory).isNull();
@ -191,7 +196,12 @@ public class OkHttpChannelBuilderTest {
public void sslSocketFactoryFrom_choice() {
OkHttpChannelBuilder.SslSocketFactoryResult result =
OkHttpChannelBuilder.sslSocketFactoryFrom(ChoiceChannelCredentials.create(
new ChannelCredentials() {},
new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
throw new UnsupportedOperationException();
}
},
TlsChannelCredentials.create(),
InsecureChannelCredentials.create()));
assertThat(result.error).isNull();
@ -200,7 +210,12 @@ public class OkHttpChannelBuilderTest {
result = OkHttpChannelBuilder.sslSocketFactoryFrom(ChoiceChannelCredentials.create(
InsecureChannelCredentials.create(),
new ChannelCredentials() {},
new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
throw new UnsupportedOperationException();
}
},
TlsChannelCredentials.create()));
assertThat(result.error).isNull();
assertThat(result.callCredentials).isNull();
@ -211,7 +226,12 @@ public class OkHttpChannelBuilderTest {
public void sslSocketFactoryFrom_choice_unknown() {
OkHttpChannelBuilder.SslSocketFactoryResult result =
OkHttpChannelBuilder.sslSocketFactoryFrom(ChoiceChannelCredentials.create(
new ChannelCredentials() {}));
new ChannelCredentials() {
@Override
public ChannelCredentials withoutBearerTokens() {
throw new UnsupportedOperationException();
}
}));
assertThat(result.error).isNotNull();
assertThat(result.callCredentials).isNull();
assertThat(result.factory).isNull();

View File

@ -0,0 +1,37 @@
/*
* Copyright 2020 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.okhttp;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import io.grpc.ChannelCredentials;
import javax.net.ssl.SSLSocketFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link SslSocketFactoryChannelCredentials}. */
@RunWith(JUnit4.class)
public class SslSocketFactoryChannelCredentialsTest {
@Test
public void withoutBearTokenGivesItself() {
ChannelCredentials sslSocketFactoryCreds =
SslSocketFactoryChannelCredentials.create(mock(SSLSocketFactory.class));
assertThat(sslSocketFactoryCreds.withoutBearerTokens()).isEqualTo(sslSocketFactoryCreds);
}
}