From 74f39e185eaddfb07e9b024b0d8aec547cd83821 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 23 Sep 2015 20:14:56 -0700 Subject: Migrate C# to the new auth API --- .../Grpc.IntegrationTesting/InteropClient.cs | 52 ++++++++++++---------- 1 file changed, 29 insertions(+), 23 deletions(-) (limited to 'src/csharp/Grpc.IntegrationTesting/InteropClient.cs') diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 504d798b89..d3b7fe87f3 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -33,11 +33,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using CommandLine; +using CommandLine.Text; using Google.Apis.Auth.OAuth2; using Google.Protobuf; using Grpc.Auth; @@ -45,8 +47,6 @@ using Grpc.Core; using Grpc.Core.Utils; using Grpc.Testing; using NUnit.Framework; -using CommandLine.Text; -using System.IO; namespace Grpc.IntegrationTesting { @@ -117,6 +117,20 @@ namespace Grpc.IntegrationTesting private async Task Run() { var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure; + + if (options.TestCase == "jwt_token_creds") + { + var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); + Assert.IsTrue(googleCredential.IsCreateScopedRequired); + credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials); + } + + if (options.TestCase == "compute_engine_creds") + { + var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); + Assert.IsFalse(googleCredential.IsCreateScopedRequired); + credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials); + } List channelOptions = null; if (!string.IsNullOrEmpty(options.ServerHostOverride)) @@ -155,10 +169,10 @@ namespace Grpc.IntegrationTesting await RunEmptyStreamAsync(client); break; case "compute_engine_creds": - await RunComputeEngineCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope); + RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope); break; case "jwt_token_creds": - await RunJwtTokenCredsAsync(client, options.DefaultServiceAccount); + RunJwtTokenCreds(client, options.DefaultServiceAccount); break; case "oauth2_auth_token": await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope); @@ -318,13 +332,10 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static async Task RunComputeEngineCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) + public static void RunComputeEngineCreds(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) { Console.WriteLine("running compute_engine_creds"); - var credential = await GoogleCredential.GetApplicationDefaultAsync(); - Assert.IsFalse(credential.IsCreateScopedRequired); - client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); - + var request = new SimpleRequest { ResponseType = PayloadType.COMPRESSABLE, @@ -334,6 +345,7 @@ namespace Grpc.IntegrationTesting FillOauthScope = true }; + // not setting credentials here because they were set on channel already var response = client.UnaryCall(request); Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); @@ -344,13 +356,10 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static async Task RunJwtTokenCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount) + public static void RunJwtTokenCreds(TestService.TestServiceClient client, string defaultServiceAccount) { Console.WriteLine("running jwt_token_creds"); - var credential = await GoogleCredential.GetApplicationDefaultAsync(); - Assert.IsTrue(credential.IsCreateScopedRequired); - client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); - + var request = new SimpleRequest { ResponseType = PayloadType.COMPRESSABLE, @@ -359,6 +368,7 @@ namespace Grpc.IntegrationTesting FillUsername = true, }; + // not setting credentials here because they were set on channel already var response = client.UnaryCall(request); Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); @@ -373,15 +383,14 @@ namespace Grpc.IntegrationTesting ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); string oauth2Token = await credential.GetAccessTokenForRequestAsync(); - client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token); - + var credentials = GrpcCredentials.FromAccessToken(oauth2Token); var request = new SimpleRequest { FillUsername = true, FillOauthScope = true }; - var response = client.UnaryCall(request); + var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); Assert.False(string.IsNullOrEmpty(response.OauthScope)); Assert.True(oauthScope.Contains(response.OauthScope)); @@ -392,18 +401,15 @@ namespace Grpc.IntegrationTesting public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) { Console.WriteLine("running per_rpc_creds"); - ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); - string accessToken = await credential.GetAccessTokenForRequestAsync(); - var headerInterceptor = AuthInterceptors.FromAccessToken(accessToken); + ITokenAccess googleCredential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); + var credentials = GrpcCredentials.Create(googleCredential); var request = new SimpleRequest { FillUsername = true, }; - var headers = new Metadata(); - headerInterceptor(null, "", headers); - var response = client.UnaryCall(request, headers: headers); + var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); Assert.AreEqual(defaultServiceAccount, response.Username); Console.WriteLine("Passed!"); -- cgit v1.2.3 From 9e5e7e9a6cde7f9d91b00cb65b3c99e01916c813 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 24 Sep 2015 10:34:05 -0700 Subject: a small interop client refactoring --- .../Grpc.IntegrationTesting/InteropClient.cs | 32 +++++++++++++--------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'src/csharp/Grpc.IntegrationTesting/InteropClient.cs') diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index d3b7fe87f3..c99084d1a9 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -115,6 +115,24 @@ namespace Grpc.IntegrationTesting } private async Task Run() + { + var credentials = await CreateCredentialsAsync(); + + List channelOptions = null; + if (!string.IsNullOrEmpty(options.ServerHostOverride)) + { + channelOptions = new List + { + new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) + }; + } + var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); + TestService.TestServiceClient client = new TestService.TestServiceClient(channel); + await RunTestCaseAsync(client, options); + await channel.ShutdownAsync(); + } + + private async Task CreateCredentialsAsync() { var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : Credentials.Insecure; @@ -131,19 +149,7 @@ namespace Grpc.IntegrationTesting Assert.IsFalse(googleCredential.IsCreateScopedRequired); credentials = CompositeCredentials.Create(googleCredential.ToGrpcCredentials(), credentials); } - - List channelOptions = null; - if (!string.IsNullOrEmpty(options.ServerHostOverride)) - { - channelOptions = new List - { - new ChannelOption(ChannelOptions.SslTargetNameOverride, options.ServerHostOverride) - }; - } - var channel = new Channel(options.ServerHost, options.ServerPort, credentials, channelOptions); - TestService.TestServiceClient client = new TestService.TestServiceClient(channel); - await RunTestCaseAsync(client, options); - await channel.ShutdownAsync(); + return credentials; } private async Task RunTestCaseAsync(TestService.TestServiceClient client, ClientOptions options) -- cgit v1.2.3 From 5bd7005833b60d9db31860049458b122fa496599 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 6 Oct 2015 16:47:49 -0700 Subject: introduce the new split-type credentials api --- src/csharp/Grpc.Auth/GrpcCredentials.cs | 10 +- src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs | 65 ++++++ .../Grpc.Core.Tests/ChannelCredentialsTest.cs | 73 ++++++ src/csharp/Grpc.Core.Tests/ChannelTest.cs | 10 +- src/csharp/Grpc.Core.Tests/CredentialsTest.cs | 109 --------- src/csharp/Grpc.Core.Tests/FakeCredentials.cs | 73 ++++++ src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj | 4 +- .../Grpc.Core.Tests/Internal/AsyncCallTest.cs | 2 +- src/csharp/Grpc.Core.Tests/MockServiceHelper.cs | 2 +- src/csharp/Grpc.Core/CallCredentials.cs | 142 ++++++++++++ src/csharp/Grpc.Core/CallOptions.cs | 6 +- src/csharp/Grpc.Core/Channel.cs | 4 +- src/csharp/Grpc.Core/ChannelCredentials.cs | 238 ++++++++++++++++++++ src/csharp/Grpc.Core/Credentials.cs | 248 --------------------- src/csharp/Grpc.Core/Grpc.Core.csproj | 3 +- src/csharp/Grpc.Examples.MathClient/MathClient.cs | 2 +- .../Grpc.Examples.Tests/MathClientServerTests.cs | 2 +- .../HealthClientServerTest.cs | 2 +- .../Grpc.IntegrationTesting/InteropClient.cs | 8 +- .../MetadataCredentialsTest.cs | 2 +- 20 files changed, 621 insertions(+), 384 deletions(-) create mode 100644 src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs create mode 100644 src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs delete mode 100644 src/csharp/Grpc.Core.Tests/CredentialsTest.cs create mode 100644 src/csharp/Grpc.Core.Tests/FakeCredentials.cs create mode 100644 src/csharp/Grpc.Core/CallCredentials.cs create mode 100644 src/csharp/Grpc.Core/ChannelCredentials.cs delete mode 100644 src/csharp/Grpc.Core/Credentials.cs (limited to 'src/csharp/Grpc.IntegrationTesting/InteropClient.cs') diff --git a/src/csharp/Grpc.Auth/GrpcCredentials.cs b/src/csharp/Grpc.Auth/GrpcCredentials.cs index 496d8e1416..d8b10804c6 100644 --- a/src/csharp/Grpc.Auth/GrpcCredentials.cs +++ b/src/csharp/Grpc.Auth/GrpcCredentials.cs @@ -41,7 +41,7 @@ using Grpc.Core.Utils; namespace Grpc.Auth { /// - /// Factory methods to create instances of class. + /// Factory methods to create instances of and classes. /// public static class GrpcCredentials { @@ -57,15 +57,15 @@ namespace Grpc.Auth } /// - /// Convenience method to create a instance from + /// Convenience method to create a instance from /// ITokenAccess credential and SslCredentials instance. /// /// The credential to use to obtain access tokens. /// The SslCredentials instance. - /// The composite credential for access token based auth over a secure channel. - public static CompositeCredentials Create(ITokenAccess credential, SslCredentials sslCredentials) + /// The channel credentials for access token based auth over a secure channel. + public static ChannelCredentials Create(ITokenAccess credential, SslCredentials sslCredentials) { - return CompositeCredentials.Create(Create(credential), sslCredentials); + return ChannelCredentials.Create(sslCredentials, Create(credential)); } /// diff --git a/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs new file mode 100644 index 0000000000..451963229a --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs @@ -0,0 +1,65 @@ +#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 CallCredentialsTest + { + [Test] + public void CallCredentials_ComposeAtLeastTwo() + { + Assert.Throws(typeof(ArgumentException), () => CallCredentials.Compose(new FakeCallCredentials())); + } + + [Test] + public void CallCredentials_ToNativeCredentials() + { + 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()) + { + } + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs new file mode 100644 index 0000000000..489bf38575 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs @@ -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()); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/ChannelTest.cs b/src/csharp/Grpc.Core.Tests/ChannelTest.cs index dfbd92879e..f4ae9abefd 100644 --- a/src/csharp/Grpc.Core.Tests/ChannelTest.cs +++ b/src/csharp/Grpc.Core.Tests/ChannelTest.cs @@ -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()); } diff --git a/src/csharp/Grpc.Core.Tests/CredentialsTest.cs b/src/csharp/Grpc.Core.Tests/CredentialsTest.cs deleted file mode 100644 index 5048144f98..0000000000 --- a/src/csharp/Grpc.Core.Tests/CredentialsTest.cs +++ /dev/null @@ -1,109 +0,0 @@ -#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 CredentialsTest - { - [Test] - public void InsecureCredentials_IsNonComposable() - { - Assert.IsFalse(Credentials.Insecure.IsComposable); - } - - [Test] - public void CompositeCredentials_Create() - { - 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()); - 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; - } - } - } -} diff --git a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs new file mode 100644 index 0000000000..87d55cd276 --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs @@ -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; + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index 0ebfaa0a62..91d072abab 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -63,8 +63,10 @@ Version.cs + + - + diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs index 685c5f7d6c..246072bff1 100644 --- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs +++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.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(); diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs index 765732c768..567e04eddc 100644 --- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs +++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs @@ -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; } diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs new file mode 100644 index 0000000000..809c9f412d --- /dev/null +++ b/src/csharp/Grpc.Core/CallCredentials.cs @@ -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 +{ + /// + /// Client-side call credentials. Provide authorization with per-call granularity. + /// + public abstract class CallCredentials + { + /// + /// Composes multiple multiple CallCredentials objects into + /// a single CallCredentials object. + /// + /// credentials to compose + /// The new CompositeCallCredentials + public static CallCredentials Compose(params CallCredentials[] credentials) + { + return new CompositeCallCredentials(credentials); + } + + /// + /// Creates native object for the credentials. + /// + /// The native credentials. + internal abstract CredentialsSafeHandle ToNativeCredentials(); + } + + /// + /// Asynchronous authentication interceptor for . + /// + /// URL of a service to which current remote call needs to authenticate + /// Metadata to populate with entries that will be added to outgoing call's headers. + /// + public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata); + + /// + /// Client-side credentials that delegate metadata based auth to an interceptor. + /// The interceptor is automatically invoked for each remote call that uses MetadataCredentials. + /// + public class MetadataCredentials : CallCredentials + { + readonly AsyncAuthInterceptor interceptor; + + /// + /// Initializes a new instance of MetadataCredentials class. + /// + /// authentication interceptor + public MetadataCredentials(AsyncAuthInterceptor interceptor) + { + this.interceptor = interceptor; + } + + internal override CredentialsSafeHandle ToNativeCredentials() + { + NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor); + return plugin.Credentials; + } + } + + /// + /// Credentials that allow composing multiple credentials objects into one object. + /// + internal sealed class CompositeCallCredentials : CallCredentials + { + readonly List credentials; + + /// + /// 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) + { + Preconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials."); + this.credentials = new List(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; + } + } + } +} diff --git a/src/csharp/Grpc.Core/CallOptions.cs b/src/csharp/Grpc.Core/CallOptions.cs index c708fcdfc4..c0f94c63c2 100644 --- a/src/csharp/Grpc.Core/CallOptions.cs +++ b/src/csharp/Grpc.Core/CallOptions.cs @@ -49,7 +49,7 @@ namespace Grpc.Core CancellationToken cancellationToken; WriteOptions writeOptions; ContextPropagationToken propagationToken; - Credentials credentials; + CallCredentials credentials; /// /// Creates a new instance of CallOptions struct. @@ -61,7 +61,7 @@ namespace Grpc.Core /// Context propagation token obtained from . /// Credentials to use for this call. 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 /// /// Credentials to use for this call. /// - public Credentials Credentials + public CallCredentials Credentials { get { diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index f1942727cd..6b99055d4c 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -68,7 +68,7 @@ namespace Grpc.Core /// Target of the channel. /// Credentials to secure the channel. /// Channel options. - public Channel(string target, Credentials credentials, IEnumerable options = null) + public Channel(string target, ChannelCredentials credentials, IEnumerable options = null) { this.target = Preconditions.CheckNotNull(target, "target"); this.environment = GrpcEnvironment.AddRef(); @@ -96,7 +96,7 @@ namespace Grpc.Core /// The port. /// Credentials to secure the channel. /// Channel options. - public Channel(string host, int port, Credentials credentials, IEnumerable options = null) : + public Channel(string host, int port, ChannelCredentials credentials, IEnumerable options = null) : this(string.Format("{0}:{1}", host, port), credentials, options) { } diff --git a/src/csharp/Grpc.Core/ChannelCredentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs new file mode 100644 index 0000000000..599674e02b --- /dev/null +++ b/src/csharp/Grpc.Core/ChannelCredentials.cs @@ -0,0 +1,238 @@ +#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 +{ + /// + /// Client-side channel credentials. Used for creation of a secure channel. + /// + public abstract class ChannelCredentials + { + static readonly ChannelCredentials InsecureInstance = new InsecureCredentialsImpl(); + + /// + /// Returns instance of credentials that provides no security and + /// will result in creating an unsecure channel with no encryption whatsoever. + /// + public static ChannelCredentials Insecure + { + get + { + return InsecureInstance; + } + } + + /// + /// Creates a new instance of ChannelCredentials class by composing + /// given channel credentials with call credentials. + /// + /// Channel credentials. + /// Call credentials. + /// The new composite ChannelCredentials + public static ChannelCredentials Create(ChannelCredentials channelCredentials, CallCredentials callCredentials) + { + return new CompositeChannelCredentials(channelCredentials, callCredentials); + } + + /// + /// Creates a new instance of ChannelCredentials by wrapping + /// an instance of CallCredentials. + /// + /// Call credentials. + /// The ChannelCredentials wrapping given call credentials. + public static ChannelCredentials Create(CallCredentials callCredentials) + { + return new WrappedCallCredentials(callCredentials); + } + + /// + /// Creates native object for the credentials. May return null if insecure channel + /// should be created. + /// + /// The native credentials. + internal abstract CredentialsSafeHandle ToNativeCredentials(); + + /// + /// Returns true if this credential type allows being composed by CompositeCredentials. + /// + internal virtual bool IsComposable + { + get { return false; } + } + + private sealed class InsecureCredentialsImpl : ChannelCredentials + { + internal override CredentialsSafeHandle ToNativeCredentials() + { + return null; + } + } + } + + /// + /// Client-side SSL credentials. + /// + public sealed class SslCredentials : ChannelCredentials + { + readonly string rootCertificates; + readonly KeyCertificatePair keyCertificatePair; + + /// + /// Creates client-side SSL credentials loaded from + /// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable. + /// If that fails, gets the roots certificates from a well known place on disk. + /// + public SslCredentials() : this(null, null) + { + } + + /// + /// Creates client-side SSL credentials from + /// a string containing PEM encoded root certificates. + /// + public SslCredentials(string rootCertificates) : this(rootCertificates, null) + { + } + + /// + /// Creates client-side SSL credentials. + /// + /// string containing PEM encoded server root certificates. + /// a key certificate pair. + public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair) + { + this.rootCertificates = rootCertificates; + this.keyCertificatePair = keyCertificatePair; + } + + /// + /// PEM encoding of the server root certificates. + /// + public string RootCertificates + { + get + { + return this.rootCertificates; + } + } + + /// + /// Client side key and certificate pair. + /// If null, client will not use key and certificate pair. + /// + public KeyCertificatePair KeyCertificatePair + { + get + { + return this.keyCertificatePair; + } + } + + // Composing composite makes no sense. + internal override bool IsComposable + { + get { return true; } + } + + internal override CredentialsSafeHandle ToNativeCredentials() + { + return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair); + } + } + + /// + /// Credentials that allow composing one object and + /// one or more objects into a single . + /// + internal sealed class CompositeChannelCredentials : ChannelCredentials + { + readonly ChannelCredentials channelCredentials; + readonly CallCredentials callCredentials; + + /// + /// Initializes a new instance of CompositeChannelCredentials class. + /// The resulting credentials object will be composite of all the credentials specified as parameters. + /// + /// channelCredentials to compose + /// channelCredentials to compose + public CompositeChannelCredentials(ChannelCredentials channelCredentials, CallCredentials callCredentials) + { + 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() + { + 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; + } + } + } + + /// + /// Credentials wrapping as . + /// + internal sealed class WrappedCallCredentials : ChannelCredentials + { + readonly CallCredentials callCredentials; + + /// + /// Wraps instance of CallCredentials as ChannelCredentials. + /// + /// credentials to wrap + public WrappedCallCredentials(CallCredentials callCredentials) + { + this.callCredentials = Preconditions.CheckNotNull(callCredentials); + } + + internal override CredentialsSafeHandle ToNativeCredentials() + { + return callCredentials.ToNativeCredentials(); + } + } +} diff --git a/src/csharp/Grpc.Core/Credentials.cs b/src/csharp/Grpc.Core/Credentials.cs deleted file mode 100644 index fcef627b25..0000000000 --- a/src/csharp/Grpc.Core/Credentials.cs +++ /dev/null @@ -1,248 +0,0 @@ -#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 -{ - /// - /// Client-side credentials. Used for creation of a secure channel. - /// - public abstract class Credentials - { - static readonly Credentials InsecureInstance = new InsecureCredentialsImpl(); - - /// - /// Returns instance of credential that provides no security and - /// will result in creating an unsecure channel with no encryption whatsoever. - /// - public static Credentials Insecure - { - get - { - return InsecureInstance; - } - } - - /// - /// Creates native object for the credentials. May return null if insecure channel - /// should be created. - /// - /// The native credentials. - internal abstract CredentialsSafeHandle ToNativeCredentials(); - - /// - /// Returns true if this credential type allows being composed by CompositeCredentials. - /// - internal virtual bool IsComposable - { - get { return true; } - } - - private sealed class InsecureCredentialsImpl : Credentials - { - internal override CredentialsSafeHandle ToNativeCredentials() - { - return null; - } - - // Composing insecure credentials makes no sense. - internal override bool IsComposable - { - get { return false; } - } - } - } - - /// - /// Client-side SSL credentials. - /// - public sealed class SslCredentials : Credentials - { - readonly string rootCertificates; - readonly KeyCertificatePair keyCertificatePair; - - /// - /// Creates client-side SSL credentials loaded from - /// disk file pointed to by the GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable. - /// If that fails, gets the roots certificates from a well known place on disk. - /// - public SslCredentials() : this(null, null) - { - } - - /// - /// Creates client-side SSL credentials from - /// a string containing PEM encoded root certificates. - /// - public SslCredentials(string rootCertificates) : this(rootCertificates, null) - { - } - - /// - /// Creates client-side SSL credentials. - /// - /// string containing PEM encoded server root certificates. - /// a key certificate pair. - public SslCredentials(string rootCertificates, KeyCertificatePair keyCertificatePair) - { - this.rootCertificates = rootCertificates; - this.keyCertificatePair = keyCertificatePair; - } - - /// - /// PEM encoding of the server root certificates. - /// - public string RootCertificates - { - get - { - return this.rootCertificates; - } - } - - /// - /// Client side key and certificate pair. - /// If null, client will not use key and certificate pair. - /// - public KeyCertificatePair KeyCertificatePair - { - get - { - return this.keyCertificatePair; - } - } - - internal override CredentialsSafeHandle ToNativeCredentials() - { - return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair); - } - } - - /// - /// Asynchronous authentication interceptor for . - /// - /// URL of a service to which current remote call needs to authenticate - /// Metadata to populate with entries that will be added to outgoing call's headers. - /// - public delegate Task AsyncAuthInterceptor(string authUri, Metadata metadata); - - /// - /// Client-side credentials that delegate metadata based auth to an interceptor. - /// The interceptor is automatically invoked for each remote call that uses MetadataCredentials. - /// - public partial class MetadataCredentials : Credentials - { - readonly AsyncAuthInterceptor interceptor; - - /// - /// Initializes a new instance of MetadataCredentials class. - /// - /// authentication interceptor - public MetadataCredentials(AsyncAuthInterceptor interceptor) - { - this.interceptor = interceptor; - } - - internal override CredentialsSafeHandle ToNativeCredentials() - { - NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor); - return plugin.Credentials; - } - } - - /// - /// Credentials that allow composing multiple credentials objects into one object. - /// - public sealed class CompositeCredentials : Credentials - { - readonly List credentials; - - /// - /// Initializes a new instance of CompositeCredentials class. - /// The resulting credentials object will be composite of all the credentials specified as parameters. - /// - /// credentials to compose - public CompositeCredentials(params Credentials[] credentials) - { - 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); - } - - /// - /// Creates a new instance of CompositeCredentials class by composing - /// multiple Credentials objects. - /// - /// credentials to compose - /// The new CompositeCredentials - public static CompositeCredentials Create(params Credentials[] credentials) - { - return new CompositeCredentials(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; - } - } - } -} diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 04c3eda113..92d4e19eac 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -48,6 +48,7 @@ + @@ -80,7 +81,7 @@ - + diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs index 01e4a80bab..64e429ed5a 100644 --- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs +++ b/src/csharp/Grpc.Examples.MathClient/MathClient.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); diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index e2975b5da9..290d42808e 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -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); } diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs index 6c3a53bec0..d90f21c2e1 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs +++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs @@ -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); } diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index c99084d1a9..0df4ee35ba 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -132,22 +132,22 @@ namespace Grpc.IntegrationTesting await channel.ShutdownAsync(); } - private async Task CreateCredentialsAsync() + private async Task 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; } diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs index 790bade89d..5325b2fa14 100644 --- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs @@ -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); -- cgit v1.2.3 From 7828e813f780d95814db67fc2aac8a3e104ac743 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 7 Oct 2015 17:27:48 -0700 Subject: make C# interop test args parsing compliant with spec --- src/csharp/Grpc.IntegrationTesting/InteropClient.cs | 12 +++++++----- src/csharp/Grpc.IntegrationTesting/InteropServer.cs | 7 ++++--- tools/run_tests/run_interop_tests.py | 6 +++--- 3 files changed, 14 insertions(+), 11 deletions(-) (limited to 'src/csharp/Grpc.IntegrationTesting/InteropClient.cs') diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 0df4ee35ba..0ed2910ae0 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -66,11 +66,13 @@ namespace Grpc.IntegrationTesting [Option("test_case", DefaultValue = "large_unary")] public string TestCase { get; set; } - [Option("use_tls")] - public bool UseTls { get; set; } + // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls) + [Option("use_tls", DefaultValue = false)] + public bool? UseTls { get; set; } - [Option("use_test_ca")] - public bool UseTestCa { get; set; } + // Deliberately using nullable bool type to allow --use_test_ca=true syntax (as opposed to --use_test_ca) + [Option("use_test_ca", DefaultValue = false)] + public bool? UseTestCa { get; set; } [Option("default_service_account", Required = false)] public string DefaultServiceAccount { get; set; } @@ -134,7 +136,7 @@ namespace Grpc.IntegrationTesting private async Task CreateCredentialsAsync() { - var credentials = options.UseTls ? TestCredentials.CreateTestClientCredentials(options.UseTestCa) : ChannelCredentials.Insecure; + var credentials = options.UseTls.Value ? TestCredentials.CreateTestClientCredentials(options.UseTestCa.Value) : ChannelCredentials.Insecure; if (options.TestCase == "jwt_token_creds") { diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs index 513f8722d6..29f842be2e 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs @@ -54,8 +54,9 @@ namespace Grpc.IntegrationTesting [Option("port", DefaultValue = 8070)] public int Port { get; set; } - [Option("use_tls")] - public bool UseTls { get; set; } + // Deliberately using nullable bool type to allow --use_tls=true syntax (as opposed to --use_tls) + [Option("use_tls", DefaultValue = false)] + public bool? UseTls { get; set; } [HelpOption] public string GetUsage() @@ -99,7 +100,7 @@ namespace Grpc.IntegrationTesting string host = "0.0.0.0"; int port = options.Port; - if (options.UseTls) + if (options.UseTls.Value) { server.Ports.Add(host, port, TestCredentials.CreateTestServerCredentials()); } diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 374dec1851..abc4b6e6fb 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -100,17 +100,17 @@ class CSharpLanguage: def cloud_to_prod_args(self): return (self.client_cmdline_base + _CLOUD_TO_PROD_BASE_ARGS + - ['--use_tls']) + ['--use_tls=true']) def cloud_to_cloud_args(self): return (self.client_cmdline_base + _CLOUD_TO_CLOUD_BASE_ARGS + - ['--use_tls', '--use_test_ca']) + ['--use_tls=true', '--use_test_ca=true']) def cloud_to_prod_env(self): return _SSL_CERT_ENV def server_args(self): - return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls'] + return ['mono', 'Grpc.IntegrationTesting.Server.exe', '--use_tls=true'] def __str__(self): return 'csharp' -- cgit v1.2.3 From 64d7c2461a525a7dacb1e8e7479d93c4ab56dfd2 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 08:02:27 -0700 Subject: make C# auth interop tests up to spec --- .../Grpc.IntegrationTesting/InteropClient.cs | 31 +++++++++++++++------- tools/run_tests/run_interop_tests.py | 4 +++ 2 files changed, 26 insertions(+), 9 deletions(-) (limited to 'src/csharp/Grpc.IntegrationTesting/InteropClient.cs') diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 0ed2910ae0..888b5c312f 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -46,6 +46,7 @@ using Grpc.Auth; using Grpc.Core; using Grpc.Core.Utils; using Grpc.Testing; +using Newtonsoft.Json.Linq; using NUnit.Framework; namespace Grpc.IntegrationTesting @@ -180,13 +181,13 @@ namespace Grpc.IntegrationTesting RunComputeEngineCreds(client, options.DefaultServiceAccount, options.OAuthScope); break; case "jwt_token_creds": - RunJwtTokenCreds(client, options.DefaultServiceAccount); + RunJwtTokenCreds(client); break; case "oauth2_auth_token": - await RunOAuth2AuthTokenAsync(client, options.DefaultServiceAccount, options.OAuthScope); + await RunOAuth2AuthTokenAsync(client, options.OAuthScope); break; case "per_rpc_creds": - await RunPerRpcCredsAsync(client, options.DefaultServiceAccount, options.OAuthScope); + await RunPerRpcCredsAsync(client, options.OAuthScope); break; case "cancel_after_begin": await RunCancelAfterBeginAsync(client); @@ -364,7 +365,7 @@ namespace Grpc.IntegrationTesting Console.WriteLine("Passed!"); } - public static void RunJwtTokenCreds(TestService.TestServiceClient client, string defaultServiceAccount) + public static void RunJwtTokenCreds(TestService.TestServiceClient client) { Console.WriteLine("running jwt_token_creds"); @@ -381,11 +382,11 @@ namespace Grpc.IntegrationTesting Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type); Assert.AreEqual(314159, response.Payload.Body.Length); - Assert.AreEqual(defaultServiceAccount, response.Username); + Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); Console.WriteLine("Passed!"); } - public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) + public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient client, string oauthScope) { Console.WriteLine("running oauth2_auth_token"); ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); @@ -402,11 +403,11 @@ namespace Grpc.IntegrationTesting Assert.False(string.IsNullOrEmpty(response.OauthScope)); Assert.True(oauthScope.Contains(response.OauthScope)); - Assert.AreEqual(defaultServiceAccount, response.Username); + Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); Console.WriteLine("Passed!"); } - public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string defaultServiceAccount, string oauthScope) + public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope) { Console.WriteLine("running per_rpc_creds"); ITokenAccess googleCredential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); @@ -419,7 +420,7 @@ namespace Grpc.IntegrationTesting var response = client.UnaryCall(request, new CallOptions(credentials: credentials)); - Assert.AreEqual(defaultServiceAccount, response.Username); + Assert.AreEqual(GetEmailFromServiceAccountFile(), response.Username); Console.WriteLine("Passed!"); } @@ -499,5 +500,17 @@ namespace Grpc.IntegrationTesting { return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; } + + // extracts the client_email field from service account file used for auth test cases + private static string GetEmailFromServiceAccountFile() + { + string keyFile = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"); + Assert.IsNotNull(keyFile); + + var jobject = JObject.Parse(File.ReadAllText(keyFile)); + string email = jobject.GetValue("client_email").Value(); + Assert.IsTrue(email.Length > 0); // spec requires nonempty client email. + return email; + } } } diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 45efa572f9..c1b4cf8a12 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -312,6 +312,10 @@ def add_auth_options(language, test_case, cmdline, env): if test_case in ['per_rpc_creds', 'oauth2_auth_token']: cmdline += [oauth_scope_arg] + if test_case == 'oauth2_auth_token' and language == 'c++': + # C++ oauth2 test uses GCE creds and thus needs to know the default account + cmdline += [default_account_arg] + if test_case == 'compute_engine_creds': cmdline += [oauth_scope_arg, default_account_arg] -- cgit v1.2.3 From cf72a3adfe8ab55775d8e0d648fb62f8b4e58f1d Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 08:44:20 -0700 Subject: use JWT credentials for per_rpc_creds --- src/csharp/Grpc.IntegrationTesting/InteropClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/csharp/Grpc.IntegrationTesting/InteropClient.cs') diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 888b5c312f..cb50b44841 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -410,7 +410,7 @@ namespace Grpc.IntegrationTesting public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient client, string oauthScope) { Console.WriteLine("running per_rpc_creds"); - ITokenAccess googleCredential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); + ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); var credentials = GrpcCredentials.Create(googleCredential); var request = new SimpleRequest -- cgit v1.2.3