diff --git a/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs index 1c14c5bb5b44634c76cf40915bd1928becd04670..f77e9c6573d824857f501d41e49d995c40756216 100644 --- a/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs +++ b/src/csharp/Grpc.Auth/GoogleAuthInterceptors.cs @@ -57,9 +57,9 @@ namespace Grpc.Auth /// <returns>The interceptor.</returns> 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)); }); } @@ -72,7 +72,7 @@ namespace Grpc.Auth public static AsyncAuthInterceptor FromAccessToken(string accessToken) { Preconditions.CheckNotNull(accessToken); - return new AsyncAuthInterceptor(async (authUri, metadata) => + return new AsyncAuthInterceptor(async (context, metadata) => { metadata.Add(CreateBearerTokenHeader(accessToken)); }); diff --git a/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs b/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs new file mode 100644 index 0000000000000000000000000000000000000000..5c9ab048120b6d0b5346cb54de515620c87d7b32 --- /dev/null +++ b/src/csharp/Grpc.Core/AsyncAuthInterceptor.cs @@ -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; } + } + } +} diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs index 5ea179dfea152353b051902c03dde16cc2c477da..a71c8904fe76aeca8f8eae751f90a7b22b7eaafe 100644 --- a/src/csharp/Grpc.Core/CallCredentials.cs +++ b/src/csharp/Grpc.Core/CallCredentials.cs @@ -40,14 +40,6 @@ using Grpc.Core.Utils; 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> diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 56a06f4a9bbd1db529a7a5cdcf54330c5ba8f60a..5b3da7c6c9948b4853a56e21e79333c882325344 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -46,6 +46,7 @@ <ItemGroup> <Compile Include="AsyncDuplexStreamingCall.cs" /> <Compile Include="AsyncServerStreamingCall.cs" /> + <Compile Include="AsyncAuthInterceptor.cs" /> <Compile Include="CallCredentials.cs" /> <Compile Include="IClientStreamWriter.cs" /> <Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" /> @@ -148,8 +149,8 @@ <Error Condition="!Exists('..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets'))" /> <Error Condition="!Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets'))" /> </Target> - <ItemGroup /> - <ItemGroup /> <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.openssl.redist.targets')" /> <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\portable-net45+netcore45+wpa81+wp8\grpc.dependencies.zlib.redist.targets')" /> -</Project> \ No newline at end of file + <ItemGroup /> + <ItemGroup /> +</Project> diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs index 4c086048d265125aaa14c81d18ee6806d280f914..8bb646d303cd025c328b547f8d1b92574360162f 100644 --- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs +++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs @@ -38,7 +38,7 @@ using Grpc.Core.Utils; 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 { @@ -71,7 +71,7 @@ namespace Grpc.Core.Internal 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) { @@ -81,8 +81,9 @@ namespace Grpc.Core.Internal try { - string serviceUrl = Marshal.PtrToStringAnsi(serviceUrlPtr); - StartGetMetadata(serviceUrl, callbackPtr, userDataPtr); + var context = new AuthInterceptorContext(Marshal.PtrToStringAnsi(serviceUrlPtr), + Marshal.PtrToStringAnsi(methodNamePtr)); + StartGetMetadata(context, callbackPtr, userDataPtr); } 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 { var metadata = new Metadata(); - await interceptor(serviceUrl, metadata).ConfigureAwait(false); + await interceptor(context, metadata).ConfigureAwait(false); using (var metadataArray = MetadataArraySafeHandle.Create(metadata)) { diff --git a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs index 3d56678b990cc9ea7885171250b66d4301e5855e..35230f48c1785c2da03e3326d366f062ae043e92 100644 --- a/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/MetadataCredentialsTest.cs @@ -67,7 +67,7 @@ namespace Grpc.IntegrationTesting 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. metadata.Add("authorization", "SECRET_TOKEN"); diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index b8705c49d320db1c046a590cce9383a4dc5cc00f..0ef9be33a6c989a946d174e8af3ef44dfd46c118 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -927,7 +927,8 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin( } 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); 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) { grpcsharp_metadata_interceptor_func interceptor = (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) { grpcsharp_metadata_interceptor_func interceptor = (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( diff --git a/src/python/grpcio/tests/_loader.py b/src/python/grpcio/tests/_loader.py index 14b22b08460edbc562dd541f855beac7b6d09a68..6992029b5e801c0bedf17c89f30c7a6b7c56d054 100644 --- a/src/python/grpcio/tests/_loader.py +++ b/src/python/grpcio/tests/_loader.py @@ -34,14 +34,6 @@ import unittest import coverage -# Some global spooky-action-at-a-distance hackery to get around -# system-installation issues where the google namespace is defaulted to the -# system even though the egg is higher priority on sys.path. This inverts the -# path priority on package module paths thus giving any installed eggs higher -# priority and having little effect otherwise. -import google -google.__path__.reverse() - TEST_MODULE_REGEX = r'^.*_test$' diff --git a/src/python/grpcio/tox.ini b/src/python/grpcio/tox.ini index 0e3cae7861bd176c1070fc722d503e862c0c4731..bfb1ca0cfada221126fd49fdf7b560d9d5cded8b 100644 --- a/src/python/grpcio/tox.ini +++ b/src/python/grpcio/tox.ini @@ -15,8 +15,5 @@ commands = coverage html --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py' coverage report --include='grpc/*' --omit='grpc/framework/alpha/*','grpc/early_adopter/*','grpc/framework/base/*','grpc/framework/face/*','grpc/_adapter/fore.py','grpc/_adapter/rear.py' deps = - cython - coverage - oauth2client - protobuf + -rrequirements.txt passenv = * diff --git a/tools/jenkins/grpc_interop_python/Dockerfile b/tools/jenkins/grpc_interop_python/Dockerfile index 5850f5f321e0794c75ae0c52e0f2865b5d980545..6034cbf95504719cc3fc9649d48902cd5cc51859 100644 --- a/tools/jenkins/grpc_interop_python/Dockerfile +++ b/tools/jenkins/grpc_interop_python/Dockerfile @@ -75,6 +75,7 @@ RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ # Install Python requisites RUN /bin/bash -l -c "pip install --upgrade pip" RUN /bin/bash -l -c "pip install virtualenv" +RUN /bin/bash -l -c "pip install tox" # Define the default command. CMD ["bash"] diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh index 7db14ce9d127444917ea670dea41a5488735671b..57080ce9348dce69599b1b3372f2e340d6a2261b 100755 --- a/tools/run_tests/build_python.sh +++ b/tools/run_tests/build_python.sh @@ -45,3 +45,5 @@ export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1 cd $GRPCIO tox --notest + +$GRPCIO/.tox/py27/bin/python $GRPCIO/setup.py build diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 36b2dc069620d55ae231217452c232b7920fe763..37b631bd0da96dc49f20632b056b14c9abfb6b35 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -266,7 +266,7 @@ class PythonLanguage: def client_cmd(self, args): return [ - 'python2.7_virtual_environment/bin/python', + 'src/python/grpcio/.tox/py27/bin/python', 'src/python/grpcio/setup.py', 'run_interop', '--client', @@ -278,7 +278,7 @@ class PythonLanguage: def server_cmd(self, args): return [ - 'python2.7_virtual_environment/bin/python', + 'src/python/grpcio/.tox/py27/bin/python', 'src/python/grpcio/setup.py', 'run_interop', '--server',