introduce auth interceptor context

pull/4260/head
Jan Tattermusch 9 years ago
parent 3e5cbee777
commit 189fcf8686
  1. 6
      src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs
  2. 84
      src/csharp/Grpc.Core/AsyncAuthInterceptor.cs
  3. 8
      src/csharp/Grpc.Core/CallCredentials.cs
  4. 5
      src/csharp/Grpc.Core/Grpc.Core.csproj
  5. 13
      src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
  6. 2
      src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs
  7. 7
      src/csharp/ext/grpc_csharp_ext.c

@ -57,9 +57,9 @@ namespace Grpc.Auth
/// <returns>The interceptor.</returns> /// <returns>The interceptor.</returns>
public static AsyncAuthInterceptor FromCredential(ITokenAccess credential) public static AsyncAuthInterceptor FromCredential(ITokenAccess credential)
{ {
return new AsyncAuthInterceptor(async (authUri, metadata) => return new AsyncAuthInterceptor(async (context, metadata) =>
{ {
var accessToken = await credential.GetAccessTokenForRequestAsync(authUri, CancellationToken.None).ConfigureAwait(false); var accessToken = await credential.GetAccessTokenForRequestAsync(context.ServiceUrl, CancellationToken.None).ConfigureAwait(false);
metadata.Add(CreateBearerTokenHeader(accessToken)); metadata.Add(CreateBearerTokenHeader(accessToken));
}); });
} }
@ -72,7 +72,7 @@ namespace Grpc.Auth
public static AsyncAuthInterceptor FromAccessToken(string accessToken) public static AsyncAuthInterceptor FromAccessToken(string accessToken)
{ {
Preconditions.CheckNotNull(accessToken); Preconditions.CheckNotNull(accessToken);
return new AsyncAuthInterceptor(async (authUri, metadata) => return new AsyncAuthInterceptor(async (context, metadata) =>
{ {
metadata.Add(CreateBearerTokenHeader(accessToken)); metadata.Add(CreateBearerTokenHeader(accessToken));
}); });

@ -0,0 +1,84 @@
#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>
/// Asynchronous authentication interceptor for <see cref="CallCredentials"/>.
/// </summary>
/// <param name="context">The interceptor context.</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(AuthInterceptorContext context, Metadata metadata);
/// <summary>
/// Context for an RPC being intercepted by <see cref="AsyncAuthInterceptor"/>.
/// </summary>
public class AuthInterceptorContext
{
readonly string serviceUrl;
readonly string methodName;
/// <summary>
/// Initializes a new instance of <c>AuthInterceptorContext</c>.
/// </summary>
public AuthInterceptorContext(string serviceUrl, string methodName)
{
this.serviceUrl = Preconditions.CheckNotNull(serviceUrl);
this.methodName = Preconditions.CheckNotNull(methodName);
}
/// <summary>
/// The fully qualified service URL for the RPC being called.
/// </summary>
public string ServiceUrl
{
get { return serviceUrl; }
}
/// <summary>
/// The method name of the RPC being called.
/// </summary>
public string MethodName
{
get { return methodName; }
}
}
}

@ -40,14 +40,6 @@ using Grpc.Core.Utils;
namespace Grpc.Core 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> /// <summary>
/// Client-side call credentials. Provide authorization with per-call granularity. /// Client-side call credentials. Provide authorization with per-call granularity.
/// </summary> /// </summary>

@ -48,6 +48,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="AsyncDuplexStreamingCall.cs" /> <Compile Include="AsyncDuplexStreamingCall.cs" />
<Compile Include="AsyncServerStreamingCall.cs" /> <Compile Include="AsyncServerStreamingCall.cs" />
<Compile Include="AsyncAuthInterceptor.cs" />
<Compile Include="CallCredentials.cs" /> <Compile Include="CallCredentials.cs" />
<Compile Include="IClientStreamWriter.cs" /> <Compile Include="IClientStreamWriter.cs" />
<Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" /> <Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" />
@ -155,7 +156,5 @@
<Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" /> <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
<Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" /> <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
<ItemGroup /> <ItemGroup />
<ItemGroup> <ItemGroup />
<Folder Include="Profiling\" />
</ItemGroup>
</Project> </Project>

@ -38,7 +38,7 @@ using Grpc.Core.Utils;
namespace Grpc.Core.Internal namespace Grpc.Core.Internal
{ {
internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy); internal delegate void NativeMetadataInterceptor(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy);
internal class NativeMetadataCredentialsPlugin internal class NativeMetadataCredentialsPlugin
{ {
@ -71,7 +71,7 @@ namespace Grpc.Core.Internal
get { return credentials; } get { return credentials; }
} }
private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy) private void NativeMetadataInterceptorHandler(IntPtr statePtr, IntPtr serviceUrlPtr, IntPtr methodNamePtr, IntPtr callbackPtr, IntPtr userDataPtr, bool isDestroy)
{ {
if (isDestroy) if (isDestroy)
{ {
@ -81,8 +81,9 @@ namespace Grpc.Core.Internal
try try
{ {
string serviceUrl = Marshal.PtrToStringAnsi(serviceUrlPtr); var context = new AuthInterceptorContext(Marshal.PtrToStringAnsi(serviceUrlPtr),
StartGetMetadata(serviceUrl, callbackPtr, userDataPtr); Marshal.PtrToStringAnsi(methodNamePtr));
StartGetMetadata(context, callbackPtr, userDataPtr);
} }
catch (Exception e) catch (Exception e)
{ {
@ -91,12 +92,12 @@ namespace Grpc.Core.Internal
} }
} }
private async void StartGetMetadata(string serviceUrl, IntPtr callbackPtr, IntPtr userDataPtr) private async void StartGetMetadata(AuthInterceptorContext context, IntPtr callbackPtr, IntPtr userDataPtr)
{ {
try try
{ {
var metadata = new Metadata(); var metadata = new Metadata();
await interceptor(serviceUrl, metadata); await interceptor(context, metadata);
using (var metadataArray = MetadataArraySafeHandle.Create(metadata)) using (var metadataArray = MetadataArraySafeHandle.Create(metadata))
{ {

@ -67,7 +67,7 @@ namespace Grpc.IntegrationTesting
new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride) new ChannelOption(ChannelOptions.SslTargetNameOverride, TestCredentials.DefaultHostOverride)
}; };
var asyncAuthInterceptor = new AsyncAuthInterceptor(async (authUri, metadata) => var asyncAuthInterceptor = new AsyncAuthInterceptor(async (context, metadata) =>
{ {
await Task.Delay(100); // make sure the operation is asynchronous. await Task.Delay(100); // make sure the operation is asynchronous.
metadata.Add("authorization", "SECRET_TOKEN"); metadata.Add("authorization", "SECRET_TOKEN");

@ -927,7 +927,8 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
} }
typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)( typedef void(GPR_CALLTYPE *grpcsharp_metadata_interceptor_func)(
void *state, const char *service_url, grpc_credentials_plugin_metadata_cb cb, void *state, const char *service_url, const char *method_name,
grpc_credentials_plugin_metadata_cb cb,
void *user_data, gpr_int32 is_destroy); void *user_data, gpr_int32 is_destroy);
static void grpcsharp_get_metadata_handler( static void grpcsharp_get_metadata_handler(
@ -935,13 +936,13 @@ static void grpcsharp_get_metadata_handler(
grpc_credentials_plugin_metadata_cb cb, void *user_data) { grpc_credentials_plugin_metadata_cb cb, void *user_data) {
grpcsharp_metadata_interceptor_func interceptor = grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(gpr_intptr)state; (grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
interceptor(state, context.service_url, cb, user_data, 0); interceptor(state, context.service_url, context.method_name, cb, user_data, 0);
} }
static void grpcsharp_metadata_credentials_destroy_handler(void *state) { static void grpcsharp_metadata_credentials_destroy_handler(void *state) {
grpcsharp_metadata_interceptor_func interceptor = grpcsharp_metadata_interceptor_func interceptor =
(grpcsharp_metadata_interceptor_func)(gpr_intptr)state; (grpcsharp_metadata_interceptor_func)(gpr_intptr)state;
interceptor(state, NULL, NULL, NULL, 1); interceptor(state, NULL, NULL, NULL, NULL, 1);
} }
GPR_EXPORT grpc_call_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin( GPR_EXPORT grpc_call_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin(

Loading…
Cancel
Save