Skip to content

Commit

Permalink
Merge pull request grpc#3756 from jtattermusch/adjust_csharp_auth_api
Browse files Browse the repository at this point in the history
Improving the C# auth API
  • Loading branch information
jtattermusch committed Oct 13, 2015
2 parents 93cec49 + 18729a0 commit d86742f
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@
namespace Grpc.Auth
{
/// <summary>
/// Factory methods to create authorization interceptors.
/// <seealso cref="GrpcCredentials"/>
/// Factory methods to create authorization interceptors for Google credentials.
/// <seealso cref="GoogleGrpcCredentials"/>
/// </summary>
public static class AuthInterceptors
public static class GoogleAuthInterceptors
{
private const string AuthorizationHeader = "Authorization";
private const string Schema = "Bearer";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

using System;
using System.Threading;
using System.Threading.Tasks;

using Google.Apis.Auth.OAuth2;
using Grpc.Core;
Expand All @@ -41,53 +42,55 @@
namespace Grpc.Auth
{
/// <summary>
/// Factory methods to create instances of <see cref="ChannelCredentials"/> and <see cref="CallCredentials"/> classes.
/// Factory/extension methods to create instances of <see cref="ChannelCredentials"/> and <see cref="CallCredentials"/> classes
/// based on credential objects originating from Google auth library.
/// </summary>
public static class GrpcCredentials
public static class GoogleGrpcCredentials
{
/// <summary>
/// Creates a <see cref="MetadataCredentials"/> instance that will obtain access tokens
/// from any credential that implements <c>ITokenAccess</c>. (e.g. <c>GoogleCredential</c>).
/// Retrieves an instance of Google's Application Default Credentials using
/// <c>GoogleCredential.GetApplicationDefaultAsync()</c> and converts them
/// into a gRPC <see cref="ChannelCredentials"/> that use the default SSL credentials.
/// </summary>
/// <param name="credential">The credential to use to obtain access tokens.</param>
/// <returns>The <c>MetadataCredentials</c> instance.</returns>
public static MetadataCredentials Create(ITokenAccess credential)
/// <returns>The <c>ChannelCredentials</c> instance.</returns>
public static async Task<ChannelCredentials> GetApplicationDefaultAsync()
{
return new MetadataCredentials(AuthInterceptors.FromCredential(credential));
var googleCredential = await GoogleCredential.GetApplicationDefaultAsync().ConfigureAwait(false);
return googleCredential.ToChannelCredentials();
}

/// <summary>
/// Convenience method to create a <see cref="ChannelCredentials"/> instance from
/// <c>ITokenAccess</c> credential and <c>SslCredentials</c> instance.
/// Creates an instance of <see cref="CallCredentials"/> that will use given access token to authenticate
/// with a gRPC service.
/// </summary>
/// <param name="credential">The credential to use to obtain access tokens.</param>
/// <param name="sslCredentials">The <c>SslCredentials</c> instance.</param>
/// <returns>The channel credentials for access token based auth over a secure channel.</returns>
public static ChannelCredentials Create(ITokenAccess credential, SslCredentials sslCredentials)
/// <param name="accessToken">OAuth2 access token.</param>
/// /// <returns>The <c>MetadataCredentials</c> instance.</returns>
public static CallCredentials FromAccessToken(string accessToken)
{
return ChannelCredentials.Create(sslCredentials, Create(credential));
return CallCredentials.FromInterceptor(GoogleAuthInterceptors.FromAccessToken(accessToken));
}

/// <summary>
/// Creates an instance of <see cref="MetadataCredentials"/> that will use given access token to authenticate
/// with a gRPC service.
/// Converts a <c>ITokenAccess</c> (e.g. <c>GoogleCredential</c>) object
/// into a gRPC <see cref="CallCredentials"/> object.
/// </summary>
/// <param name="accessToken">OAuth2 access token.</param>
/// /// <returns>The <c>MetadataCredentials</c> instance.</returns>
public static MetadataCredentials FromAccessToken(string accessToken)
/// <param name="credential">The credential to use to obtain access tokens.</param>
/// <returns>The <c>CallCredentials</c> instance.</returns>
public static CallCredentials ToCallCredentials(this ITokenAccess credential)
{
return new MetadataCredentials(AuthInterceptors.FromAccessToken(accessToken));
return CallCredentials.FromInterceptor(GoogleAuthInterceptors.FromCredential(credential));
}

/// <summary>
/// Converts a <c>ITokenAccess</c> object into a <see cref="MetadataCredentials"/> object supported
/// by gRPC.
/// Converts a <c>ITokenAccess</c> (e.g. <c>GoogleCredential</c>) object
/// into a gRPC <see cref="ChannelCredentials"/> object.
/// Default SSL credentials are used.
/// </summary>
/// <param name="credential"></param>
/// <returns></returns>
public static MetadataCredentials ToGrpcCredentials(this ITokenAccess credential)
/// <param name="googleCredential">The credential to use to obtain access tokens.</param>
/// <returns>>The <c>ChannelCredentials</c> instance.</returns>
public static ChannelCredentials ToChannelCredentials(this ITokenAccess googleCredential)
{
return GrpcCredentials.Create(credential);
return ChannelCredentials.Create(new SslCredentials(), googleCredential.ToCallCredentials());
}
}
}
4 changes: 2 additions & 2 deletions src/csharp/Grpc.Auth/Grpc.Auth.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@
<Compile Include="..\Grpc.Core\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="GrpcCredentials.cs" />
<Compile Include="GoogleGrpcCredentials.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="AuthInterceptors.cs" />
<Compile Include="GoogleAuthInterceptors.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/csharp/Grpc.Core.Tests/CallCredentialsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ public void CallCredentials_ComposeAtLeastTwo()
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())
{
}
Expand Down
6 changes: 0 additions & 6 deletions src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,5 @@ public void ChannelCredentials_CreateComposite()
// forbid composing non-composable
Assert.Throws(typeof(ArgumentException), () => ChannelCredentials.Create(new FakeChannelCredentials(false), new FakeCallCredentials()));
}

[Test]
public void ChannelCredentials_CreateWrapped()
{
ChannelCredentials.Create(new FakeCallCredentials());
}
}
}
30 changes: 20 additions & 10 deletions src/csharp/Grpc.Core/CallCredentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@

namespace Grpc.Core
{
/// <summary>
/// Asynchronous authentication interceptor for <see cref="CallCredentials"/>.
/// </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 call credentials. Provide authorization with per-call granularity.
/// </summary>
Expand All @@ -56,26 +64,28 @@ public static CallCredentials Compose(params CallCredentials[] credentials)
return new CompositeCallCredentials(credentials);
}

/// <summary>
/// Creates a new instance of <c>CallCredentials</c> class from an
/// interceptor that can attach metadata to outgoing calls.
/// </summary>
/// <param name="interceptor">authentication interceptor</param>
public static CallCredentials FromInterceptor(AsyncAuthInterceptor interceptor)
{
return new MetadataCredentials(interceptor);
}

/// <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
internal sealed class MetadataCredentials : CallCredentials
{
readonly AsyncAuthInterceptor interceptor;

Expand All @@ -85,7 +95,7 @@ public class MetadataCredentials : CallCredentials
/// <param name="interceptor">authentication interceptor</param>
public MetadataCredentials(AsyncAuthInterceptor interceptor)
{
this.interceptor = interceptor;
this.interceptor = Preconditions.CheckNotNull(interceptor);
}

internal override CredentialsSafeHandle ToNativeCredentials()
Expand Down
33 changes: 0 additions & 33 deletions src/csharp/Grpc.Core/ChannelCredentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,6 @@ public static ChannelCredentials Create(ChannelCredentials channelCredentials, C
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.
Expand Down Expand Up @@ -213,26 +202,4 @@ internal override CredentialsSafeHandle ToNativeCredentials()
}
}
}

/// <summary>
/// Credentials wrapping <see cref="CallCredentials"/> as <see cref="ChannelCredentials"/>.
/// </summary>
internal sealed class WrappedCallCredentials : ChannelCredentials
{
readonly CallCredentials callCredentials;

/// <summary>
/// Wraps instance of <c>CallCredentials</c> as <c>ChannelCredentials</c>.
/// </summary>
/// <param name="callCredentials">credentials to wrap</param>
public WrappedCallCredentials(CallCredentials callCredentials)
{
this.callCredentials = Preconditions.CheckNotNull(callCredentials);
}

internal override CredentialsSafeHandle ToNativeCredentials()
{
return callCredentials.ToNativeCredentials();
}
}
}
8 changes: 4 additions & 4 deletions src/csharp/Grpc.IntegrationTesting/InteropClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,14 @@ private async Task<ChannelCredentials> CreateCredentialsAsync()
{
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;
}
Expand Down Expand Up @@ -392,7 +392,7 @@ public static async Task RunOAuth2AuthTokenAsync(TestService.TestServiceClient c
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,
Expand All @@ -412,7 +412,7 @@ public static async Task RunPerRpcCredsAsync(TestService.TestServiceClient clien
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void Init()

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);
}
Expand Down

0 comments on commit d86742f

Please sign in to comment.