From 7422e2d7aef14226d208653391c5a2cca0d3c2c8 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 29 Jul 2019 16:00:29 -0700 Subject: [PATCH] Add anonymous auth for ASP.NET Core integration (#7036) --- .../src/AzureClientFactoryBuilder.cs | 4 +++- .../src/Internal/ClientInformation.cs | 7 +++++++ .../src/Internal/ConfigurationClientFactory.cs | 6 ++++++ .../tests/AzureClientFactoryTests.cs | 11 +++++++++++ .../tests/ClientFactoryTests.cs | 12 ++++++++++++ .../tests/TestClientWithCredentials.cs | 5 +++++ .../IAzureClientFactoryBuilderWithCredential.cs | 2 +- .../src/AzureClientBuilderExtensions.cs | 6 ++++-- .../src/AzureClientBuilderExtensions.cs | 6 ++++-- 9 files changed, 53 insertions(+), 6 deletions(-) diff --git a/sdk/core/Azure.Core.Extensions/src/AzureClientFactoryBuilder.cs b/sdk/core/Azure.Core.Extensions/src/AzureClientFactoryBuilder.cs index f19013c15ca9f..2e80683f53e50 100644 --- a/sdk/core/Azure.Core.Extensions/src/AzureClientFactoryBuilder.cs +++ b/sdk/core/Azure.Core.Extensions/src/AzureClientFactoryBuilder.cs @@ -70,9 +70,11 @@ public AzureClientFactoryBuilder ConfigureDefaults(IConfiguration configuration) return this; } - IAzureClientBuilder IAzureClientFactoryBuilderWithCredential.RegisterClientFactory(Func clientFactory) + IAzureClientBuilder IAzureClientFactoryBuilderWithCredential.RegisterClientFactory(Func clientFactory, bool requiresCredential) { var clientRegistration = new ClientRegistration(DefaultClientName, clientFactory); + clientRegistration.RequiresTokenCredential = requiresCredential; + _serviceCollection.AddSingleton(clientRegistration); _serviceCollection.TryAddSingleton(typeof(IConfigureOptions>), typeof(DefaultCredentialClientOptionsSetup)); diff --git a/sdk/core/Azure.Core.Extensions/src/Internal/ClientInformation.cs b/sdk/core/Azure.Core.Extensions/src/Internal/ClientInformation.cs index 2e5f77125e10f..0fb2b39fecf7f 100644 --- a/sdk/core/Azure.Core.Extensions/src/Internal/ClientInformation.cs +++ b/sdk/core/Azure.Core.Extensions/src/Internal/ClientInformation.cs @@ -10,6 +10,7 @@ internal class ClientRegistration { public string Name { get; set; } public object Version { get; set; } + public bool RequiresTokenCredential { get; set; } private readonly Func _factory; @@ -43,6 +44,12 @@ public TClient GetClient(TOptions options, TokenCredential tokenCredential) return _cachedClient; } + + if (RequiresTokenCredential && tokenCredential == null) + { + throw new InvalidOperationException("Client registration requires a TokenCredential. Configure it using UseCredential method."); + } + try { _cachedClient = _factory(options, tokenCredential); diff --git a/sdk/core/Azure.Core.Extensions/src/Internal/ConfigurationClientFactory.cs b/sdk/core/Azure.Core.Extensions/src/Internal/ConfigurationClientFactory.cs index 13cf599d46f4d..065d139857886 100644 --- a/sdk/core/Azure.Core.Extensions/src/Internal/ConfigurationClientFactory.cs +++ b/sdk/core/Azure.Core.Extensions/src/Internal/ConfigurationClientFactory.cs @@ -31,6 +31,12 @@ public static object CreateClient(Type clientType, Type optionsType, object opti { if (IsCredentialParameter(parameter)) { + if (credential == null) + { + match = false; + break; + } + arguments.Add(credential); continue; } diff --git a/sdk/core/Azure.Core.Extensions/tests/AzureClientFactoryTests.cs b/sdk/core/Azure.Core.Extensions/tests/AzureClientFactoryTests.cs index fd0c680eb3218..69ea516e8381b 100644 --- a/sdk/core/Azure.Core.Extensions/tests/AzureClientFactoryTests.cs +++ b/sdk/core/Azure.Core.Extensions/tests/AzureClientFactoryTests.cs @@ -319,6 +319,17 @@ public void SupportsSettingVersion() Assert.AreEqual(TestClientOptions.ServiceVersion.B, client.Options.Version); } + [Test] + public void ThrowsIfCredentialIsNullButIsRequired() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddAzureClients(builder => builder.AddTestClient(new Uri("http://localhost/")).WithCredential((TokenCredential)null)); + + ServiceProvider provider = serviceCollection.BuildServiceProvider(); + InvalidOperationException exception = Assert.Throws(() => provider.GetService()); + Assert.AreEqual("Client registration requires a TokenCredential. Configure it using UseCredential method.", exception.Message); + } + private IConfiguration GetConfiguration(params KeyValuePair[] items) { return new ConfigurationBuilder().AddInMemoryCollection(items).Build(); diff --git a/sdk/core/Azure.Core.Extensions/tests/ClientFactoryTests.cs b/sdk/core/Azure.Core.Extensions/tests/ClientFactoryTests.cs index ca41e1524b7ba..8e775c87f98b3 100644 --- a/sdk/core/Azure.Core.Extensions/tests/ClientFactoryTests.cs +++ b/sdk/core/Azure.Core.Extensions/tests/ClientFactoryTests.cs @@ -153,6 +153,18 @@ public void CreatesClientSecretCredentials() Assert.AreEqual("ConfigurationTenantId", clientSecretCredential.TenantId); } + [Test] + public void IgnoresConstructorWhenCredentialsNull() + { + IConfiguration configuration = GetConfiguration(new KeyValuePair("uri", "http://localhost")); + + var clientOptions = new TestClientOptions(); + var client = (TestClientWithCredentials)ClientFactory.CreateClient(typeof(TestClientWithCredentials), typeof(TestClientOptions), clientOptions, configuration, null); + + Assert.AreEqual("http://localhost/", client.Uri.ToString()); + Assert.AreSame(clientOptions, client.Options); + } + private IConfiguration GetConfiguration(params KeyValuePair[] items) { return new ConfigurationBuilder().AddInMemoryCollection(items).Build(); diff --git a/sdk/core/Azure.Core.Extensions/tests/TestClientWithCredentials.cs b/sdk/core/Azure.Core.Extensions/tests/TestClientWithCredentials.cs index 413b355d0ac3d..ce329617c6ba8 100644 --- a/sdk/core/Azure.Core.Extensions/tests/TestClientWithCredentials.cs +++ b/sdk/core/Azure.Core.Extensions/tests/TestClientWithCredentials.cs @@ -9,8 +9,13 @@ internal class TestClientWithCredentials : TestClient { public TokenCredential Credential { get; } + public TestClientWithCredentials(Uri uri, TestClientOptions options) : base(uri, options) + { + } + public TestClientWithCredentials(Uri uri, TokenCredential credential, TestClientOptions options) : base(uri, options) { + if (credential == null) throw new ArgumentNullException(nameof(credential)); Credential = credential; } } diff --git a/sdk/core/Azure.Core/src/Extensions/IAzureClientFactoryBuilderWithCredential.cs b/sdk/core/Azure.Core/src/Extensions/IAzureClientFactoryBuilderWithCredential.cs index bb6088898fc40..ac995688a66d7 100644 --- a/sdk/core/Azure.Core/src/Extensions/IAzureClientFactoryBuilderWithCredential.cs +++ b/sdk/core/Azure.Core/src/Extensions/IAzureClientFactoryBuilderWithCredential.cs @@ -7,6 +7,6 @@ namespace Azure.Core.Extensions { public interface IAzureClientFactoryBuilderWithCredential { - IAzureClientBuilder RegisterClientFactory(Func clientFactory) where TOptions: class; + IAzureClientBuilder RegisterClientFactory(Func clientFactory, bool requiresCredential = true) where TOptions: class; } } diff --git a/sdk/storage/Azure.Storage.Blobs/src/AzureClientBuilderExtensions.cs b/sdk/storage/Azure.Storage.Blobs/src/AzureClientBuilderExtensions.cs index 8b934c6d850a7..1da0f377fe2c1 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/AzureClientBuilderExtensions.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/AzureClientBuilderExtensions.cs @@ -24,9 +24,11 @@ public static IAzureClientBuilder AddBlobS /// Registers a instance with the provided /// public static IAzureClientBuilder AddBlobServiceClient(this TBuilder builder, Uri serviceUri) - where TBuilder: IAzureClientFactoryBuilder + where TBuilder: IAzureClientFactoryBuilderWithCredential { - return builder.RegisterClientFactory(options => new BlobServiceClient(serviceUri, options)); + return builder.RegisterClientFactory( + (options, token) => token != null ? new BlobServiceClient(serviceUri, token, options) : new BlobServiceClient(serviceUri, options), + requiresCredential: false); } /// diff --git a/sdk/storage/Azure.Storage.Queues/src/AzureClientBuilderExtensions.cs b/sdk/storage/Azure.Storage.Queues/src/AzureClientBuilderExtensions.cs index 159636186895a..b6bcda0dec73e 100644 --- a/sdk/storage/Azure.Storage.Queues/src/AzureClientBuilderExtensions.cs +++ b/sdk/storage/Azure.Storage.Queues/src/AzureClientBuilderExtensions.cs @@ -25,9 +25,11 @@ public static IAzureClientBuilder AddQue /// Registers a instance with the provided /// public static IAzureClientBuilder AddQueueServiceClient(this TBuilder builder, Uri serviceUri) - where TBuilder: IAzureClientFactoryBuilder + where TBuilder: IAzureClientFactoryBuilderWithCredential { - return builder.RegisterClientFactory(options => new QueueServiceClient(serviceUri, options)); + return builder.RegisterClientFactory( + (options, token) => token != null ? new QueueServiceClient(serviceUri, token, options) : new QueueServiceClient(serviceUri, options), + requiresCredential: false); } ///