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 c1bd95b9e22..6344a881070 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;
@@ -48,81 +47,43 @@ namespace Grpc.Core
/// authentication interceptor
public static CallCredentials FromInterceptor(AsyncAuthInterceptor interceptor)
{
- return new MetadataCredentials(interceptor);
+ return new AsyncAuthInterceptorCredentials(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);
- ///
- /// 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()
+ private class CompositeCallCredentials : CallCredentials
{
- NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor);
- return plugin.Credentials;
- }
- }
+ readonly IReadOnlyList credentials;
- ///
- /// Credentials that allow composing multiple credentials objects into one object.
- ///
- internal sealed class CompositeCallCredentials : CallCredentials
- {
- readonly List credentials;
+ public CompositeCallCredentials(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();
+ }
- ///
- /// 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)
- {
- GrpcPreconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials.");
- this.credentials = new List(credentials);
+ public override void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state)
+ {
+ configurator.SetCompositeCredentials(state, credentials);
+ }
}
- internal override CallCredentialsSafeHandle ToNativeCredentials()
+ private class AsyncAuthInterceptorCredentials : CallCredentials
{
- return ToNativeRecursive(0);
- }
+ readonly AsyncAuthInterceptor interceptor;
- // 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)
- {
- if (startIndex == credentials.Count - 1)
+ public AsyncAuthInterceptorCredentials(AsyncAuthInterceptor interceptor)
{
- return credentials[startIndex].ToNativeCredentials();
+ this.interceptor = GrpcPreconditions.CheckNotNull(interceptor);
}
- using (var cred1 = credentials[startIndex].ToNativeCredentials())
- using (var cred2 = ToNativeRecursive(startIndex + 1))
+ public override void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state)
{
- var nativeComposite = CallCredentialsSafeHandle.CreateComposite(cred1, cred2);
- if (nativeComposite.IsInvalid)
- {
- throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
- }
- return nativeComposite;
+ 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/DefaultCallCredentialsConfigurator.cs b/src/csharp/Grpc.Core/Internal/DefaultCallCredentialsConfigurator.cs
new file mode 100644
index 00000000000..a2c53a173c5
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/DefaultCallCredentialsConfigurator.cs
@@ -0,0 +1,85 @@
+#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 Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+ ///
+ /// Creates native call credential objects from instances of CallCredentials.
+ ///
+ internal class DefaultCallCredentialsConfigurator : CallCredentialsConfiguratorBase
+ {
+ CallCredentialsSafeHandle nativeCredentials;
+
+ public CallCredentialsSafeHandle NativeCredentials => nativeCredentials;
+
+ public override void SetAsyncAuthInterceptorCredentials(object state, AsyncAuthInterceptor interceptor)
+ {
+ GrpcPreconditions.CheckState(nativeCredentials == null);
+
+ var plugin = new NativeMetadataCredentialsPlugin(interceptor);
+ nativeCredentials = plugin.Credentials;
+ }
+
+ public override void SetCompositeCredentials(object state, IReadOnlyList credentials)
+ {
+ 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 CompositeToNativeRecursive(IReadOnlyList credentials, int startIndex)
+ {
+ if (startIndex == credentials.Count - 1)
+ {
+ return credentials[startIndex].ToNativeCredentials();
+ }
+
+ using (var cred1 = credentials[startIndex].ToNativeCredentials())
+ using (var cred2 = CompositeToNativeRecursive(credentials, startIndex + 1))
+ {
+ var nativeComposite = CallCredentialsSafeHandle.CreateComposite(cred1, cred2);
+ if (nativeComposite.IsInvalid)
+ {
+ throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
+ }
+ return nativeComposite;
+ }
+ }
+ }
+
+ 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;
+ }
+ }
+}