From dca6e884ce8f9363029f9dfd1a68f02882c5394b Mon Sep 17 00:00:00 2001
From: Jan Tattermusch <jtattermusch@google.com>
Date: Wed, 22 Apr 2015 16:56:27 -0700
Subject: [PATCH] First attempt to add service account creds interop test

---
 src/csharp/Grpc.Auth/GoogleCredential.cs      | 50 +++++++++++--------
 src/csharp/Grpc.Auth/Grpc.Auth.csproj         | 48 +++++++++++++++++-
 .../Grpc.Auth/OAuth2InterceptorFactory.cs     |  6 +--
 src/csharp/Grpc.Auth/app.config               | 15 ++++++
 src/csharp/Grpc.Auth/packages.config          | 12 +++++
 src/csharp/Grpc.Core/Grpc.Core.csproj         |  3 +-
 .../Grpc.IntegrationTesting.Client/app.config |  4 ++
 .../Grpc.IntegrationTesting.Server/app.config |  4 ++
 .../Grpc.IntegrationTesting.csproj            | 21 ++++----
 .../Grpc.IntegrationTesting/InteropClient.cs  | 47 ++++++++++++++++-
 src/csharp/Grpc.IntegrationTesting/app.config |  4 ++
 11 files changed, 173 insertions(+), 41 deletions(-)
 create mode 100644 src/csharp/Grpc.Auth/app.config
 create mode 100644 src/csharp/Grpc.Auth/packages.config

diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs
index d66952a901..7385a26485 100644
--- a/src/csharp/Grpc.Auth/GoogleCredential.cs
+++ b/src/csharp/Grpc.Auth/GoogleCredential.cs
@@ -41,6 +41,11 @@ using Grpc.Core.Utils;
 
 using Google.Apis.Auth.OAuth2;
 using System.Security.Cryptography.X509Certificates;
+using Newtonsoft.Json.Linq;
+using Mono.Security.Cryptography;
+using Org.BouncyCastle.Crypto.Parameters;
+using System.Security.Cryptography;
+using Org.BouncyCastle.Security;
 
 namespace Grpc.Auth
 {
@@ -53,6 +58,8 @@ namespace Grpc.Auth
     public class GoogleCredential
     {
         private const string GoogleApplicationCredentialsEnvName = "GOOGLE_APPLICATION_CREDENTIALS";
+        private const string ClientEmailFieldName = "client_email";
+        private const string PrivateKeyFieldName = "private_key";
 
         private ServiceCredential credential;
 
@@ -76,31 +83,20 @@ namespace Grpc.Auth
 
         public GoogleCredential CreateScoped(IEnumerable<string> scopes)
         {
+            // TODO(jtattermusch): also support compute credential.
+            var credsPath = Environment.GetEnvironmentVariable(GoogleApplicationCredentialsEnvName);
 
-            // TODO: also support compute credential.
-
-            //var credsPath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
-            //var credsPath = "/usr/local/google/home/jtattermusch/certs/service_account/stubbyCloudTestingTest-7dd63462c60c.json";
-
-            //JObject o1 = JObject.Parse(File.ReadAllText(credsPath));
-            //string privateKey = o1.GetValue("private_key").Value<string>();
-            //Console.WriteLine(privateKey);
-
-            //var certificate = new X509Certificate2(System.Text.Encoding.UTF8.GetBytes(privateKey), "notasecret", X509KeyStorageFlags.Exportable);
-
-            // TODO: support JSON key file.
-
-            // TODO: get file location from GoogleApplicationCredential env var
-            var certificate = new X509Certificate2("/usr/local/google/home/jtattermusch/certs/stubbyCloudTestingTest-090796e783f3.p12", "notasecret", X509KeyStorageFlags.Exportable);
-
-            // TODO: auth user will be read from the JSON key
-            string authUser = "155450119199-3psnrh1sdr3d8cpj1v46naggf81mhdnk@developer.gserviceaccount.com";
+            JObject o1 = JObject.Parse(File.ReadAllText(credsPath));
+            string clientEmail = o1.GetValue(ClientEmailFieldName).Value<string>();
+            string privateKeyString = o1.GetValue(PrivateKeyFieldName).Value<string>();
+            var privateKey = ParsePrivateKeyFromString(privateKeyString);
 
             var serviceCredential = new ServiceAccountCredential(
-                new ServiceAccountCredential.Initializer(authUser)
+                new ServiceAccountCredential.Initializer(clientEmail)
                 {
-                    Scopes = scopes
-                }.FromCertificate(certificate));
+                    Scopes = scopes,
+                    Key = privateKey
+                });
             return new GoogleCredential(serviceCredential);
         }
 
@@ -111,5 +107,17 @@ namespace Grpc.Auth
                 return credential;
             }
         }
+
+        private RSACryptoServiceProvider ParsePrivateKeyFromString(string base64PrivateKey)
+        {
+            // TODO(jtattermusch): temporary code to create RSACryptoServiceProvider.
+            base64PrivateKey = base64PrivateKey.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("\n", "").Replace("-----END PRIVATE KEY-----", "");
+            PKCS8.PrivateKeyInfo PKI = new PKCS8.PrivateKeyInfo(Convert.FromBase64String(base64PrivateKey));
+            RsaPrivateCrtKeyParameters key = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(PKI.GetBytes());
+            RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(key);
+            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
+            rsa.ImportParameters(rsaParameters);
+            return rsa;
+        }
     }
 }
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index dbbee780a8..1931db5fd8 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -30,7 +30,44 @@
     <ConsolePause>false</ConsolePause>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="BouncyCastle.Crypto">
+      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth">
+      <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth.PlatformServices">
+      <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Core">
+      <HintPath>..\packages\Google.Apis.Core.1.9.1\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks.Extensions">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+    </Reference>
+    <Reference Include="Mono.Security">
+      <HintPath>..\packages\Mono.Security.3.2.3.0\lib\net45\Mono.Security.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
+    <Reference Include="System.Net" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Net.Http.Extensions">
+      <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Net.Http.Primitives">
+      <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Net.Http.WebRequest" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Properties\AssemblyInfo.cs" />
@@ -44,4 +81,13 @@
       <Name>Grpc.Core</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
+  <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
+    <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
+    <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
+  </Target>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
index ae9d70deb8..8a1e87ad6f 100644
--- a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
+++ b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
@@ -33,17 +33,13 @@
 
 using System;
 using System.Collections.Generic;
-using System.Collections.Immutable;
 using System.Diagnostics;
 using System.IO;
 using System.Text.RegularExpressions;
 using System.Threading;
 using System.Threading.Tasks;
-using Google.ProtocolBuffers;
-using grpc.testing;
 using Grpc.Core;
 using Grpc.Core.Utils;
-using NUnit.Framework;
 
 using Google.Apis.Auth.OAuth2;
 using System.Security.Cryptography.X509Certificates;
@@ -59,7 +55,7 @@ namespace Grpc.Auth
             string accessToken = credential.Token.AccessToken;
 
             // TODO: token refresh logic!!
-            return new HeaderInterceptorDelegate((b)=> { b.Add(new Metadata.MetadataEntry("Authorization", "Bearer " + accessToken)); });
+            return new HeaderInterceptorDelegate((b) => { b.Add(new Metadata.MetadataEntry("Authorization", "Bearer " + accessToken)); });
 
         }
     }
diff --git a/src/csharp/Grpc.Auth/app.config b/src/csharp/Grpc.Auth/app.config
new file mode 100644
index 0000000000..966b777192
--- /dev/null
+++ b/src/csharp/Grpc.Auth/app.config
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config
new file mode 100644
index 0000000000..0816bdbad1
--- /dev/null
+++ b/src/csharp/Grpc.Auth/packages.config
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
+  <package id="Google.Apis.Auth" version="1.9.1" targetFramework="net45" />
+  <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" />
+  <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
+  <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
+  <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
+  <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
+  <package id="Mono.Security" version="3.2.3.0" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index b612512b03..0b85392e15 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -34,8 +34,7 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
-    <Reference Include="System.Collections.Immutable, Version=1.0.34.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
+    <Reference Include="System.Collections.Immutable">
       <HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
     </Reference>
   </ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config
index 4e4d248a19..966b777192 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/app.config
+++ b/src/csharp/Grpc.IntegrationTesting.Client/app.config
@@ -6,6 +6,10 @@
         <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
         <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
       </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
+      </dependentAssembly>
     </assemblyBinding>
   </runtime>
 </configuration>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config
index 4e4d248a19..966b777192 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/app.config
+++ b/src/csharp/Grpc.IntegrationTesting.Server/app.config
@@ -6,6 +6,10 @@
         <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
         <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
       </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
+      </dependentAssembly>
     </assemblyBinding>
   </runtime>
 </configuration>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index ce4a18c192..13bbb5363f 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -32,9 +32,6 @@
     <PlatformTarget>x86</PlatformTarget>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Google.Apis.Auth">
-      <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.dll</HintPath>
-    </Reference>
     <Reference Include="Google.Apis.Auth.PlatformServices">
       <HintPath>..\packages\Google.Apis.Auth.1.9.1\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
     </Reference>
@@ -50,10 +47,6 @@
     <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
       <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
     </Reference>
-    <Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
     <Reference Include="nunit.framework">
       <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
     </Reference>
@@ -61,10 +54,6 @@
     <Reference Include="Google.ProtocolBuffers">
       <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
     </Reference>
-    <Reference Include="System.Collections.Immutable, Version=1.0.34.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
-    </Reference>
     <Reference Include="System.Net" />
     <Reference Include="System.Net.Http" />
     <Reference Include="System.Net.Http.Extensions">
@@ -74,6 +63,12 @@
       <HintPath>..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll</HintPath>
     </Reference>
     <Reference Include="System.Net.Http.WebRequest" />
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Collections.Immutable">
+      <HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+    </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Properties\AssemblyInfo.cs" />
@@ -92,6 +87,10 @@
       <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
       <Name>Grpc.Core</Name>
     </ProjectReference>
+    <ProjectReference Include="..\Grpc.Auth\Grpc.Auth.csproj">
+      <Project>{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}</Project>
+      <Name>Grpc.Auth</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <None Include="app.config" />
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 6b92d3c660..20ecd60c30 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -39,14 +39,25 @@ using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using Google.ProtocolBuffers;
 using grpc.testing;
+using Grpc.Auth;
 using Grpc.Core;
 using Grpc.Core.Utils;
 using NUnit.Framework;
+using Newtonsoft.Json.Linq;
+using System.Threading;
+
+using Google.Apis.Auth.OAuth2;
+using System.Security.Cryptography.X509Certificates;
 
 namespace Grpc.IntegrationTesting
 {
     public class InteropClient
     {
+        private const string ServiceAccountUser = "155450119199-3psnrh1sdr3d8cpj1v46naggf81mhdnk@developer.gserviceaccount.com";
+        private const string ComputeEngineUser = "155450119199-r5aaqa2vqoa9g5mv2m6s3m1l293rlmel@developer.gserviceaccount.com";
+        private const string AuthScope = "https://www.googleapis.com/auth/xapi.zoo";
+        private const string AuthScopeResponse = "xapi.zoo";
+
         private class ClientOptions
         {
             public bool help;
@@ -115,7 +126,18 @@ namespace Grpc.IntegrationTesting
 
             using (Channel channel = new Channel(addr, credentials, channelArgs))
             {
-                TestServiceGrpc.ITestServiceClient client = new TestServiceGrpc.TestServiceClientStub(channel);
+                var stubConfig = StubConfiguration.Default;
+                if (options.testCase == "service_account_creds")
+                {
+                    var credential = GoogleCredential.GetApplicationDefault();
+                    if (credential.IsCreateScopedRequired)
+                    {
+                        credential = credential.CreateScoped(new[] { AuthScope });
+                    }
+                    stubConfig = new StubConfiguration(OAuth2InterceptorFactory.Create(credential));
+                }
+
+                TestServiceGrpc.ITestServiceClient client = new TestServiceGrpc.TestServiceClientStub(channel, stubConfig);
                 RunTestCase(options.testCase, client);
             }
 
@@ -144,6 +166,9 @@ namespace Grpc.IntegrationTesting
                 case "empty_stream":
                     RunEmptyStream(client);
                     break;
+                case "service_account_creds":
+                    RunServiceAccountCreds(client);
+                    break;
                 case "benchmark_empty_unary":
                     RunBenchmarkEmptyUnary(client);
                     break;
@@ -287,6 +312,26 @@ namespace Grpc.IntegrationTesting
             Console.WriteLine("Passed!");
         }
 
+        public static void RunServiceAccountCreds(TestServiceGrpc.ITestServiceClient client)
+        {
+            Console.WriteLine("running service_account_creds");
+            var request = SimpleRequest.CreateBuilder()
+                .SetResponseType(PayloadType.COMPRESSABLE)
+                    .SetResponseSize(314159)
+                    .SetPayload(CreateZerosPayload(271828))
+                    .SetFillUsername(true)
+                    .SetFillOauthScope(true)
+                    .Build();
+
+            var response = client.UnaryCall(request);
+
+            Assert.AreEqual(PayloadType.COMPRESSABLE, response.Payload.Type);
+            Assert.AreEqual(314159, response.Payload.Body.Length);
+            Assert.AreEqual(AuthScopeResponse, response.OauthScope);
+            Assert.AreEqual(ServiceAccountUser, response.Username);
+            Console.WriteLine("Passed!");
+        }
+
         // This is not an official interop test, but it's useful.
         public static void RunBenchmarkEmptyUnary(TestServiceGrpc.ITestServiceClient client)
         {
diff --git a/src/csharp/Grpc.IntegrationTesting/app.config b/src/csharp/Grpc.IntegrationTesting/app.config
index 4e4d248a19..966b777192 100644
--- a/src/csharp/Grpc.IntegrationTesting/app.config
+++ b/src/csharp/Grpc.IntegrationTesting/app.config
@@ -6,6 +6,10 @@
         <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
         <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.2.28.0" />
       </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.28.0" newVersion="4.0.0.0" />
+      </dependentAssembly>
     </assemblyBinding>
   </runtime>
 </configuration>
\ No newline at end of file
-- 
GitLab