From a1a878b593366780c3caf272d9c4eb6911906f7c Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 5 Apr 2019 04:47:06 +0200 Subject: [PATCH] make CallCredentials implementation agnostic --- src/csharp/Grpc.Core.Tests/FakeCredentials.cs | 4 +- src/csharp/Grpc.Core/CallCredentials.cs | 44 +++++++++++++--- .../CallCredentialsConfiguratorBase.cs | 38 ++++++++++++++ ... => DefaultCallCredentialsConfigurator.cs} | 49 +++++++++++------- .../Grpc.Core/Internal/MetadataCredentials.cs | 51 ------------------- 5 files changed, 108 insertions(+), 78 deletions(-) create mode 100644 src/csharp/Grpc.Core/CallCredentialsConfiguratorBase.cs rename src/csharp/Grpc.Core/Internal/{CompositeCallCredentials.cs => DefaultCallCredentialsConfigurator.cs} (51%) delete mode 100644 src/csharp/Grpc.Core/Internal/MetadataCredentials.cs diff --git a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs index f23c9e97574..59587b9a510 100644 --- a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs +++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs @@ -42,9 +42,9 @@ namespace Grpc.Core.Tests internal class FakeCallCredentials : CallCredentials { - internal override CallCredentialsSafeHandle ToNativeCredentials() + public override void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state) { - return null; + // not invoking the configurator on purpose } } } diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs index bac75038070..ebe5f260df4 100644 --- a/src/csharp/Grpc.Core/CallCredentials.cs +++ b/src/csharp/Grpc.Core/CallCredentials.cs @@ -16,9 +16,8 @@ #endregion -using System; using System.Collections.Generic; -using System.Threading.Tasks; +using System.Collections.ObjectModel; using Grpc.Core.Internal; using Grpc.Core.Utils; @@ -38,7 +37,7 @@ namespace Grpc.Core /// The new CompositeCallCredentials public static CallCredentials Compose(params CallCredentials[] credentials) { - return new CompositeCallCredentials(credentials); + return new CompositeCallCredentialsConfiguration(credentials); } /// @@ -48,13 +47,44 @@ namespace Grpc.Core /// authentication interceptor public static CallCredentials FromInterceptor(AsyncAuthInterceptor interceptor) { - return new MetadataCredentials(interceptor); + return new AsyncAuthInterceptorCredentialsConfiguration(interceptor); } /// - /// Creates native object for the credentials. + /// Populates this call credential instances. + /// You never need to invoke this, part of internal implementation. /// - /// The native credentials. - internal abstract CallCredentialsSafeHandle ToNativeCredentials(); + public abstract void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state); + + private class CompositeCallCredentialsConfiguration : CallCredentials + { + readonly IReadOnlyList credentials; + + public CompositeCallCredentialsConfiguration(CallCredentials[] credentials) + { + GrpcPreconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials."); + this.credentials = new List(credentials).AsReadOnly(); + } + + public override void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state) + { + configurator.SetCompositeCredentials(state, credentials); + } + } + + internal class AsyncAuthInterceptorCredentialsConfiguration : CallCredentials + { + readonly AsyncAuthInterceptor interceptor; + + public AsyncAuthInterceptorCredentialsConfiguration(AsyncAuthInterceptor interceptor) + { + this.interceptor = GrpcPreconditions.CheckNotNull(interceptor); + } + + public override void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state) + { + configurator.SetAsyncAuthInterceptorCredentials(state, interceptor); + } + } } } diff --git a/src/csharp/Grpc.Core/CallCredentialsConfiguratorBase.cs b/src/csharp/Grpc.Core/CallCredentialsConfiguratorBase.cs new file mode 100644 index 00000000000..40a33bbf599 --- /dev/null +++ b/src/csharp/Grpc.Core/CallCredentialsConfiguratorBase.cs @@ -0,0 +1,38 @@ +#region Copyright notice and license + +// Copyright 2019 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. + +#endregion + +using System.Collections.Generic; + +namespace Grpc.Core +{ + /// + /// Base class for objects that can consume configuration from CallCredentials objects. + /// + public abstract class CallCredentialsConfiguratorBase + { + /// + /// Consumes configuration for composite call credentials. + /// + public abstract void SetCompositeCredentials(object state, IReadOnlyList credentials); + + /// + /// Consumes configuration for call credentials created from AsyncAuthInterceptor + /// + public abstract void SetAsyncAuthInterceptorCredentials(object state, AsyncAuthInterceptor interceptor); + } +} diff --git a/src/csharp/Grpc.Core/Internal/CompositeCallCredentials.cs b/src/csharp/Grpc.Core/Internal/DefaultCallCredentialsConfigurator.cs similarity index 51% rename from src/csharp/Grpc.Core/Internal/CompositeCallCredentials.cs rename to src/csharp/Grpc.Core/Internal/DefaultCallCredentialsConfigurator.cs index 43ce8519e5b..a2c53a173c5 100644 --- a/src/csharp/Grpc.Core/Internal/CompositeCallCredentials.cs +++ b/src/csharp/Grpc.Core/Internal/DefaultCallCredentialsConfigurator.cs @@ -18,39 +18,38 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; - -using Grpc.Core.Internal; using Grpc.Core.Utils; namespace Grpc.Core.Internal { /// - /// Credentials that allow composing multiple credentials objects into one object. + /// Creates native call credential objects from instances of CallCredentials. /// - internal sealed class CompositeCallCredentials : CallCredentials + internal class DefaultCallCredentialsConfigurator : CallCredentialsConfiguratorBase { - readonly List credentials; + CallCredentialsSafeHandle nativeCredentials; - /// - /// Initializes a new instance of CompositeCallCredentials class. - /// The resulting credentials object will be composite of all the credentials specified as parameters. - /// - /// credentials to compose - public CompositeCallCredentials(params CallCredentials[] credentials) + public CallCredentialsSafeHandle NativeCredentials => nativeCredentials; + + public override void SetAsyncAuthInterceptorCredentials(object state, AsyncAuthInterceptor interceptor) { - GrpcPreconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials."); - this.credentials = new List(credentials); + GrpcPreconditions.CheckState(nativeCredentials == null); + + var plugin = new NativeMetadataCredentialsPlugin(interceptor); + nativeCredentials = plugin.Credentials; } - internal override CallCredentialsSafeHandle ToNativeCredentials() + public override void SetCompositeCredentials(object state, IReadOnlyList credentials) { - return ToNativeRecursive(0); + GrpcPreconditions.CheckState(nativeCredentials == null); + + GrpcPreconditions.CheckArgument(credentials.Count >= 2); + nativeCredentials = CompositeToNativeRecursive(credentials, 0); } // Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier. // In practice, we won't usually see composites from more than two credentials anyway. - private CallCredentialsSafeHandle ToNativeRecursive(int startIndex) + private CallCredentialsSafeHandle CompositeToNativeRecursive(IReadOnlyList credentials, int startIndex) { if (startIndex == credentials.Count - 1) { @@ -58,7 +57,7 @@ namespace Grpc.Core.Internal } using (var cred1 = credentials[startIndex].ToNativeCredentials()) - using (var cred2 = ToNativeRecursive(startIndex + 1)) + using (var cred2 = CompositeToNativeRecursive(credentials, startIndex + 1)) { var nativeComposite = CallCredentialsSafeHandle.CreateComposite(cred1, cred2); if (nativeComposite.IsInvalid) @@ -69,4 +68,18 @@ namespace Grpc.Core.Internal } } } + + internal static class CallCredentialsExtensions + { + /// + /// Creates native object for the credentials. + /// + /// The native credentials. + public static CallCredentialsSafeHandle ToNativeCredentials(this CallCredentials credentials) + { + var configurator = new DefaultCallCredentialsConfigurator(); + credentials.InternalPopulateConfiguration(configurator, credentials); + return configurator.NativeCredentials; + } + } } diff --git a/src/csharp/Grpc.Core/Internal/MetadataCredentials.cs b/src/csharp/Grpc.Core/Internal/MetadataCredentials.cs deleted file mode 100644 index 8dd00f072e5..00000000000 --- a/src/csharp/Grpc.Core/Internal/MetadataCredentials.cs +++ /dev/null @@ -1,51 +0,0 @@ -#region Copyright notice and license - -// Copyright 2019 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. - -#endregion - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -using Grpc.Core.Internal; -using Grpc.Core.Utils; - -namespace Grpc.Core.Internal -{ - /// - /// Client-side credentials that delegate metadata based auth to an interceptor. - /// The interceptor is automatically invoked for each remote call that uses MetadataCredentials. - /// - internal sealed class MetadataCredentials : CallCredentials - { - readonly AsyncAuthInterceptor interceptor; - - /// - /// Initializes a new instance of MetadataCredentials class. - /// - /// authentication interceptor - public MetadataCredentials(AsyncAuthInterceptor interceptor) - { - this.interceptor = GrpcPreconditions.CheckNotNull(interceptor); - } - - internal override CallCredentialsSafeHandle ToNativeCredentials() - { - NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor); - return plugin.Credentials; - } - } -}