From 18729a05e59c93eb258eb0a72cf2af4c22b28041 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 8 Oct 2015 18:40:00 -0700 Subject: [PATCH] Polishing of C# auth API --- ...erceptors.cs => GoogleAuthInterceptors.cs} | 6 +- ...redentials.cs => GoogleGrpcCredentials.cs} | 57 ++++++++++--------- src/csharp/Grpc.Auth/Grpc.Auth.csproj | 4 +- .../Grpc.Core.Tests/CallCredentialsTest.cs | 4 +- .../Grpc.Core.Tests/ChannelCredentialsTest.cs | 6 -- src/csharp/Grpc.Core/CallCredentials.cs | 30 ++++++---- src/csharp/Grpc.Core/ChannelCredentials.cs | 33 ----------- .../Grpc.IntegrationTesting/InteropClient.cs | 8 +-- .../MetadataCredentialsTest.cs | 2 +- 9 files changed, 62 insertions(+), 88 deletions(-) rename src/csharp/Grpc.Auth/{AuthInterceptors.cs => GoogleAuthInterceptors.cs} (95%) rename src/csharp/Grpc.Auth/{GrpcCredentials.cs => GoogleGrpcCredentials.cs} (52%) diff --git a/src/csharp/Grpc.Auth/AuthInterceptors.cs b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs similarity index 95% rename from src/csharp/Grpc.Auth/AuthInterceptors.cs rename to src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs index fa925667751..1c14c5bb5b4 100644 --- a/src/csharp/Grpc.Auth/AuthInterceptors.cs +++ b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs @@ -41,10 +41,10 @@ using Grpc.Core.Utils; namespace Grpc.Auth { /// - /// Factory methods to create authorization interceptors. - /// + /// Factory methods to create authorization interceptors for Google credentials. + /// /// - public static class AuthInterceptors + public static class GoogleAuthInterceptors { private const string AuthorizationHeader = "Authorization"; private const string Schema = "Bearer"; diff --git a/src/csharp/Grpc.Auth/GrpcCredentials.cs b/src/csharp/Grpc.Auth/GoogleGrpcCredentials.cs similarity index 52% rename from src/csharp/Grpc.Auth/GrpcCredentials.cs rename to src/csharp/Grpc.Auth/GoogleGrpcCredentials.cs index d8b10804c6e..a1e7db13bdf 100644 --- a/src/csharp/Grpc.Auth/GrpcCredentials.cs +++ b/src/csharp/Grpc.Auth/GoogleGrpcCredentials.cs @@ -33,6 +33,7 @@ using System; using System.Threading; +using System.Threading.Tasks; using Google.Apis.Auth.OAuth2; using Grpc.Core; @@ -41,53 +42,55 @@ using Grpc.Core.Utils; namespace Grpc.Auth { /// - /// Factory methods to create instances of and classes. + /// Factory/extension methods to create instances of and classes + /// based on credential objects originating from Google auth library. /// - public static class GrpcCredentials + public static class GoogleGrpcCredentials { /// - /// Creates a instance that will obtain access tokens - /// from any credential that implements ITokenAccess. (e.g. GoogleCredential). + /// Retrieves an instance of Google's Application Default Credentials using + /// GoogleCredential.GetApplicationDefaultAsync() and converts them + /// into a gRPC that use the default SSL credentials. /// - /// The credential to use to obtain access tokens. - /// The MetadataCredentials instance. - public static MetadataCredentials Create(ITokenAccess credential) + /// The ChannelCredentials instance. + public static async Task GetApplicationDefaultAsync() { - return new MetadataCredentials(AuthInterceptors.FromCredential(credential)); + var googleCredential = await GoogleCredential.GetApplicationDefaultAsync().ConfigureAwait(false); + return googleCredential.ToChannelCredentials(); } /// - /// Convenience method to create a instance from - /// ITokenAccess credential and SslCredentials instance. + /// Creates an instance of that will use given access token to authenticate + /// with a gRPC service. /// - /// The credential to use to obtain access tokens. - /// The SslCredentials instance. - /// The channel credentials for access token based auth over a secure channel. - public static ChannelCredentials Create(ITokenAccess credential, SslCredentials sslCredentials) + /// OAuth2 access token. + /// /// The MetadataCredentials instance. + public static CallCredentials FromAccessToken(string accessToken) { - return ChannelCredentials.Create(sslCredentials, Create(credential)); + return CallCredentials.FromInterceptor(GoogleAuthInterceptors.FromAccessToken(accessToken)); } /// - /// Creates an instance of that will use given access token to authenticate - /// with a gRPC service. + /// Converts a ITokenAccess (e.g. GoogleCredential) object + /// into a gRPC object. /// - /// OAuth2 access token. - /// /// The MetadataCredentials instance. - public static MetadataCredentials FromAccessToken(string accessToken) + /// The credential to use to obtain access tokens. + /// The CallCredentials instance. + public static CallCredentials ToCallCredentials(this ITokenAccess credential) { - return new MetadataCredentials(AuthInterceptors.FromAccessToken(accessToken)); + return CallCredentials.FromInterceptor(GoogleAuthInterceptors.FromCredential(credential)); } /// - /// Converts a ITokenAccess object into a object supported - /// by gRPC. + /// Converts a ITokenAccess (e.g. GoogleCredential) object + /// into a gRPC object. + /// Default SSL credentials are used. /// - /// - /// - public static MetadataCredentials ToGrpcCredentials(this ITokenAccess credential) + /// The credential to use to obtain access tokens. + /// >The ChannelCredentials instance. + public static ChannelCredentials ToChannelCredentials(this ITokenAccess googleCredential) { - return GrpcCredentials.Create(credential); + return ChannelCredentials.Create(new SslCredentials(), googleCredential.ToCallCredentials()); } } } diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj index 80ab07d2ae5..55bde6e1942 100644 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -78,9 +78,9 @@ Version.cs - + - + diff --git a/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs index 451963229a4..82f881969eb 100644 --- a/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs +++ b/src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs @@ -55,8 +55,8 @@ namespace Grpc.Core.Tests 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); })); + CallCredentials.FromInterceptor(async (uri, m) => { await Task.Delay(1); }), + CallCredentials.FromInterceptor(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 index 489bf385756..d5315ed39b4 100644 --- a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs +++ b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs @@ -63,11 +63,5 @@ namespace Grpc.Core.Tests // 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/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs index 809c9f412d0..400a9825de2 100644 --- a/src/csharp/Grpc.Core/CallCredentials.cs +++ b/src/csharp/Grpc.Core/CallCredentials.cs @@ -40,6 +40,14 @@ using Grpc.Core.Utils; namespace Grpc.Core { + /// + /// 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 call credentials. Provide authorization with per-call granularity. /// @@ -56,6 +64,16 @@ namespace Grpc.Core return new CompositeCallCredentials(credentials); } + /// + /// Creates a new instance of CallCredentials class from an + /// interceptor that can attach metadata to outgoing calls. + /// + /// authentication interceptor + public static CallCredentials FromInterceptor(AsyncAuthInterceptor interceptor) + { + return new MetadataCredentials(interceptor); + } + /// /// Creates native object for the credentials. /// @@ -63,19 +81,11 @@ namespace Grpc.Core 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 + internal sealed class MetadataCredentials : CallCredentials { readonly AsyncAuthInterceptor interceptor; @@ -85,7 +95,7 @@ namespace Grpc.Core /// authentication interceptor public MetadataCredentials(AsyncAuthInterceptor interceptor) { - this.interceptor = interceptor; + this.interceptor = Preconditions.CheckNotNull(interceptor); } internal override CredentialsSafeHandle ToNativeCredentials() diff --git a/src/csharp/Grpc.Core/ChannelCredentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs index 599674e02bd..9d2bcdabe84 100644 --- a/src/csharp/Grpc.Core/ChannelCredentials.cs +++ b/src/csharp/Grpc.Core/ChannelCredentials.cs @@ -71,17 +71,6 @@ namespace Grpc.Core 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. @@ -213,26 +202,4 @@ namespace Grpc.Core } } } - - /// - /// 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.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index cb50b44841f..030a098cad3 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -143,14 +143,14 @@ namespace Grpc.IntegrationTesting { var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); Assert.IsTrue(googleCredential.IsCreateScopedRequired); - credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials()); + credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); } if (options.TestCase == "compute_engine_creds") { var googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); Assert.IsFalse(googleCredential.IsCreateScopedRequired); - credentials = ChannelCredentials.Create(credentials, googleCredential.ToGrpcCredentials()); + credentials = ChannelCredentials.Create(credentials, googleCredential.ToCallCredentials()); } return credentials; } @@ -392,7 +392,7 @@ namespace Grpc.IntegrationTesting ITokenAccess credential = (await GoogleCredential.GetApplicationDefaultAsync()).CreateScoped(new[] { oauthScope }); string oauth2Token = await credential.GetAccessTokenForRequestAsync(); - var credentials = GrpcCredentials.FromAccessToken(oauth2Token); + var credentials = GoogleGrpcCredentials.FromAccessToken(oauth2Token); var request = new SimpleRequest { FillUsername = true, @@ -412,7 +412,7 @@ namespace Grpc.IntegrationTesting Console.WriteLine("running per_rpc_creds"); ITokenAccess googleCredential = await GoogleCredential.GetApplicationDefaultAsync(); - var credentials = GrpcCredentials.Create(googleCredential); + var credentials = googleCredential.ToCallCredentials(); var request = new SimpleRequest { FillUsername = true, diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs index 5325b2fa148..3d56678b990 100644 --- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs @@ -75,7 +75,7 @@ namespace Grpc.IntegrationTesting var clientCredentials = ChannelCredentials.Create( new SslCredentials(File.ReadAllText(TestCredentials.ClientCertAuthorityPath)), - new MetadataCredentials(asyncAuthInterceptor)); + CallCredentials.FromInterceptor(asyncAuthInterceptor)); channel = new Channel(Host, server.Ports.Single().BoundPort, clientCredentials, options); client = TestService.NewClient(channel); }