Skip to content

Commit

Permalink
make CallCredentials implementation agnostic
Browse files Browse the repository at this point in the history
  • Loading branch information
jtattermusch committed Apr 5, 2019
1 parent e3290aa commit a1a878b
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 78 deletions.
4 changes: 2 additions & 2 deletions src/csharp/Grpc.Core.Tests/FakeCredentials.cs
Expand Up @@ -42,9 +42,9 @@ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()

internal class FakeCallCredentials : CallCredentials
{
internal override CallCredentialsSafeHandle ToNativeCredentials()
public override void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state)
{
return null;
// not invoking the configurator on purpose
}
}
}
44 changes: 37 additions & 7 deletions src/csharp/Grpc.Core/CallCredentials.cs
Expand Up @@ -16,9 +16,8 @@

#endregion

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Collections.ObjectModel;

using Grpc.Core.Internal;
using Grpc.Core.Utils;
Expand All @@ -38,7 +37,7 @@ public abstract class CallCredentials
/// <returns>The new <c>CompositeCallCredentials</c></returns>
public static CallCredentials Compose(params CallCredentials[] credentials)
{
return new CompositeCallCredentials(credentials);
return new CompositeCallCredentialsConfiguration(credentials);
}

/// <summary>
Expand All @@ -48,13 +47,44 @@ public static CallCredentials Compose(params CallCredentials[] credentials)
/// <param name="interceptor">authentication interceptor</param>
public static CallCredentials FromInterceptor(AsyncAuthInterceptor interceptor)
{
return new MetadataCredentials(interceptor);
return new AsyncAuthInterceptorCredentialsConfiguration(interceptor);
}

/// <summary>
/// Creates native object for the credentials.
/// Populates this call credential instances.
/// You never need to invoke this, part of internal implementation.
/// </summary>
/// <returns>The native credentials.</returns>
internal abstract CallCredentialsSafeHandle ToNativeCredentials();
public abstract void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state);

private class CompositeCallCredentialsConfiguration : CallCredentials
{
readonly IReadOnlyList<CallCredentials> credentials;

public CompositeCallCredentialsConfiguration(CallCredentials[] credentials)
{
GrpcPreconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials.");
this.credentials = new List<CallCredentials>(credentials).AsReadOnly();
}

public override void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state)
{
configurator.SetCompositeCredentials(state, credentials);
}
}

internal class AsyncAuthInterceptorCredentialsConfiguration : CallCredentials
{
readonly AsyncAuthInterceptor interceptor;

public AsyncAuthInterceptorCredentialsConfiguration(AsyncAuthInterceptor interceptor)
{
this.interceptor = GrpcPreconditions.CheckNotNull(interceptor);
}

public override void InternalPopulateConfiguration(CallCredentialsConfiguratorBase configurator, object state)
{
configurator.SetAsyncAuthInterceptorCredentials(state, interceptor);
}
}
}
}
38 changes: 38 additions & 0 deletions src/csharp/Grpc.Core/CallCredentialsConfiguratorBase.cs
@@ -0,0 +1,38 @@
#region Copyright notice and license

// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#endregion

using System.Collections.Generic;

namespace Grpc.Core
{
/// <summary>
/// Base class for objects that can consume configuration from <c>CallCredentials</c> objects.
/// </summary>
public abstract class CallCredentialsConfiguratorBase
{
/// <summary>
/// Consumes configuration for composite call credentials.
/// </summary>
public abstract void SetCompositeCredentials(object state, IReadOnlyList<CallCredentials> credentials);

/// <summary>
/// Consumes configuration for call credentials created from <c>AsyncAuthInterceptor</c>
/// </summary>
public abstract void SetAsyncAuthInterceptorCredentials(object state, AsyncAuthInterceptor interceptor);
}
}
Expand Up @@ -18,47 +18,46 @@

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using Grpc.Core.Internal;
using Grpc.Core.Utils;

namespace Grpc.Core.Internal
{
/// <summary>
/// Credentials that allow composing multiple credentials objects into one <see cref="CallCredentials"/> object.
/// Creates native call credential objects from instances of <c>CallCredentials</c>.
/// </summary>
internal sealed class CompositeCallCredentials : CallCredentials
internal class DefaultCallCredentialsConfigurator : CallCredentialsConfiguratorBase
{
readonly List<CallCredentials> credentials;
CallCredentialsSafeHandle nativeCredentials;

/// <summary>
/// Initializes a new instance of <c>CompositeCallCredentials</c> class.
/// The resulting credentials object will be composite of all the credentials specified as parameters.
/// </summary>
/// <param name="credentials">credentials to compose</param>
public CompositeCallCredentials(params CallCredentials[] credentials)
public CallCredentialsSafeHandle NativeCredentials => nativeCredentials;

public override void SetAsyncAuthInterceptorCredentials(object state, AsyncAuthInterceptor interceptor)
{
GrpcPreconditions.CheckArgument(credentials.Length >= 2, "Composite credentials object can only be created from 2 or more credentials.");
this.credentials = new List<CallCredentials>(credentials);
GrpcPreconditions.CheckState(nativeCredentials == null);

var plugin = new NativeMetadataCredentialsPlugin(interceptor);
nativeCredentials = plugin.Credentials;
}

internal override CallCredentialsSafeHandle ToNativeCredentials()
public override void SetCompositeCredentials(object state, IReadOnlyList<CallCredentials> credentials)
{
return ToNativeRecursive(0);
GrpcPreconditions.CheckState(nativeCredentials == null);

GrpcPreconditions.CheckArgument(credentials.Count >= 2);
nativeCredentials = CompositeToNativeRecursive(credentials, 0);
}

// Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier.
// In practice, we won't usually see composites from more than two credentials anyway.
private CallCredentialsSafeHandle ToNativeRecursive(int startIndex)
private CallCredentialsSafeHandle CompositeToNativeRecursive(IReadOnlyList<CallCredentials> credentials, int startIndex)
{
if (startIndex == credentials.Count - 1)
{
return credentials[startIndex].ToNativeCredentials();
}

using (var cred1 = credentials[startIndex].ToNativeCredentials())
using (var cred2 = ToNativeRecursive(startIndex + 1))
using (var cred2 = CompositeToNativeRecursive(credentials, startIndex + 1))
{
var nativeComposite = CallCredentialsSafeHandle.CreateComposite(cred1, cred2);
if (nativeComposite.IsInvalid)
Expand All @@ -69,4 +68,18 @@ private CallCredentialsSafeHandle ToNativeRecursive(int startIndex)
}
}
}

internal static class CallCredentialsExtensions
{
/// <summary>
/// Creates native object for the credentials.
/// </summary>
/// <returns>The native credentials.</returns>
public static CallCredentialsSafeHandle ToNativeCredentials(this CallCredentials credentials)
{
var configurator = new DefaultCallCredentialsConfigurator();
credentials.InternalPopulateConfiguration(configurator, credentials);
return configurator.NativeCredentials;
}
}
}
51 changes: 0 additions & 51 deletions src/csharp/Grpc.Core/Internal/MetadataCredentials.cs

This file was deleted.

0 comments on commit a1a878b

Please sign in to comment.