From 64d7c2461a525a7dacb1e8e7479d93c4ab56dfd2 Mon Sep 17 00:00:00 2001
From: Jan Tattermusch <jtattermusch@google.com>
Date: Thu, 8 Oct 2015 08:02:27 -0700
Subject: [PATCH 1/3] 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(-)

diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 0ed2910ae02..888b5c312fe 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<string>();
+            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 45efa572f95..c1b4cf8a12b 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]
 

From 9d8a65218f440c27b42d389053b0107b45065cbd Mon Sep 17 00:00:00 2001
From: Jan Tattermusch <jtattermusch@google.com>
Date: Thu, 8 Oct 2015 08:43:42 -0700
Subject: [PATCH 2/3] prevent ArgumentNullException in credentials plugin

---
 .../Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs    | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
index 6662a73b17a..f76492cba4a 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -86,7 +86,7 @@ namespace Grpc.Core.Internal
             }
             catch (Exception e)
             {
-                grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, null, StatusCode.Unknown, GetMetadataExceptionMsg);
+                grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
                 Logger.Error(e, GetMetadataExceptionMsg);
             }
         }
@@ -97,6 +97,7 @@ namespace Grpc.Core.Internal
             {
                 var metadata = new Metadata();
                 await interceptor(serviceUrl, metadata);
+
                 using (var metadataArray = MetadataArraySafeHandle.Create(metadata))
                 {
                     grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, metadataArray, StatusCode.OK, null);
@@ -104,7 +105,7 @@ namespace Grpc.Core.Internal
             }
             catch (Exception e)
             {
-                grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, null, StatusCode.Unknown, GetMetadataExceptionMsg);
+                grpcsharp_metadata_credentials_notify_from_plugin(callbackPtr, userDataPtr, MetadataArraySafeHandle.Create(Metadata.Empty), StatusCode.Unknown, GetMetadataExceptionMsg);
                 Logger.Error(e, GetMetadataExceptionMsg);
             }
         }

From cf72a3adfe8ab55775d8e0d648fb62f8b4e58f1d Mon Sep 17 00:00:00 2001
From: Jan Tattermusch <jtattermusch@google.com>
Date: Thu, 8 Oct 2015 08:44:20 -0700
Subject: [PATCH 3/3] use JWT credentials for per_rpc_creds

---
 src/csharp/Grpc.IntegrationTesting/InteropClient.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 888b5c312fe..cb50b44841f 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