introduce the new split-type credentials api

pull/3468/head
Jan Tattermusch 9 years ago
parent 9e5e7e9a6c
commit 5bd7005833
  1. 10
      src/csharp/Grpc.Auth/GrpcCredentials.cs
  2. 58
      src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs
  3. 73
      src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
  4. 10
      src/csharp/Grpc.Core.Tests/ChannelTest.cs
  5. 73
      src/csharp/Grpc.Core.Tests/FakeCredentials.cs
  6. 4
      src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
  7. 2
      src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
  8. 2
      src/csharp/Grpc.Core.Tests/MockServiceHelper.cs
  9. 142
      src/csharp/Grpc.Core/CallCredentials.cs
  10. 6
      src/csharp/Grpc.Core/CallOptions.cs
  11. 4
      src/csharp/Grpc.Core/Channel.cs
  12. 146
      src/csharp/Grpc.Core/ChannelCredentials.cs
  13. 3
      src/csharp/Grpc.Core/Grpc.Core.csproj
  14. 2
      src/csharp/Grpc.Examples.MathClient/MathClient.cs
  15. 2
      src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
  16. 2
      src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
  17. 8
      src/csharp/Grpc.IntegrationTesting/InteropClient.cs
  18. 2
      src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs

@ -41,7 +41,7 @@ using Grpc.Core.Utils;
namespace Grpc.Auth
{
/// <summary>
/// Factory methods to create instances of <see cref="Credentials"/> class.
/// Factory methods to create instances of <see cref="ChannelCredentials"/> and <see cref="CallCredentials"/> classes.
/// </summary>
public static class GrpcCredentials
{
@ -57,15 +57,15 @@ namespace Grpc.Auth
}
/// <summary>
/// Convenience method to create a <see cref="CompositeCredentials"/> instance from
/// Convenience method to create a <see cref="ChannelCredentials"/> instance from
/// <c>ITokenAccess</c> credential and <c>SslCredentials</c> instance.
/// </summary>
/// <param name="credential">The credential to use to obtain access tokens.</param>
/// <param name="sslCredentials">The <c>SslCredentials</c> instance.</param>
/// <returns>The composite credential for access token based auth over a secure channel.</returns>
public static CompositeCredentials Create(ITokenAccess credential, SslCredentials sslCredentials)
/// <returns>The channel credentials for access token based auth over a secure channel.</returns>
public static ChannelCredentials Create(ITokenAccess credential, SslCredentials sslCredentials)
{
return CompositeCredentials.Create(Create(credential), sslCredentials);
return ChannelCredentials.Create(sslCredentials, Create(credential));
}
/// <summary>

@ -43,67 +43,23 @@ using NUnit.Framework;
namespace Grpc.Core.Tests
{
public class CredentialsTest
public class CallCredentialsTest
{
[Test]
public void InsecureCredentials_IsNonComposable()
public void CallCredentials_ComposeAtLeastTwo()
{
Assert.IsFalse(Credentials.Insecure.IsComposable);
Assert.Throws(typeof(ArgumentException), () => CallCredentials.Compose(new FakeCallCredentials()));
}
[Test]
public void CompositeCredentials_Create()
public void CallCredentials_ToNativeCredentials()
{
new CompositeCredentials(new FakeCredentials(true), new FakeCredentials(true), new FakeCredentials(true));
}
[Test]
public void CompositeCredentials_ComposeAtLeastTwo()
{
Assert.Throws(typeof(ArgumentException), () => new CompositeCredentials(new FakeCredentials(true)));
}
[Test]
public void CompositeCredentials_ForbidsNonComposable()
{
Assert.Throws(typeof(ArgumentException), () => new CompositeCredentials(new FakeCredentials(true), new FakeCredentials(false)));
}
[Test]
public void CompositeCredentials_ToNativeCredentials()
{
var composite = new CompositeCredentials(new MetadataCredentials(async (uri, m) => { await Task.Delay(1); }), new SslCredentials());
var composite = CallCredentials.Compose(
new MetadataCredentials(async (uri, m) => { await Task.Delay(1); }),
new MetadataCredentials(async (uri, m) => { await Task.Delay(2); }));
using (var nativeComposite = composite.ToNativeCredentials())
{
}
}
[Test]
public void CompositeCredentials_OnlyOneConnectorCredentialAllowed()
{
var composite = new CompositeCredentials(new SslCredentials(), new SslCredentials());
// it makes no sense to compose multiple ssl credentials.
Assert.Throws(typeof(ArgumentException), () => composite.ToNativeCredentials());
}
private class FakeCredentials : Credentials
{
readonly bool composable;
public FakeCredentials(bool composable)
{
this.composable = composable;
}
internal override bool IsComposable
{
get { return composable; }
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return null;
}
}
}
}

@ -0,0 +1,73 @@
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
namespace Grpc.Core.Tests
{
public class ChannelCredentialsTest
{
[Test]
public void InsecureCredentials_IsNonComposable()
{
Assert.IsFalse(ChannelCredentials.Insecure.IsComposable);
}
[Test]
public void ChannelCredentials_CreateComposite()
{
var composite = ChannelCredentials.Create(new FakeChannelCredentials(true), new FakeCallCredentials());
Assert.IsFalse(composite.IsComposable);
Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(null, new FakeCallCredentials()));
Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(new FakeChannelCredentials(true), null));
// forbid composing non-composable
Assert.Throws(typeof(ArgumentException), () => ChannelCredentials.Create(new FakeChannelCredentials(false), new FakeCallCredentials()));
}
[Test]
public void ChannelCredentials_CreateWrapped()
{
ChannelCredentials.Create(new FakeCallCredentials());
}
}
}

@ -44,13 +44,13 @@ namespace Grpc.Core.Tests
[Test]
public void Constructor_RejectsInvalidParams()
{
Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, Credentials.Insecure));
Assert.Throws(typeof(ArgumentNullException), () => new Channel(null, ChannelCredentials.Insecure));
}
[Test]
public void State_IdleAfterCreation()
{
var channel = new Channel("localhost", Credentials.Insecure);
var channel = new Channel("localhost", ChannelCredentials.Insecure);
Assert.AreEqual(ChannelState.Idle, channel.State);
channel.ShutdownAsync().Wait();
}
@ -58,7 +58,7 @@ namespace Grpc.Core.Tests
[Test]
public void WaitForStateChangedAsync_InvalidArgument()
{
var channel = new Channel("localhost", Credentials.Insecure);
var channel = new Channel("localhost", ChannelCredentials.Insecure);
Assert.Throws(typeof(ArgumentException), () => channel.WaitForStateChangedAsync(ChannelState.FatalFailure));
channel.ShutdownAsync().Wait();
}
@ -66,7 +66,7 @@ namespace Grpc.Core.Tests
[Test]
public void ResolvedTarget()
{
var channel = new Channel("127.0.0.1", Credentials.Insecure);
var channel = new Channel("127.0.0.1", ChannelCredentials.Insecure);
Assert.IsTrue(channel.ResolvedTarget.Contains("127.0.0.1"));
channel.ShutdownAsync().Wait();
}
@ -74,7 +74,7 @@ namespace Grpc.Core.Tests
[Test]
public void Shutdown_AllowedOnlyOnce()
{
var channel = new Channel("localhost", Credentials.Insecure);
var channel = new Channel("localhost", ChannelCredentials.Insecure);
channel.ShutdownAsync().Wait();
Assert.Throws(typeof(InvalidOperationException), () => channel.ShutdownAsync().GetAwaiter().GetResult());
}

@ -0,0 +1,73 @@
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
using NUnit.Framework;
namespace Grpc.Core.Tests
{
internal class FakeChannelCredentials : ChannelCredentials
{
readonly bool composable;
public FakeChannelCredentials(bool composable)
{
this.composable = composable;
}
internal override bool IsComposable
{
get { return composable; }
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return null;
}
}
internal class FakeCallCredentials : CallCredentials
{
internal override CredentialsSafeHandle ToNativeCredentials()
{
return null;
}
}
}

@ -63,8 +63,10 @@
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="CallCredentialsTest.cs" />
<Compile Include="FakeCredentials.cs" />
<Compile Include="MarshallingErrorsTest.cs" />
<Compile Include="CredentialsTest.cs" />
<Compile Include="ChannelCredentialsTest.cs" />
<Compile Include="ShutdownTest.cs" />
<Compile Include="Internal\AsyncCallTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

@ -49,7 +49,7 @@ namespace Grpc.Core.Internal.Tests
[SetUp]
public void Init()
{
channel = new Channel("localhost", Credentials.Insecure);
channel = new Channel("localhost", ChannelCredentials.Insecure);
fakeCall = new FakeNativeCall();

@ -154,7 +154,7 @@ namespace Grpc.Core.Tests
{
if (channel == null)
{
channel = new Channel(Host, GetServer().Ports.Single().BoundPort, Credentials.Insecure);
channel = new Channel(Host, GetServer().Ports.Single().BoundPort, ChannelCredentials.Insecure);
}
return channel;
}

@ -0,0 +1,142 @@
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
/// Client-side call credentials. Provide authorization with per-call granularity.
/// </summary>
public abstract class CallCredentials
{
/// <summary>
/// Composes multiple multiple <c>CallCredentials</c> objects into
/// a single <c>CallCredentials</c> object.
/// </summary>
/// <param name="credentials">credentials to compose</param>
/// <returns>The new <c>CompositeCallCredentials</c></returns>
public static CallCredentials Compose(params CallCredentials[] credentials)
{
return new CompositeCallCredentials(credentials);
}
/// <summary>
/// Creates native object for the credentials.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract CredentialsSafeHandle ToNativeCredentials();
}
/// <summary>
/// Asynchronous authentication interceptor for <see cref="MetadataCredentials"/>.
/// </summary>
/// <param name="authUri">URL of a service to which current remote call needs to authenticate</param>
/// <param name="metadata">Metadata to populate with entries that will be added to outgoing call's headers.</param>
/// <returns></returns>
public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata);
/// <summary>
/// Client-side credentials that delegate metadata based auth to an interceptor.
/// The interceptor is automatically invoked for each remote call that uses <c>MetadataCredentials.</c>
/// </summary>
public class MetadataCredentials : CallCredentials
{
readonly AsyncAuthInterceptor interceptor;
/// <summary>
/// Initializes a new instance of <c>MetadataCredentials</c> class.
/// </summary>
/// <param name="interceptor">authentication interceptor</param>
public MetadataCredentials(AsyncAuthInterceptor interceptor)
{
this.interceptor = interceptor;
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor);
return plugin.Credentials;
}
}
/// <summary>
/// Credentials that allow composing multiple credentials objects into one <see cref="CallCredentials"/> object.
/// </summary>
internal sealed class CompositeCallCredentials : CallCredentials
{
readonly List<CallCredentials> credentials;
/// <summary>
/// Initializes a new instance of <c>CompositeCallCredentials</c> class.
/// The resulting credentials object will be composite of all the credentials specified as parameters.
/// </summary>
/// <param name="credentials">credentials to compose</param>
public CompositeCallCredentials(params CallCredentials[] credentials)
{
Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials.");
this.credentials = new List<CallCredentials>(credentials);
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return ToNativeRecursive(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 CredentialsSafeHandle ToNativeRecursive(int startIndex)
{
if (startIndex == credentials.Count - 1)
{
return credentials[startIndex].ToNativeCredentials();
}
using (var cred1 = credentials[startIndex].ToNativeCredentials())
using (var cred2 = ToNativeRecursive(startIndex + 1))
{
var nativeComposite = CredentialsSafeHandle.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;
}
}
}
}

@ -49,7 +49,7 @@ namespace Grpc.Core
CancellationToken cancellationToken;
WriteOptions writeOptions;
ContextPropagationToken propagationToken;
Credentials credentials;
CallCredentials credentials;
/// <summary>
/// Creates a new instance of <c>CallOptions</c> struct.
@ -61,7 +61,7 @@ namespace Grpc.Core
/// <param name="propagationToken">Context propagation token obtained from <see cref="ServerCallContext"/>.</param>
/// <param name="credentials">Credentials to use for this call.</param>
public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken),
WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null, Credentials credentials = null)
WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null, CallCredentials credentials = null)
{
this.headers = headers;
this.deadline = deadline;
@ -120,7 +120,7 @@ namespace Grpc.Core
/// <summary>
/// Credentials to use for this call.
/// </summary>
public Credentials Credentials
public CallCredentials Credentials
{
get
{

@ -68,7 +68,7 @@ namespace Grpc.Core
/// <param name="target">Target of the channel.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
public Channel(string target, Credentials credentials, IEnumerable<ChannelOption> options = null)
public Channel(string target, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null)
{
this.target = Preconditions.CheckNotNull(target, "target");
this.environment = GrpcEnvironment.AddRef();
@ -96,7 +96,7 @@ namespace Grpc.Core
/// <param name="port">The port.</param>
/// <param name="credentials">Credentials to secure the channel.</param>
/// <param name="options">Channel options.</param>
public Channel(string host, int port, Credentials credentials, IEnumerable<ChannelOption> options = null) :
public Channel(string host, int port, ChannelCredentials credentials, IEnumerable<ChannelOption> options = null) :
this(string.Format("{0}:{1}", host, port), credentials, options)
{
}

@ -41,17 +41,17 @@ using Grpc.Core.Utils;
namespace Grpc.Core
{
/// <summary>
/// Client-side credentials. Used for creation of a secure channel.
/// Client-side channel credentials. Used for creation of a secure channel.
/// </summary>
public abstract class Credentials
public abstract class ChannelCredentials
{
static readonly Credentials InsecureInstance = new InsecureCredentialsImpl();
static readonly ChannelCredentials InsecureInstance = new InsecureCredentialsImpl();
/// <summary>
/// Returns instance of credential that provides no security and
/// Returns instance of credentials that provides no security and
/// will result in creating an unsecure channel with no encryption whatsoever.
/// </summary>
public static Credentials Insecure
public static ChannelCredentials Insecure
{
get
{
@ -59,6 +59,29 @@ namespace Grpc.Core
}
}
/// <summary>
/// Creates a new instance of <c>ChannelCredentials</c> class by composing
/// given channel credentials with call credentials.
/// </summary>
/// <param name="channelCredentials">Channel credentials.</param>
/// <param name="callCredentials">Call credentials.</param>
/// <returns>The new composite <c>ChannelCredentials</c></returns>
public static ChannelCredentials Create(ChannelCredentials channelCredentials, CallCredentials callCredentials)
{
return new CompositeChannelCredentials(channelCredentials, callCredentials);
}
/// <summary>
/// Creates a new instance of <c>ChannelCredentials</c> by wrapping
/// an instance of <c>CallCredentials</c>.
/// </summary>
/// <param name="callCredentials">Call credentials.</param>
/// <returns>The <c>ChannelCredentials</c> wrapping given call credentials.</returns>
public static ChannelCredentials Create(CallCredentials callCredentials)
{
return new WrappedCallCredentials(callCredentials);
}
/// <summary>
/// Creates native object for the credentials. May return null if insecure channel
/// should be created.
@ -71,28 +94,22 @@ namespace Grpc.Core
/// </summary>
internal virtual bool IsComposable
{
get { return true; }
get { return false; }
}
private sealed class InsecureCredentialsImpl : Credentials
private sealed class InsecureCredentialsImpl : ChannelCredentials
{
internal override CredentialsSafeHandle ToNativeCredentials()
{
return null;
}
// Composing insecure credentials makes no sense.
internal override bool IsComposable
{
get { return false; }
}
}
}
/// <summary>
/// Client-side SSL credentials.
/// </summary>
public sealed class SslCredentials : Credentials
public sealed class SslCredentials : ChannelCredentials
{
readonly string rootCertificates;
readonly KeyCertificatePair keyCertificatePair;
@ -148,6 +165,12 @@ namespace Grpc.Core
}
}
// Composing composite makes no sense.
internal override bool IsComposable
{
get { return true; }
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
@ -155,94 +178,61 @@ namespace Grpc.Core
}
/// <summary>
/// Asynchronous authentication interceptor for <see cref="MetadataCredentials"/>.
/// Credentials that allow composing one <see cref="ChannelCredentials"/> object and
/// one or more <see cref="CallCredentials"/> objects into a single <see cref="ChannelCredentials"/>.
/// </summary>
/// <param name="authUri">URL of a service to which current remote call needs to authenticate</param>
/// <param name="metadata">Metadata to populate with entries that will be added to outgoing call's headers.</param>
/// <returns></returns>
public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata);
/// <summary>
/// Client-side credentials that delegate metadata based auth to an interceptor.
/// The interceptor is automatically invoked for each remote call that uses <c>MetadataCredentials.</c>
/// </summary>
public partial class MetadataCredentials : Credentials
internal sealed class CompositeChannelCredentials : ChannelCredentials
{
readonly AsyncAuthInterceptor interceptor;
readonly ChannelCredentials channelCredentials;
readonly CallCredentials callCredentials;
/// <summary>
/// Initializes a new instance of <c>MetadataCredentials</c> class.
/// Initializes a new instance of <c>CompositeChannelCredentials</c> class.
/// The resulting credentials object will be composite of all the credentials specified as parameters.
/// </summary>
/// <param name="interceptor">authentication interceptor</param>
public MetadataCredentials(AsyncAuthInterceptor interceptor)
/// <param name="channelCredentials">channelCredentials to compose</param>
/// <param name="callCredentials">channelCredentials to compose</param>
public CompositeChannelCredentials(ChannelCredentials channelCredentials, CallCredentials callCredentials)
{
this.interceptor = interceptor;
this.channelCredentials = Preconditions.CheckNotNull(channelCredentials);
this.callCredentials = Preconditions.CheckNotNull(callCredentials);
Preconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition.");
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor);
return plugin.Credentials;
using (var cred1 = channelCredentials.ToNativeCredentials())
using (var cred2 = callCredentials.ToNativeCredentials())
{
var nativeComposite = CredentialsSafeHandle.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;
}
}
}
/// <summary>
/// Credentials that allow composing multiple credentials objects into one <see cref="Credentials"/> object.
/// Credentials wrapping <see cref="CallCredentials"/> as <see cref="ChannelCredentials"/>.
/// </summary>
public sealed class CompositeCredentials : Credentials
internal sealed class WrappedCallCredentials : ChannelCredentials
{
readonly List<Credentials> credentials;
readonly CallCredentials callCredentials;
/// <summary>
/// Initializes a new instance of <c>CompositeCredentials</c> class.
/// The resulting credentials object will be composite of all the credentials specified as parameters.
/// Wraps instance of <c>CallCredentials</c> as <c>ChannelCredentials</c>.
/// </summary>
/// <param name="credentials">credentials to compose</param>
public CompositeCredentials(params Credentials[] credentials)
/// <param name="callCredentials">credentials to wrap</param>
public WrappedCallCredentials(CallCredentials callCredentials)
{
Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials.");
foreach (var cred in credentials)
{
Preconditions.CheckArgument(cred.IsComposable, "Cannot create composite credentials: one or more credential objects do not allow composition.");
}
this.credentials = new List<Credentials>(credentials);
}
/// <summary>
/// Creates a new instance of <c>CompositeCredentials</c> class by composing
/// multiple <c>Credentials</c> objects.
/// </summary>
/// <param name="credentials">credentials to compose</param>
/// <returns>The new <c>CompositeCredentials</c></returns>
public static CompositeCredentials Create(params Credentials[] credentials)
{
return new CompositeCredentials(credentials);
this.callCredentials = Preconditions.CheckNotNull(callCredentials);
}
internal override CredentialsSafeHandle ToNativeCredentials()
{
return ToNativeRecursive(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 CredentialsSafeHandle ToNativeRecursive(int startIndex)
{
if (startIndex == credentials.Count - 1)
{
return credentials[startIndex].ToNativeCredentials();
}
using (var cred1 = credentials[startIndex].ToNativeCredentials())
using (var cred2 = ToNativeRecursive(startIndex + 1))
{
var nativeComposite = CredentialsSafeHandle.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;
}
return callCredentials.ToNativeCredentials();
}
}
}

@ -48,6 +48,7 @@
<ItemGroup>
<Compile Include="AsyncDuplexStreamingCall.cs" />
<Compile Include="AsyncServerStreamingCall.cs" />
<Compile Include="CallCredentials.cs" />
<Compile Include="IClientStreamWriter.cs" />
<Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" />
<Compile Include="Internal\INativeCall.cs" />
@ -80,7 +81,7 @@
<Compile Include="Utils\AsyncStreamExtensions.cs" />
<Compile Include="Utils\BenchmarkUtil.cs" />
<Compile Include="Internal\CredentialsSafeHandle.cs" />
<Compile Include="Credentials.cs" />
<Compile Include="ChannelCredentials.cs" />
<Compile Include="Internal\ChannelArgsSafeHandle.cs" />
<Compile Include="Internal\AsyncCompletion.cs" />
<Compile Include="Internal\AsyncCallBase.cs" />

@ -39,7 +39,7 @@ namespace Math
{
public static void Main(string[] args)
{
var channel = new Channel("127.0.0.1", 23456, Credentials.Insecure);
var channel = new Channel("127.0.0.1", 23456, ChannelCredentials.Insecure);
Math.IMathClient client = new Math.MathClient(channel);
MathExamples.DivExample(client);

@ -61,7 +61,7 @@ namespace Math.Tests
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
server.Start();
channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = Math.NewClient(channel);
}

@ -63,7 +63,7 @@ namespace Grpc.HealthCheck.Tests
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
};
server.Start();
channel = new Channel(Host, server.Ports.Single().BoundPort, Credentials.Insecure);
channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = Grpc.Health.V1Alpha.Health.NewClient(channel);
}

@ -132,22 +132,22 @@ namespace Grpc.IntegrationTesting
await channel.ShutdownAsync();
}
private async Task<Credentials> CreateCredentialsAsync()
private async Task<ChannelCredentials> CreateCredentialsAsync()
{
var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure;
var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : ChannelCredentials.Insecure;
if (options.TestCase == "jwt_token_creds")
{
var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsTrue(googleCredential.IsCreateScopedRequired);
credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials);
credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials());
}
if (options.TestCase == "compute_engine_creds")
{
var googleCredential = await GoogleCredential.GetApplicationDefaultAsync();
Assert.IsFalse(googleCredential.IsCreateScopedRequired);
credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials);
credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials());
}
return credentials;
}

@ -73,7 +73,7 @@ namespace Grpc.IntegrationTesting
metadata.Add("authorization", "SECRET_TOKEN");
});
var clientCredentials = CompositeCredentials.Create(
var clientCredentials = ChannelCredentials.Create(
new SslCredentials(File.ReadAllText(TestCredentials.ClientCertAuthorityPath)),
new MetadataCredentials(asyncAuthInterceptor));
channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options);

Loading…
Cancel
Save