diff options
Diffstat (limited to 'src/csharp')
19 files changed, 541 insertions, 11 deletions
diff --git a/src/csharp/Grpc.Auth/.gitignore b/src/csharp/Grpc.Auth/.gitignore new file mode 100644 index 0000000000..c2dd664167 --- /dev/null +++ b/src/csharp/Grpc.Auth/.gitignore @@ -0,0 +1,3 @@ +bin +obj +*.nupkg diff --git a/src/csharp/Grpc.Auth/GoogleCredential.cs b/src/csharp/Grpc.Auth/GoogleCredential.cs new file mode 100644 index 0000000000..36d43d3207 --- /dev/null +++ b/src/csharp/Grpc.Auth/GoogleCredential.cs @@ -0,0 +1,124 @@ +#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.IO; +using System.Security.Cryptography; + +using Google.Apis.Auth.OAuth2; +using Mono.Security.Cryptography; +using Newtonsoft.Json.Linq; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; + +namespace Grpc.Auth +{ + // TODO(jtattermusch): Remove this class once possible. + /// <summary> + /// A temporary placeholder for Google credential from + /// Google Auth library for .NET. It emulates the usage pattern + /// for Usable auth. + /// </summary> + 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; + + private GoogleCredential(ServiceCredential credential) + { + this.credential = credential; + } + + public static GoogleCredential GetApplicationDefault() + { + return new GoogleCredential(null); + } + + public bool IsCreateScopedRequired + { + get + { + return true; + } + } + + public GoogleCredential CreateScoped(IEnumerable<string> scopes) + { + var credsPath = Environment.GetEnvironmentVariable(GoogleApplicationCredentialsEnvName); + if (credsPath == null) + { + // Default to ComputeCredentials if path to JSON key is not set. + // ComputeCredential is not scoped actually, but for our use case it's + // fine to treat is as such. + return new GoogleCredential(new ComputeCredential(new ComputeCredential.Initializer())); + } + + 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(clientEmail) + { + Scopes = scopes, + Key = privateKey + }); + return new GoogleCredential(serviceCredential); + } + + internal ServiceCredential InternalCredential + { + get + { + 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 new file mode 100644 index 0000000000..1931db5fd8 --- /dev/null +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -0,0 +1,93 @@ +<?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> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>10.0.0</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}</ProjectGuid> + <OutputType>Library</OutputType> + <RootNamespace>Grpc.Auth</RootNamespace> + <AssemblyName>Grpc.Auth</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug</OutputPath> + <DefineConstants>DEBUG;</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <ConsolePause>false</ConsolePause> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>full</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release</OutputPath> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <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" /> + <Compile Include="GoogleCredential.cs" /> + <Compile Include="OAuth2InterceptorFactory.cs" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <ItemGroup> + <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj"> + <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project> + <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 new file mode 100644 index 0000000000..ca384d1a6e --- /dev/null +++ b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs @@ -0,0 +1,104 @@ +#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.Diagnostics; +using System.IO; +using System.Security.Cryptography.X509Certificates; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +using Google.Apis.Auth.OAuth2; +using Google.Apis.Util; +using Grpc.Core; +using Grpc.Core.Utils; + +namespace Grpc.Auth +{ + public static class OAuth2InterceptorFactory + { + /// <summary> + /// Creates OAuth2 interceptor. + /// </summary> + public static HeaderInterceptorDelegate Create(GoogleCredential googleCredential) + { + var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default); + return new HeaderInterceptorDelegate(interceptor.InterceptHeaders); + } + + /// <summary> + /// Injects OAuth2 authorization header into initial metadata (= request headers). + /// </summary> + private class OAuth2Interceptor + { + private const string AuthorizationHeader = "Authorization"; + private const string Schema = "Bearer"; + + private ServiceCredential credential; + private IClock clock; + + public OAuth2Interceptor(ServiceCredential credential, IClock clock) + { + this.credential = credential; + this.clock = clock; + } + + /// <summary> + /// Gets access token and requests refreshing it if is going to expire soon. + /// </summary> + /// <param name="cancellationToken"></param> + /// <returns></returns> + public string GetAccessToken(CancellationToken cancellationToken) + { + if (credential.Token == null || credential.Token.IsExpired(clock)) + { + // TODO(jtattermusch): Parallel requests will spawn multiple requests to refresh the token once the token expires. + // TODO(jtattermusch): Rethink synchronous wait to obtain the result. + if (!credential.RequestAccessTokenAsync(cancellationToken).Result) + { + throw new InvalidOperationException("The access token has expired but we can't refresh it"); + } + } + return credential.Token.AccessToken; + } + + public void InterceptHeaders(Metadata.Builder headerBuilder) + { + var accessToken = GetAccessToken(CancellationToken.None); + headerBuilder.Add(new Metadata.MetadataEntry(AuthorizationHeader, Schema + " " + accessToken)); + } + } + } +} diff --git a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..66b18d0ccf --- /dev/null +++ b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs @@ -0,0 +1,14 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly: AssemblyTitle("Grpc.Auth")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Google Inc. All rights reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: AssemblyVersion("0.2.*")] + +[assembly: InternalsVisibleTo("Grpc.Auth.Tests")]
\ No newline at end of file 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.Core/RpcException.cs b/src/csharp/Grpc.Core/RpcException.cs index 433d87215e..c58578286b 100644 --- a/src/csharp/Grpc.Core/RpcException.cs +++ b/src/csharp/Grpc.Core/RpcException.cs @@ -42,7 +42,7 @@ namespace Grpc.Core { private readonly Status status; - public RpcException(Status status) + public RpcException(Status status) : base(status.ToString()) { this.status = status; } diff --git a/src/csharp/Grpc.Core/Status.cs b/src/csharp/Grpc.Core/Status.cs index 080bbdc2f5..7d76aec4d1 100644 --- a/src/csharp/Grpc.Core/Status.cs +++ b/src/csharp/Grpc.Core/Status.cs @@ -69,5 +69,10 @@ namespace Grpc.Core return detail; } } + + public override string ToString() + { + return string.Format("Status(StatusCode={0}, Detail=\"{1}\")", statusCode, detail); + } } } diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj index b1a4a81916..df05c535e2 100644 --- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj +++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.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> @@ -46,4 +46,7 @@ <Name>Grpc.IntegrationTesting</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <None Include="app.config" /> + </ItemGroup> </Project>
\ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting.Client/app.config b/src/csharp/Grpc.IntegrationTesting.Client/app.config new file mode 100644 index 0000000000..966b777192 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting.Client/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.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj index 73c9f2d207..235897c888 100644 --- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj +++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.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> @@ -46,4 +46,7 @@ <Name>Grpc.IntegrationTesting</Name> </ProjectReference> </ItemGroup> + <ItemGroup> + <None Include="app.config" /> + </ItemGroup> </Project>
\ No newline at end of file diff --git a/src/csharp/Grpc.IntegrationTesting.Server/app.config b/src/csharp/Grpc.IntegrationTesting.Server/app.config new file mode 100644 index 0000000000..966b777192 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting.Server/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.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index 6ae8041fb7..13bbb5363f 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -32,6 +32,21 @@ <PlatformTarget>x86</PlatformTarget> </PropertyGroup> <ItemGroup> + <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="nunit.framework"> <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath> </Reference> @@ -39,8 +54,19 @@ <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> + <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" /> + <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> @@ -61,8 +87,13 @@ <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" /> <None Include="packages.config" /> <None Include="proto\test.proto" /> <None Include="proto\empty.proto" /> @@ -83,4 +114,9 @@ <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </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.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 6b92d3c660..1fbae374b1 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -33,12 +33,11 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; 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; @@ -47,6 +46,11 @@ 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 +119,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" || options.testCase == "compute_engine_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 +159,12 @@ namespace Grpc.IntegrationTesting case "empty_stream": RunEmptyStream(client); break; + case "service_account_creds": + RunServiceAccountCreds(client); + break; + case "compute_engine_creds": + RunComputeEngineCreds(client); + break; case "benchmark_empty_unary": RunBenchmarkEmptyUnary(client); break; @@ -287,6 +308,46 @@ 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!"); + } + + public static void RunComputeEngineCreds(TestServiceGrpc.ITestServiceClient client) + { + Console.WriteLine("running compute_engine_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(ComputeEngineUser, 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 new file mode 100644 index 0000000000..966b777192 --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/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.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config index 335f829432..e33b6e3e46 100644 --- a/src/csharp/Grpc.IntegrationTesting/packages.config +++ b/src/csharp/Grpc.IntegrationTesting/packages.config @@ -1,6 +1,13 @@ <?xml version="1.0" encoding="utf-8"?> <packages> + <package id="Google.Apis.Auth" version="1.9.1" targetFramework="net45" /> + <package id="Google.Apis.Core" version="1.9.1" targetFramework="net45" /> <package id="Google.ProtocolBuffers" version="2.4.1.521" 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.Bcl.Immutable" version="1.0.34" targetFramework="net45" /> + <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" /> + <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" /> <package id="NUnit" version="2.6.4" targetFramework="net45" /> </packages>
\ No newline at end of file diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln index 2f8c2e1719..e2a374e362 100644 --- a/src/csharp/Grpc.sln +++ b/src/csharp/Grpc.sln @@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Ser EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.csproj", "{BF62FE08-373A-43D6-9D73-41CAA38B7011}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Auth", "Grpc.Auth\Grpc.Auth.csproj", "{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@@ -49,6 +51,10 @@ Global {A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86
{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU
+ {AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86
{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86
|