Skip to content

Commit 12d4c5f

Browse files
committed
Add better error handling for API management URI support.
1 parent 6a29dce commit 12d4c5f

4 files changed

Lines changed: 94 additions & 34 deletions

File tree

src/VirtualClient/VirtualClient.Core.UnitTests/DependencyFactoryTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,20 @@ public void DependencyFactoryCreatesTheExpectedBlobManagerForApiManagementEndpoi
340340
Assert.AreEqual(blobManager.RestClient.DefaultRequestHeaders.GetValues(RequestHeader.OcpApimSubscriptionKey).FirstOrDefault(), expectedSubscriptionKey);
341341
}
342342

343+
[Test]
344+
public void DependencyFactoryThrowsIfTheSubscriptionKeyIsNotDefinedWhenCreatingABlobManagerForApiManagementEndpoints()
345+
{
346+
// Setup:
347+
// API management subscription key is NOT defined in the environment variables.
348+
SchemaException error = Assert.Throws<SchemaException>(() => DependencyFactory.CreateBlobManager(
349+
DependencyStore.Packages,
350+
"\"https://any.azure-api.net",
351+
this.mockFixture.CertificateManager.Object,
352+
this.mockFixture.PlatformSpecifics));
353+
354+
Assert.IsTrue(error.Message.StartsWith("Required API key not defined. The URI provided for the blob store is an Azure API management endpoint"));
355+
}
356+
343357
[Test]
344358
[TestCase("https://any.api.proxy", "https://any.api.proxy/")]
345359
[TestCase("https://any.api.proxy:9876", "https://any.api.proxy:9876/")]
@@ -578,6 +592,20 @@ public void DependencyFactoryCreatesTheExpectedEventHubTelemetryChannelForApiMan
578592
Assert.AreEqual(telemetryChannel.RestClient.DefaultRequestHeaders.GetValues(RequestHeader.OcpApimSubscriptionKey).FirstOrDefault(), expectedSubscriptionKey);
579593
}
580594

595+
[Test]
596+
public void DependencyFactoryThrowsIfTheSubscriptionKeyIsNotDefinedWhenCreatingAnEventHubTelemetryChannelForApiManagementEndpoints()
597+
{
598+
// Setup:
599+
// API management subscription key is NOT defined in the environment variables.
600+
SchemaException error = Assert.Throws<SchemaException>(() => DependencyFactory.CreateEventHubTelemetryChannel(
601+
"https://any.azure-api.net",
602+
"any-hub",
603+
this.mockFixture.CertificateManager.Object,
604+
this.mockFixture.PlatformSpecifics));
605+
606+
Assert.IsTrue(error.Message.StartsWith("Required API key not defined. The URI provided for the Event Hub is an Azure API management endpoint"));
607+
}
608+
581609
[Test]
582610
[TestCase("Endpoint=sb://any.servicebus.windows.net/;SharedAccessKeyName=AnyAccessPolicy;SharedAccessKey=123", "https://any.proxy.net")]
583611
[TestCase("EndpointUrl=sb://any.servicebus.windows.net;ClientId=11223344;TenantId=55667788;CertificateThumbprint=123456789", "https://any.azure-api.net:9876")]

src/VirtualClient/VirtualClient.Core.UnitTests/EndpointUtilityTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ public void Initialize()
2222
this.mockFixture.SetupCertificateMocks();
2323
}
2424

25+
[Test]
26+
[TestCase("https://any.azure-api.net")]
27+
[TestCase("https://any.azure-api.net/")]
28+
[TestCase("https://any.azure-api.net/any-container")]
29+
public void EndpointUtilityConfirmsApiManagementUris(string uri)
30+
{
31+
Assert.IsTrue(EndpointUtility.IsApiManagementUri(new Uri(uri)));
32+
}
33+
34+
[Test]
35+
[TestCase("https://anystorage.blob.core.windows.net")]
36+
[TestCase("https://any.servicebus.windows.net")]
37+
[TestCase("https://packages.virtualclient.microsoft.com")]
38+
public void EndpointUtilityConfirmsNonApiManagementUris(string uri)
39+
{
40+
Assert.IsFalse(EndpointUtility.IsApiManagementUri(new Uri(uri)));
41+
}
42+
2543
[Test]
2644
[TestCase("EndpointUrl=https://anystorage.blob.core.windows.net;ManagedIdentityId=307591a4-abb2-4559-af59-b47177d140cf")]
2745
[TestCase("EventHubNamespace=any.servicebus.windows.net;ManagedIdentityId=307591a4-abb2-4559-af59-b47177d140cf")]

src/VirtualClient/VirtualClient.Core/DependencyFactory.cs

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -952,30 +952,34 @@ private static IBlobManager CreateBlobManager(string storeName, Uri endpointUri,
952952
var store = new DependencyBlobStore(storeName, endpointUri);
953953
blobManager = new BlobManager(store);
954954
}
955-
else
955+
else if (EndpointUtility.IsApiManagementUri(endpointUri))
956956
{
957-
// Basic URI
958-
// e.g.
959-
// https://any.blob.core.windows.net
960-
//
961957
// API management
962958
// e.g.
963959
// https://any.azure-api.net
964960
var store = new DependencyBlobStore(storeName, endpointUri, DependencyStore.StoreTypeProxy);
965961

966962
// Check for API management support.
967963
string subscriptionKey = platformSpecifics.GetEnvironmentVariable(EnvironmentVariable.VC_APIM_SUBSCRIPTION_KEY);
968-
if (!string.IsNullOrWhiteSpace(subscriptionKey))
964+
if (string.IsNullOrWhiteSpace(subscriptionKey))
969965
{
970-
HttpClient restClient = new HttpClient();
971-
restClient.Timeout = Timeout.InfiniteTimeSpan;
972-
restClient.DefaultRequestHeaders.Add(RequestHeader.OcpApimSubscriptionKey, subscriptionKey);
973-
blobManager = new BlobManager(store, restClient);
974-
}
975-
else
976-
{
977-
blobManager = new BlobManager(store);
966+
throw new SchemaException(
967+
$"Required API key not defined. The URI provided for the blob store is an Azure API management endpoint but the required subscription/API key is not defined." +
968+
$"Set the '{EnvironmentVariable.VC_APIM_SUBSCRIPTION_KEY}' environment variable to the appropriate key value before executing the application.");
978969
}
970+
971+
HttpClient restClient = new HttpClient();
972+
restClient.Timeout = Timeout.InfiniteTimeSpan;
973+
restClient.DefaultRequestHeaders.Add(RequestHeader.OcpApimSubscriptionKey, subscriptionKey);
974+
blobManager = new BlobManager(store, restClient);
975+
}
976+
else
977+
{
978+
// Basic URI
979+
// e.g.
980+
// https://any.blob.core.windows.net
981+
var store = new DependencyBlobStore(storeName, endpointUri, DependencyStore.StoreTypeProxy);
982+
blobManager = new BlobManager(store);
979983
}
980984

981985
return blobManager;
@@ -1114,28 +1118,31 @@ private static EventHubTelemetryChannel CreateEventHubTelemetryChannel(string ev
11141118
channel = new EventHubTelemetryChannel(client, enableDiagnostics: true);
11151119
}
11161120
}
1117-
else
1121+
else if (EndpointUtility.IsApiManagementUri(endpointUri))
11181122
{
1119-
// Check for API management targeting.
1123+
// Check for API management support.
11201124
string subscriptionKey = platformSpecifics.GetEnvironmentVariable(EnvironmentVariable.VC_APIM_SUBSCRIPTION_KEY);
1121-
1122-
if (!string.IsNullOrWhiteSpace(subscriptionKey))
1125+
if (string.IsNullOrWhiteSpace(subscriptionKey))
11231126
{
1124-
// Supports the use of Azure API Management as a gateway for Event Hub traffic. This allows clients to use a secure API endpoint to route traffic to the
1125-
// Event Hub namespace (vs. a direct connection).
1126-
HttpClient restClient = new HttpClient();
1127-
Uri baseUri = new Uri(endpointUri, eventHubName);
1127+
throw new SchemaException(
1128+
$"Required API key not defined. The URI provided for the Event Hub is an Azure API management endpoint but the required subscription/API key is not defined." +
1129+
$"Set the '{EnvironmentVariable.VC_APIM_SUBSCRIPTION_KEY}' environment variable to the appropriate key value before executing the application.");
1130+
}
11281131

1129-
if (!string.IsNullOrWhiteSpace(endpointUri.Query))
1130-
{
1131-
baseUri = new Uri($"{baseUri.AbsoluteUri}{endpointUri.Query}");
1132-
}
1132+
// Supports the use of Azure API Management as a gateway for Event Hub traffic. This allows clients to use a secure API endpoint to route traffic to the
1133+
// Event Hub namespace (vs. a direct connection).
1134+
HttpClient restClient = new HttpClient();
1135+
Uri baseUri = new Uri(endpointUri, eventHubName);
11331136

1134-
restClient.BaseAddress = baseUri;
1135-
restClient.Timeout = Timeout.InfiniteTimeSpan;
1136-
restClient.DefaultRequestHeaders.Add(RequestHeader.OcpApimSubscriptionKey, subscriptionKey);
1137-
channel = new EventHubTelemetryChannel(restClient, enableDiagnostics: true);
1137+
if (!string.IsNullOrWhiteSpace(endpointUri.Query))
1138+
{
1139+
baseUri = new Uri($"{baseUri.AbsoluteUri}{endpointUri.Query}");
11381140
}
1141+
1142+
restClient.BaseAddress = baseUri;
1143+
restClient.Timeout = Timeout.InfiniteTimeSpan;
1144+
restClient.DefaultRequestHeaders.Add(RequestHeader.OcpApimSubscriptionKey, subscriptionKey);
1145+
channel = new EventHubTelemetryChannel(restClient, enableDiagnostics: true);
11391146
}
11401147

11411148
return channel;

src/VirtualClient/VirtualClient.Core/EndpointUtility.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ namespace VirtualClient
77
using System.Collections.Generic;
88
using System.Linq;
99
using System.Text.RegularExpressions;
10-
using Azure.Core;
11-
using Azure.Identity;
12-
using VirtualClient.Common.Extensions;
1310
using VirtualClient.Contracts;
14-
using VirtualClient.Identity;
1511

1612
/// <summary>
1713
/// Provides features for managing requirements for remote endpoint access.
@@ -20,6 +16,17 @@ public static class EndpointUtility
2016
{
2117
internal const string DefaultPackageStoreUri = "https://packages.virtualclient.microsoft.com";
2218

19+
/// <summary>
20+
/// Returns true/false whether the value is a standard API management URI
21+
/// (e.g. https://any.azure-api.net).
22+
/// </summary>
23+
/// <param name="endpointUri">The URI to evaluate.</param>
24+
/// <returns>True if the value is a Key Vault URI. False if not.</returns>
25+
public static bool IsApiManagementUri(Uri endpointUri)
26+
{
27+
return Regex.IsMatch(endpointUri.AbsoluteUri, "azure-api.net", RegexOptions.IgnoreCase);
28+
}
29+
2330
/// <summary>
2431
/// Returns true/false whether the value is a custom Virtual Client connection string
2532
/// (e.g. EndpointUrl=https://any.blob.core.windows.net;ManagedIdentityId=307591a4-abb2-4559-af59-b47177d140cf).

0 commit comments

Comments
 (0)