Skip to content

Commit

Permalink
Support AAD auth (#19892)
Browse files Browse the repository at this point in the history
* Support AAD auth

* Fix test

* Add back provider

* Fix processor binding

* API and change log

* Fix test

* Undo test change

* stop the hosts

* try increasing timeout

* volatile

* unused code

* debug

* fix

* Add debug statements

* debug

* semaphore

* Fix for real

* add back debug info

* Add missing StopAsync call

* remove logging
  • Loading branch information
JoshLove-msft authored Apr 6, 2021
1 parent 4825853 commit 762a7b2
Show file tree
Hide file tree
Showing 33 changed files with 769 additions and 723 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# Release History

## 5.0.0-beta.2 (Unreleased)
## 5.0.0-beta.2 (2021-04-07)

### Added
- Add AAD support

### Breaking Changes
- Changed the API signatures for the methods in `MessagingProvider`.
- Added `receiver` parameter to `MessageProcessor` constructor.
- Added `client` parameter to `SessionMessageProcessor` constructor.

## 5.0.0-beta.1 (2021-03-23)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ For local development, use the `local.settings.json` file to store the connectio

When deployed, use the [application settings](https://docs.microsoft.com/azure/azure-functions/functions-how-to-use-azure-function-app-settings) to set the connection string.

#### Managed identity authentication

If your environment has [managed identity](https://docs.microsoft.com/azure/app-service/overview-managed-identity?tabs=dotnet) enabled you can use it to authenticate the Service Bus extension.
To use managed identity provide the `<connection_name>__fullyQualifiedNamespace` configuration setting.

```json
{
"Values": {
"<connection_name>__fullyQualifiedNamespace": "<service_bus_namespace>.servicebus.windows.net"
}
}
```

Or in the case of deployed app set the same setting in [application settings](https://docs.microsoft.com/azure/azure-functions/functions-how-to-use-azure-function-app-settings):

```
<connection_name>__fullyQualifiedNamespace=<service_bus_namespace>.servicebus.windows.net
```


## Key concepts

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,24 @@ public enum EntityType
}
public partial class MessageProcessor
{
public MessageProcessor(Azure.Messaging.ServiceBus.ServiceBusProcessor processor) { }
public MessageProcessor(Azure.Messaging.ServiceBus.ServiceBusProcessor processor, Azure.Messaging.ServiceBus.ServiceBusReceiver receiver) { }
protected internal Azure.Messaging.ServiceBus.ServiceBusProcessor Processor { get { throw null; } set { } }
protected internal Azure.Messaging.ServiceBus.ServiceBusReceiver Receiver { get { throw null; } set { } }
public virtual System.Threading.Tasks.Task<bool> BeginProcessingMessageAsync(Microsoft.Azure.WebJobs.ServiceBus.ServiceBusMessageActions messageActions, Azure.Messaging.ServiceBus.ServiceBusReceivedMessage message, System.Threading.CancellationToken cancellationToken) { throw null; }
public virtual System.Threading.Tasks.Task CompleteProcessingMessageAsync(Microsoft.Azure.WebJobs.ServiceBus.ServiceBusMessageActions messageActions, Azure.Messaging.ServiceBus.ServiceBusReceivedMessage message, Microsoft.Azure.WebJobs.Host.Executors.FunctionResult result, System.Threading.CancellationToken cancellationToken) { throw null; }
}
public partial class MessagingProvider
{
public MessagingProvider(Microsoft.Extensions.Options.IOptions<Microsoft.Azure.WebJobs.ServiceBus.ServiceBusOptions> serviceBusOptions) { }
public virtual Azure.Messaging.ServiceBus.ServiceBusReceiver CreateBatchMessageReceiver(string entityPath, string connectionString) { throw null; }
protected MessagingProvider() { }
public MessagingProvider(Microsoft.Extensions.Options.IOptions<Microsoft.Azure.WebJobs.ServiceBus.ServiceBusOptions> options) { }
public virtual Azure.Messaging.ServiceBus.ServiceBusReceiver CreateBatchMessageReceiver(Azure.Messaging.ServiceBus.ServiceBusClient client, string entityPath) { throw null; }
public virtual Azure.Messaging.ServiceBus.ServiceBusClient CreateClient(string connectionString) { throw null; }
public virtual Microsoft.Azure.WebJobs.ServiceBus.MessageProcessor CreateMessageProcessor(string entityPath, string connectionString) { throw null; }
public virtual Azure.Messaging.ServiceBus.ServiceBusSender CreateMessageSender(string entityPath, string connectionString) { throw null; }
public virtual Azure.Messaging.ServiceBus.ServiceBusProcessor CreateProcessor(string entityPath, string connectionString) { throw null; }
public virtual Microsoft.Azure.WebJobs.ServiceBus.SessionMessageProcessor CreateSessionMessageProcessor(string entityPath, string connectionString) { throw null; }
public virtual Azure.Messaging.ServiceBus.ServiceBusClient CreateClient(string fullyQualifiedNamespace, Azure.Core.TokenCredential credential) { throw null; }
public virtual Microsoft.Azure.WebJobs.ServiceBus.MessageProcessor CreateMessageProcessor(Azure.Messaging.ServiceBus.ServiceBusClient client, string entityPath) { throw null; }
public virtual Azure.Messaging.ServiceBus.ServiceBusSender CreateMessageSender(Azure.Messaging.ServiceBus.ServiceBusClient client, string entityPath) { throw null; }
public virtual Azure.Messaging.ServiceBus.ServiceBusProcessor CreateProcessor(Azure.Messaging.ServiceBus.ServiceBusClient client, string entityPath) { throw null; }
public virtual Microsoft.Azure.WebJobs.ServiceBus.SessionMessageProcessor CreateSessionMessageProcessor(Azure.Messaging.ServiceBus.ServiceBusClient client, string entityPath) { throw null; }
public virtual Azure.Messaging.ServiceBus.ServiceBusSessionProcessor CreateSessionProcessor(Azure.Messaging.ServiceBus.ServiceBusClient client, string entityPath) { throw null; }
}
public partial class ServiceBusMessageActions
{
Expand All @@ -78,7 +83,6 @@ public partial class ServiceBusOptions : Microsoft.Azure.WebJobs.Hosting.IOption
{
public ServiceBusOptions() { }
public bool AutoCompleteMessages { get { throw null; } set { } }
public string ConnectionString { get { throw null; } set { } }
public System.Func<Azure.Messaging.ServiceBus.ProcessErrorEventArgs, System.Threading.Tasks.Task> ExceptionHandler { get { throw null; } set { } }
public System.TimeSpan MaxAutoLockRenewalDuration { get { throw null; } set { } }
public int MaxConcurrentCalls { get { throw null; } set { } }
Expand All @@ -104,7 +108,9 @@ public void Configure(Microsoft.Azure.WebJobs.IWebJobsBuilder builder) { }
}
public partial class SessionMessageProcessor
{
public SessionMessageProcessor(Azure.Messaging.ServiceBus.ServiceBusSessionProcessor processor) { }
public SessionMessageProcessor(Azure.Messaging.ServiceBus.ServiceBusClient client, Azure.Messaging.ServiceBus.ServiceBusSessionProcessor processor) { }
protected internal Azure.Messaging.ServiceBus.ServiceBusClient Client { get { throw null; } set { } }
protected internal Azure.Messaging.ServiceBus.ServiceBusSessionProcessor Processor { get { throw null; } set { } }
public virtual System.Threading.Tasks.Task<bool> BeginProcessingMessageAsync(Microsoft.Azure.WebJobs.ServiceBus.ServiceBusSessionMessageActions sessionActions, Azure.Messaging.ServiceBus.ServiceBusReceivedMessage message, System.Threading.CancellationToken cancellationToken) { throw null; }
public virtual System.Threading.Tasks.Task CompleteProcessingMessageAsync(Microsoft.Azure.WebJobs.ServiceBus.ServiceBusSessionMessageActions sessionActions, Azure.Messaging.ServiceBus.ServiceBusReceivedMessage message, Microsoft.Azure.WebJobs.Host.Executors.FunctionResult result, System.Threading.CancellationToken cancellationToken) { throw null; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
using System.Globalization;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Extensions.ServiceBus.Config;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Azure.WebJobs.Host.Bindings;
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Azure.WebJobs.ServiceBus.Bindings
Expand All @@ -25,33 +27,17 @@ internal class ServiceBusAttributeBindingProvider : IBindingProvider
new AsyncCollectorArgumentBindingProvider());

private readonly INameResolver _nameResolver;
private readonly ServiceBusOptions _options;
private readonly IConfiguration _configuration;
private readonly MessagingProvider _messagingProvider;
private readonly ServiceBusClientFactory _clientFactory;

public ServiceBusAttributeBindingProvider(INameResolver nameResolver, ServiceBusOptions options, IConfiguration configuration, MessagingProvider messagingProvider)
public ServiceBusAttributeBindingProvider(
INameResolver nameResolver,
MessagingProvider messagingProvider,
ServiceBusClientFactory clientFactory)
{
if (nameResolver == null)
{
throw new ArgumentNullException(nameof(nameResolver));
}
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
if (messagingProvider == null)
{
throw new ArgumentNullException(nameof(messagingProvider));
}

_nameResolver = nameResolver;
_options = options;
_configuration = configuration;
_messagingProvider = messagingProvider;
_nameResolver = nameResolver ?? throw new ArgumentNullException(nameof(nameResolver));
_messagingProvider = messagingProvider ?? throw new ArgumentNullException(nameof(messagingProvider));
_clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory));
}

public Task<IBinding> TryCreateAsync(BindingProviderContext context)
Expand All @@ -69,7 +55,7 @@ public Task<IBinding> TryCreateAsync(BindingProviderContext context)
return Task.FromResult<IBinding>(null);
}

string queueOrTopicName = Resolve(attribute.QueueOrTopicName);
string queueOrTopicName = _nameResolver.ResolveWholeString(attribute.QueueOrTopicName);
IBindableServiceBusPath path = BindableServiceBusPath.Create(queueOrTopicName);
ValidateContractCompatibility(path, context.BindingDataContract);

Expand All @@ -79,10 +65,9 @@ public Task<IBinding> TryCreateAsync(BindingProviderContext context)
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Can't bind ServiceBus to type '{0}'.", parameter.ParameterType));
}

attribute.Connection = Resolve(attribute.Connection);
ServiceBusAccount account = new ServiceBusAccount(_options, _configuration, attribute);
attribute.Connection = _nameResolver.ResolveWholeString(attribute.Connection);

IBinding binding = new ServiceBusBinding(parameter.Name, argumentBinding, account, path, attribute, _messagingProvider);
IBinding binding = new ServiceBusBinding(parameter.Name, argumentBinding, path, attribute, _messagingProvider, _clientFactory);
return Task.FromResult<IBinding>(binding);
}

Expand All @@ -105,15 +90,5 @@ private static void ValidateContractCompatibility(IBindableServiceBusPath path,
}
}
}

private string Resolve(string queueName)
{
if (_nameResolver == null)
{
return queueName;
}

return _nameResolver.ResolveWholeString(queueName);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Extensions.ServiceBus.Config;
using Microsoft.Azure.WebJobs.Host.Bindings;
using Microsoft.Azure.WebJobs.Host.Converters;
using Microsoft.Azure.WebJobs.Host.Protocols;
Expand All @@ -14,21 +15,27 @@ internal class ServiceBusBinding : IBinding
{
private readonly string _parameterName;
private readonly IArgumentBinding<ServiceBusEntity> _argumentBinding;
private readonly ServiceBusAccount _account;
private readonly IBindableServiceBusPath _path;
private readonly IAsyncObjectToTypeConverter<ServiceBusEntity> _converter;
private readonly EntityType _entityType;
private readonly MessagingProvider _messagingProvider;

public ServiceBusBinding(string parameterName, IArgumentBinding<ServiceBusEntity> argumentBinding, ServiceBusAccount account, IBindableServiceBusPath path, ServiceBusAttribute attr, MessagingProvider messagingProvider)
private readonly ServiceBusClientFactory _clientFactory;
private readonly ServiceBusAttribute _attribute;

public ServiceBusBinding(
string parameterName,
IArgumentBinding<ServiceBusEntity> argumentBinding,
IBindableServiceBusPath path,
ServiceBusAttribute attribute,
MessagingProvider messagingProvider,
ServiceBusClientFactory clientFactory)
{
_parameterName = parameterName;
_argumentBinding = argumentBinding;
_account = account;
_path = path;
_entityType = attr.EntityType;
_messagingProvider = messagingProvider;
_converter = new OutputConverter<string>(new StringToServiceBusEntityConverter(account, _path, _entityType, _messagingProvider));
_clientFactory = clientFactory;
_attribute = attribute;
_converter = new OutputConverter<string>(new StringToServiceBusEntityConverter(_attribute, _path, _messagingProvider, _clientFactory));
}

public bool FromAttribute
Expand All @@ -41,12 +48,12 @@ public async Task<IValueProvider> BindAsync(BindingContext context)
context.CancellationToken.ThrowIfCancellationRequested();

string boundQueueName = _path.Bind(context.BindingData);
var messageSender = _messagingProvider.CreateMessageSender(boundQueueName, _account.ConnectionString);
var messageSender = _messagingProvider.CreateMessageSender(_clientFactory.CreateClientFromSetting(_attribute.Connection), boundQueueName);

var entity = new ServiceBusEntity
{
MessageSender = messageSender,
EntityType = _entityType
EntityType = _attribute.EntityType
};

return await BindAsync(entity, context.ValueContext).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using Microsoft.Azure.WebJobs.Extensions.ServiceBus.Config;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Azure.WebJobs.ServiceBus.Bindings
{
internal class StringToServiceBusEntityConverter : IAsyncConverter<string, ServiceBusEntity>
{
private readonly ServiceBusAccount _account;
private readonly ServiceBusAttribute _attribute;
private readonly IBindableServiceBusPath _defaultPath;
private readonly EntityType _entityType;
private readonly MessagingProvider _messagingProvider;
private readonly ServiceBusClientFactory _clientFactory;

public StringToServiceBusEntityConverter(ServiceBusAccount account, IBindableServiceBusPath defaultPath, EntityType entityType, MessagingProvider messagingProvider)
public StringToServiceBusEntityConverter(ServiceBusAttribute attribute, IBindableServiceBusPath defaultPath, MessagingProvider messagingProvider, ServiceBusClientFactory clientFactory)
{
_account = account;
_attribute = attribute;
_defaultPath = defaultPath;
_entityType = entityType;
_entityType = _attribute.EntityType;
_messagingProvider = messagingProvider;
_clientFactory = clientFactory;
}

public Task<ServiceBusEntity> ConvertAsync(string input, CancellationToken cancellationToken)
{
string queueOrTopicName;

// For convenience, treat an an empty string as a request for the default value.
if (String.IsNullOrEmpty(input) && _defaultPath.IsBound)
if (string.IsNullOrEmpty(input) && _defaultPath.IsBound)
{
queueOrTopicName = _defaultPath.Bind(null);
}
Expand All @@ -37,7 +39,7 @@ public Task<ServiceBusEntity> ConvertAsync(string input, CancellationToken cance
}

cancellationToken.ThrowIfCancellationRequested();
var messageSender = _messagingProvider.CreateMessageSender(queueOrTopicName, _account.ConnectionString);
var messageSender = _messagingProvider.CreateMessageSender(_clientFactory.CreateClientFromSetting(_attribute.Connection), queueOrTopicName);

var entity = new ServiceBusEntity
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Azure.WebJobs.Extensions.Clients.Shared;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Azure.WebJobs.Extensions.ServiceBus.Config
{
internal static class ConfigurationExtensions
{
// The order of priority is intentionally flipped from what is defined in
// WebJobsConfigurationExtensions.GetWebJobsConnectionStringSection for back compat with the Track 1
// Service Bus extensions.
public static IConfigurationSection GetWebJobsConnectionStringSectionServiceBus(this IConfiguration configuration, string connectionStringName)
{
// first try a direct unprefixed lookup
IConfigurationSection section = WebJobsConfigurationExtensions.GetConnectionStringOrSetting(configuration, connectionStringName);

if (!section.Exists())
{
// next try prefixing
string prefixedConnectionStringName = WebJobsConfigurationExtensions.GetPrefixedConnectionStringName(connectionStringName);
section = WebJobsConfigurationExtensions.GetConnectionStringOrSetting(configuration, prefixedConnectionStringName);
}

return section;
}
}
}
Loading

0 comments on commit 762a7b2

Please sign in to comment.