From 75e796826d7a8c8161b0189e24da2cc6f27655d8 Mon Sep 17 00:00:00 2001 From: Varun Puranik Date: Fri, 16 Nov 2018 15:48:36 -0800 Subject: [PATCH] Fix getting CloudProxy when no identity exists (#548) --- .../ConnectionManager.cs | 11 +-- .../identity/ClientCredentialsFactory.cs | 30 +++---- .../identity/IIdentityProvider.cs | 11 +++ .../identity/IdentityProvider.cs | 34 +++++++ .../modules/CommonModule.cs | 2 +- .../modules/RoutingModule.cs | 7 ++ .../ClientTokenCloudConnectionTest.cs | 2 +- .../ConnectionManagerTest.cs | 88 +++++++++++++++---- .../IdentityFactoryTest.cs | 8 +- .../IdentityProviderTest.cs | 55 ++++++++++++ .../routing/RoutingEdgeHubTest.cs | 6 +- .../routing/RoutingTest.cs | 2 +- .../EdgeHubConnectionTest.cs | 5 +- .../AuthenticationMiddlewareTest.cs | 20 ++--- .../DeviceIdentityProviderTest.cs | 2 +- .../IdentityTest.cs | 2 +- 16 files changed, 221 insertions(+), 64 deletions(-) create mode 100644 edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/IIdentityProvider.cs create mode 100644 edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/IdentityProvider.cs create mode 100644 edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/IdentityProviderTest.cs diff --git a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/ConnectionManager.cs b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/ConnectionManager.cs index f2e7f1f94d5..b8dcb66c50f 100644 --- a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/ConnectionManager.cs +++ b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/ConnectionManager.cs @@ -26,6 +26,7 @@ public class ConnectionManager : IConnectionManager readonly ICloudConnectionProvider cloudConnectionProvider; readonly int maxClients; readonly ICredentialsCache credentialsCache; + readonly IIdentityProvider identityProvider; public event EventHandler CloudConnectionLost; public event EventHandler CloudConnectionEstablished; @@ -35,11 +36,13 @@ public class ConnectionManager : IConnectionManager public ConnectionManager( ICloudConnectionProvider cloudConnectionProvider, ICredentialsCache credentialsCache, + IIdentityProvider identityProvider, int maxClients = DefaultMaxClients) { this.cloudConnectionProvider = Preconditions.CheckNotNull(cloudConnectionProvider, nameof(cloudConnectionProvider)); this.maxClients = Preconditions.CheckRange(maxClients, 1, nameof(maxClients)); this.credentialsCache = Preconditions.CheckNotNull(credentialsCache, nameof(credentialsCache)); + this.identityProvider = Preconditions.CheckNotNull(identityProvider, nameof(identityProvider)); Util.Metrics.RegisterGaugeCallback(() => Metrics.SetConnectedClientCountGauge(this)); } @@ -92,13 +95,11 @@ public Option GetDeviceConnection(string id) public async Task> GetCloudConnection(string id) { - if (!this.devices.TryGetValue(Preconditions.CheckNonWhiteSpace(id, nameof(id)), out ConnectedDevice device)) - { - return Option.None(); - } + IIdentity identity = this.identityProvider.Create(Preconditions.CheckNonWhiteSpace(id, nameof(id))); + ConnectedDevice device = this.GetOrCreateConnectedDevice(identity); Try cloudConnectionTry = await device.GetOrCreateCloudConnection( - c => this.cloudConnectionProvider.Connect(c.Identity, (identity, status) => this.CloudConnectionStatusChangedHandler(identity, status))); + c => this.cloudConnectionProvider.Connect(c.Identity, (i, status) => this.CloudConnectionStatusChangedHandler(i, status))); Events.GetCloudConnection(device.Identity, cloudConnectionTry); Try cloudProxyTry = GetCloudProxyFromCloudConnection(cloudConnectionTry, device.Identity); diff --git a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/ClientCredentialsFactory.cs b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/ClientCredentialsFactory.cs index 8a115fc23c2..ae8bb166bd6 100644 --- a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/ClientCredentialsFactory.cs +++ b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/ClientCredentialsFactory.cs @@ -13,31 +13,31 @@ namespace Microsoft.Azure.Devices.Edge.Hub.Core.Identity /// public class ClientCredentialsFactory : IClientCredentialsFactory { - readonly string iotHubHostName; + readonly IIdentityProvider identityProvider; readonly string callerProductInfo; - public ClientCredentialsFactory(string iotHubHostName) - : this(iotHubHostName, string.Empty) + public ClientCredentialsFactory(IIdentityProvider identityProvider) + : this(identityProvider, string.Empty) { } - public ClientCredentialsFactory(string iotHubHostName, string callerProductInfo) + public ClientCredentialsFactory(IIdentityProvider identityProvider, string callerProductInfo) { - this.iotHubHostName = iotHubHostName; + this.identityProvider = identityProvider; this.callerProductInfo = callerProductInfo; } public IClientCredentials GetWithX509Cert(string deviceId, string moduleId, string deviceClientType) { string productInfo = string.Join(" ", this.callerProductInfo, deviceClientType).Trim(); - IIdentity identity = this.GetIdentity(deviceId, moduleId); + IIdentity identity = this.identityProvider.Create(deviceId, moduleId); return new X509CertCredentials(identity, productInfo); } public IClientCredentials GetWithSasToken(string deviceId, string moduleId, string deviceClientType, string token, bool updatable) { string productInfo = string.Join(" ", this.callerProductInfo, deviceClientType).Trim(); - IIdentity identity = this.GetIdentity(deviceId, moduleId); + IIdentity identity = this.identityProvider.Create(deviceId, moduleId); return new TokenCredentials(identity, token, productInfo, updatable); } @@ -45,21 +45,11 @@ public IClientCredentials GetWithConnectionString(string connectionString) { Preconditions.CheckNonWhiteSpace(connectionString, nameof(connectionString)); IotHubConnectionStringBuilder iotHubConnectionStringBuilder = IotHubConnectionStringBuilder.Create(connectionString); - IIdentity identity = this.GetIdentity(iotHubConnectionStringBuilder.DeviceId, iotHubConnectionStringBuilder.ModuleId); + IIdentity identity = this.identityProvider.Create(iotHubConnectionStringBuilder.DeviceId, iotHubConnectionStringBuilder.ModuleId); return new SharedKeyCredentials(identity, connectionString, this.callerProductInfo); } - public IClientCredentials GetWithIotEdged(string deviceId, string moduleId) - { - return new IotEdgedCredentials(this.GetIdentity(deviceId, moduleId), this.callerProductInfo); - } - - IIdentity GetIdentity(string deviceId, string moduleId) - { - IIdentity identity = string.IsNullOrWhiteSpace(moduleId) - ? new DeviceIdentity(this.iotHubHostName, deviceId) - : new ModuleIdentity(this.iotHubHostName, deviceId, moduleId) as IIdentity; - return identity; - } + public IClientCredentials GetWithIotEdged(string deviceId, string moduleId) => + new IotEdgedCredentials(this.identityProvider.Create(deviceId, moduleId), this.callerProductInfo); } } diff --git a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/IIdentityProvider.cs b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/IIdentityProvider.cs new file mode 100644 index 00000000000..1cadfb78ba1 --- /dev/null +++ b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/IIdentityProvider.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft. All rights reserved. + +namespace Microsoft.Azure.Devices.Edge.Hub.Core.Identity +{ + public interface IIdentityProvider + { + IIdentity Create(string id); + + IIdentity Create(string deviceId, string moduleId); + } +} diff --git a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/IdentityProvider.cs b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/IdentityProvider.cs new file mode 100644 index 00000000000..88bae09bd3d --- /dev/null +++ b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Core/identity/IdentityProvider.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All rights reserved. + +namespace Microsoft.Azure.Devices.Edge.Hub.Core.Identity +{ + using Microsoft.Azure.Devices.Edge.Util; + + public class IdentityProvider : IIdentityProvider + { + readonly string iothubHostName; + + public IdentityProvider(string iothubHostName) + { + this.iothubHostName = Preconditions.CheckNonWhiteSpace(iothubHostName, nameof(iothubHostName)); + } + + public IIdentity Create(string id) + { + // If it is a module id, it will have the format "deviceId/moduleId" + string[] parts = Preconditions.CheckNotNull(id, nameof(id)).Split('/'); + IIdentity identity = parts.Length == 2 + ? new ModuleIdentity(this.iothubHostName, parts[0], parts[1]) as IIdentity + : new DeviceIdentity(this.iothubHostName, id); + return identity; + } + + public IIdentity Create(string deviceId, string moduleId) + { + IIdentity identity = string.IsNullOrWhiteSpace(moduleId) + ? new DeviceIdentity(this.iothubHostName, deviceId) + : new ModuleIdentity(this.iothubHostName, deviceId, moduleId) as IIdentity; + return identity; + } + } +} diff --git a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Service/modules/CommonModule.cs b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Service/modules/CommonModule.cs index 46946a84c94..813415232c7 100644 --- a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Service/modules/CommonModule.cs +++ b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Service/modules/CommonModule.cs @@ -250,7 +250,7 @@ protected override void Load(ContainerBuilder builder) .SingleInstance(); // IClientCredentialsFactory - builder.Register(c => new ClientCredentialsFactory(this.iothubHostName, this.productInfo)) + builder.Register(c => new ClientCredentialsFactory(c.Resolve(), this.productInfo)) .As() .SingleInstance(); diff --git a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Service/modules/RoutingModule.cs b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Service/modules/RoutingModule.cs index 6951c6340f0..720666fc526 100644 --- a/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Service/modules/RoutingModule.cs +++ b/edge-hub/src/Microsoft.Azure.Devices.Edge.Hub.Service/modules/RoutingModule.cs @@ -190,17 +190,24 @@ protected override void Load(ContainerBuilder builder) .As>() .SingleInstance(); + // IIdentityProvider + builder.Register(_ => new IdentityProvider(this.iotHubName)) + .As() + .SingleInstance(); + // Task builder.Register( async c => { var cloudConnectionProviderTask = c.Resolve>(); var credentialsCacheTask = c.Resolve>(); + var identityProvider = c.Resolve(); ICloudConnectionProvider cloudConnectionProvider = await cloudConnectionProviderTask; ICredentialsCache credentialsCache = await credentialsCacheTask; IConnectionManager connectionManager = new ConnectionManager( cloudConnectionProvider, credentialsCache, + identityProvider, this.maxConnectedClients); return connectionManager; }) diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.CloudProxy.Test/ClientTokenCloudConnectionTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.CloudProxy.Test/ClientTokenCloudConnectionTest.cs index be4c28b6a1a..c9beb271d31 100644 --- a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.CloudProxy.Test/ClientTokenCloudConnectionTest.cs +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.CloudProxy.Test/ClientTokenCloudConnectionTest.cs @@ -411,7 +411,7 @@ IClient GetMockedDeviceClient() Mock.Of(i => i.Id == $"{deviceId}/$edgeHub"), TimeSpan.FromMinutes(60), true); cloudConnectionProvider.BindEdgeHub(Mock.Of()); - IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, Mock.Of()); + IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, Mock.Of(), new IdentityProvider(hostname)); ITokenCredentials clientCredentials1 = GetClientCredentials(TimeSpan.FromSeconds(10)); Try cloudProxyTry1 = await connectionManager.CreateCloudConnectionAsync(clientCredentials1); diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/ConnectionManagerTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/ConnectionManagerTest.cs index 816f2fed7e6..43ca7b16f65 100644 --- a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/ConnectionManagerTest.cs +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/ConnectionManagerTest.cs @@ -21,14 +21,15 @@ public class ConnectionManagerTest const string DummyToken = "abc"; const string EdgeDeviceId = "testEdgeDeviceId"; const string EdgeModuleId = "$edgeHub"; + const string IotHubHostName = "foo.azure-devices.net"; [Fact] [Integration] public async Task DeviceConnectionTest() { var cloudProviderMock = new Mock(); - var credentialsManager = Mock.Of(); - IConnectionManager connectionManager = new ConnectionManager(cloudProviderMock.Object, credentialsManager); + var credentialsManager = Mock.Of(); + IConnectionManager connectionManager = new ConnectionManager(cloudProviderMock.Object, credentialsManager, GetIdentityProvider()); var deviceProxyMock1 = new Mock(); deviceProxyMock1.SetupGet(dp => dp.IsActive).Returns(true); @@ -83,7 +84,7 @@ public async Task CloudConnectionTest() var deviceCredentials2 = Mock.Of(c => c.Identity == Mock.Of(d => d.Id == "Device2")); var credentialsManager = Mock.Of(); - IConnectionManager connectionManager = new ConnectionManager(cloudProviderMock.Object, credentialsManager); + IConnectionManager connectionManager = new ConnectionManager(cloudProviderMock.Object, credentialsManager, GetIdentityProvider()); Option returnedValue = await connectionManager.GetCloudConnection(deviceCredentials1.Identity.Id); Assert.False(returnedValue.HasValue); @@ -125,7 +126,7 @@ public async Task MutipleModulesConnectionTest() var credentialsManager = Mock.Of(); - var connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsManager); + var connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsManager, GetIdentityProvider()); Try module1CloudProxy = await connectionManager.CreateCloudConnectionAsync(module1Credentials); Assert.True(module1CloudProxy.Success); Assert.NotNull(module1CloudProxy.Value); @@ -179,7 +180,7 @@ public async Task TestAddRemoveDeviceConnectionTest() TimeSpan.FromMinutes(60), true); cloudConnectionProvider.BindEdgeHub(edgeHub.Object); - IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsManager); + IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsManager, GetIdentityProvider()); Try cloudProxyTry = await connectionManager.CreateCloudConnectionAsync(deviceCredentials); Assert.True(cloudProxyTry.Success); var deviceListener = new DeviceMessageHandler(deviceCredentials.Identity, edgeHub.Object, connectionManager); @@ -233,7 +234,7 @@ public async Task GetOrCreateCloudProxyTest() .ReturnsAsync(() => Try.Success(cloudConnectionMock2)); var credentialsCache = Mock.Of(); - var connectionManager = new ConnectionManager(cloudProxyProviderMock.Object, credentialsCache); + var connectionManager = new ConnectionManager(cloudProxyProviderMock.Object, credentialsCache, GetIdentityProvider()); Task> getCloudProxyTask1 = connectionManager.GetOrCreateCloudConnectionAsync(module1Credentials); Task> getCloudProxyTask2 = connectionManager.GetOrCreateCloudConnectionAsync(module2Credentials); @@ -274,7 +275,7 @@ public async Task CreateCloudProxyTest() var cloudConnectionProvider = new CloudConnectionProvider(messageConverterProvider, 1, deviceClientProvider.Object, Option.None(), Mock.Of(), Mock.Of(), credentialsCache, edgeHubIdentity, TimeSpan.FromMinutes(60), true); cloudConnectionProvider.BindEdgeHub(Mock.Of()); - IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache); + IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache, GetIdentityProvider()); Task> getCloudProxyTask1 = connectionManager.CreateCloudConnectionAsync(module1Credentials); Task> getCloudProxyTask2 = connectionManager.CreateCloudConnectionAsync(module1Credentials); @@ -322,7 +323,7 @@ public async Task CloudProxyCallbackTest() var credentialsCache = new Mock(MockBehavior.Strict); credentialsCache.Setup(c => c.Get(identity)).ReturnsAsync(Option.None()); - var connectionManager = new ConnectionManager(cloudProxyProviderMock.Object, credentialsCache.Object); + var connectionManager = new ConnectionManager(cloudProxyProviderMock.Object, credentialsCache.Object, GetIdentityProvider()); await connectionManager.AddDeviceConnection(deviceCredentials.Identity, deviceProxy.Object); Try cloudProxyTry = await connectionManager.GetOrCreateCloudConnectionAsync(deviceCredentials); @@ -359,7 +360,7 @@ public async Task CloudProxyCallbackTest2() var credentialsCache = new Mock(MockBehavior.Strict); credentialsCache.Setup(c => c.Get(deviceIdentity)).ReturnsAsync(Option.Some((IClientCredentials)updatedDeviceCredentials)); - var connectionManager = new ConnectionManager(cloudProxyProviderMock.Object, credentialsCache.Object); + var connectionManager = new ConnectionManager(cloudProxyProviderMock.Object, credentialsCache.Object, GetIdentityProvider()); await connectionManager.AddDeviceConnection(deviceCredentials.Identity, deviceProxy.Object); Try cloudProxyTry = await connectionManager.GetOrCreateCloudConnectionAsync(deviceCredentials); @@ -390,7 +391,7 @@ public async Task CloudConnectionUpdateTest() var cloudConnectionProvider = new CloudConnectionProvider(messageConverterProvider, 1, deviceClientProvider.Object, Option.None(), Mock.Of(), Mock.Of(), credentialsCache, edgeHubIdentity, TimeSpan.FromMinutes(60), true); cloudConnectionProvider.BindEdgeHub(Mock.Of()); - IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache); + IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache, GetIdentityProvider()); string token1 = TokenHelper.CreateSasToken("foo.azure-devices.net", DateTime.UtcNow.AddHours(2)); var deviceCredentials = new TokenCredentials(new DeviceIdentity("iotHub", "Device1"), token1, DummyProductInfo, true); @@ -435,7 +436,7 @@ public async Task CloudConnectionInvalidUpdateTest() var cloudConnectionProvider = new CloudConnectionProvider(messageConverterProvider, 1, deviceClientProvider.Object, Option.None(), Mock.Of(), Mock.Of(), credentialsCache, edgeHubIdentity, TimeSpan.FromMinutes(60), true); cloudConnectionProvider.BindEdgeHub(Mock.Of()); - IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache); + IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache, GetIdentityProvider()); string token1 = TokenHelper.CreateSasToken("foo.azure-devices.net", DateTime.UtcNow.AddHours(2)); var deviceCredentials1 = new TokenCredentials(new DeviceIdentity("iotHub", "Device1"), token1, DummyProductInfo, true); @@ -476,7 +477,7 @@ public async Task MaxClientsTest() var deviceProxy3 = Mock.Of(d => d.IsActive); var credentialsCache = Mock.Of(); - var connectionManager = new ConnectionManager(cloudProviderMock.Object, credentialsCache, 2); + var connectionManager = new ConnectionManager(cloudProviderMock.Object, credentialsCache, GetIdentityProvider(), 2); await connectionManager.AddDeviceConnection(deviceIdentity1, deviceProxy1); await connectionManager.AddDeviceConnection(deviceIdentity2, deviceProxy2); @@ -491,7 +492,7 @@ public async Task AddRemoveSubscriptionsTest() string deviceId = "d1"; var cloudConnectionProvider = Mock.Of(); var credentialsCache = Mock.Of(); - var connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache); + var connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache, GetIdentityProvider()); var identity = Mock.Of(i => i.Id == deviceId); // Act @@ -537,7 +538,7 @@ public async Task KeepSubscriptionsOnDeviceRemoveTest() string deviceId = "d1"; var cloudConnectionProvider = Mock.Of(); var credentialsCache = Mock.Of(); - var connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache); + var connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache, GetIdentityProvider()); var identity = Mock.Of(i => i.Id == deviceId); bool isProxyActive = true; // ReSharper disable once PossibleUnintendedReferenceComparison @@ -617,7 +618,7 @@ public async Task GetConnectedClientsTest() // Arrange var cloudConnectionProvider = Mock.Of(); var credentialsCache = Mock.Of(); - var connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache); + var connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache, GetIdentityProvider()); var deviceProxies = new List(); for (int i = 0; i < 10; i++) @@ -672,6 +673,61 @@ public async Task GetConnectedClientsTest() } } + [Fact] + [Unit] + public async Task GetCloudProxyTest() + { + // Arrange + string edgeDeviceId = "edgeDevice"; + string module1Id = "module1"; + string iotHub = "foo.azure-devices.net"; + string token = TokenHelper.CreateSasToken(iotHub); + var module1Credentials = new TokenCredentials(new ModuleIdentity(iotHub, edgeDeviceId, module1Id), token, DummyProductInfo, true); + + IClient client1 = GetDeviceClient(); + IClient client2 = GetDeviceClient(); + var messageConverterProvider = Mock.Of(); + var deviceClientProvider = new Mock(); + deviceClientProvider.SetupSequence(d => d.Create(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(client1) + .Returns(client2); + + ICredentialsCache credentialsCache = new CredentialsCache(new NullCredentialsCache()); + await credentialsCache.Add(module1Credentials); + + var cloudConnectionProvider = new CloudConnectionProvider( + messageConverterProvider, + 1, + deviceClientProvider.Object, + Option.None(), + Mock.Of(), + Mock.Of(), + credentialsCache, + new ModuleIdentity(iotHub, edgeDeviceId, "$edgeHub"), + TimeSpan.FromMinutes(60), + true); + cloudConnectionProvider.BindEdgeHub(Mock.Of()); + IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, credentialsCache, GetIdentityProvider()); + + // Act + Option getCloudProxyTask = await connectionManager.GetCloudConnection(module1Credentials.Identity.Id); + + // Assert + Assert.True(getCloudProxyTask.HasValue); + Assert.True(getCloudProxyTask.OrDefault().IsActive); + + // Act + await getCloudProxyTask.OrDefault().CloseAsync(); + Option newCloudProxyTask1 = await connectionManager.GetCloudConnection(module1Credentials.Identity.Id); + + // Assert + Assert.True(newCloudProxyTask1.HasValue); + Assert.NotEqual(newCloudProxyTask1.OrDefault(), getCloudProxyTask.OrDefault()); + + Mock.Get(client1).Verify(cp => cp.CloseAsync(), Times.Once); + Mock.Get(client2).Verify(cp => cp.CloseAsync(), Times.Never); + } + static ICloudConnection GetCloudConnectionMock() { ICloudProxy cloudProxyMock = GetCloudProxyMock(); @@ -712,5 +768,7 @@ static IClient GetDeviceClient() deviceClient.Setup(dc => dc.OpenAsync()).Returns(Task.CompletedTask); return deviceClient.Object; } + + static IIdentityProvider GetIdentityProvider() => new IdentityProvider(IotHubHostName); } } diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/IdentityFactoryTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/IdentityFactoryTest.cs index 28fc92f48a2..0e2e88811a4 100644 --- a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/IdentityFactoryTest.cs +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/IdentityFactoryTest.cs @@ -19,7 +19,7 @@ public void GetWithConnectionStringTest_Device() string key = GetRandomString(44); string deviceConnectionstring = $"HostName={iotHubHostName};DeviceId={deviceId};SharedAccessKey={key}"; - IClientCredentialsFactory identityFactory = new ClientCredentialsFactory(iotHubHostName); + IClientCredentialsFactory identityFactory = new ClientCredentialsFactory(new IdentityProvider(iotHubHostName)); IClientCredentials identityTry = identityFactory.GetWithConnectionString(deviceConnectionstring); Assert.NotNull(identityTry); IIdentity identity = identityTry.Identity; @@ -38,7 +38,7 @@ public void GetWithConnectionStringTest_Module() string key = GetRandomString(44); string deviceConnectionstring = $"HostName={iotHubHostName};DeviceId={deviceId};ModuleId={moduleId};SharedAccessKey={key}"; - IClientCredentialsFactory identityFactory = new ClientCredentialsFactory(iotHubHostName); + IClientCredentialsFactory identityFactory = new ClientCredentialsFactory(new IdentityProvider(iotHubHostName)); IClientCredentials identityTry = identityFactory.GetWithConnectionString(deviceConnectionstring); Assert.NotNull(identityTry); var identity = identityTry.Identity as IModuleIdentity; @@ -64,7 +64,7 @@ public void GetSasIdentityTest() string callerProductInfo = "productInfo"; string sasToken = TokenHelper.CreateSasToken($"{iothubHostName}/devices/device1/modules/moduleId"); - var identityFactory = new ClientCredentialsFactory(iothubHostName, callerProductInfo); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName), callerProductInfo); // device test string deviceId = "device1"; @@ -98,7 +98,7 @@ public void GetX509IdentityTest() string deviceId = "device1"; string moduleId = "module1"; string deviceClientType = "customDeviceClient1"; - var identityFactory = new ClientCredentialsFactory(iothubHostName, callerProductInfo); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName), callerProductInfo); // device test IClientCredentials identityTry1 = identityFactory.GetWithX509Cert(deviceId, null, deviceClientType); diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/IdentityProviderTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/IdentityProviderTest.cs new file mode 100644 index 00000000000..9c1a65a7c43 --- /dev/null +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/IdentityProviderTest.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft. All rights reserved. + +namespace Microsoft.Azure.Devices.Edge.Hub.Core.Test +{ + using System.Collections.Generic; + using Microsoft.Azure.Devices.Edge.Hub.Core.Identity; + using Microsoft.Azure.Devices.Edge.Util.Test.Common; + using Xunit; + + [Unit] + public class IdentityProviderTest + { + [Theory] + [MemberData(nameof(GetCreateTestParameters1))] + public void CreateTest(string iothubHostName, string id, IIdentity expectedIdentity) + { + // Arrange + var identityProvider = new IdentityProvider(iothubHostName); + + // Act + IIdentity identity = identityProvider.Create(id); + + // Assert + Assert.Equal(expectedIdentity, identity); + Assert.Equal(expectedIdentity.GetType(), identity.GetType()); + } + + [Theory] + [MemberData(nameof(GetCreateTestParameters2))] + public void CreateTest(string iothubHostName, string deviceId, string moduleId, IIdentity expectedIdentity) + { + // Arrange + var identityProvider = new IdentityProvider(iothubHostName); + + // Act + IIdentity identity = identityProvider.Create(deviceId, moduleId); + + // Assert + Assert.Equal(expectedIdentity, identity); + Assert.Equal(expectedIdentity.GetType(), identity.GetType()); + } + + static IEnumerable GetCreateTestParameters1() + { + yield return new object[] { "foo.azure-device.net", "d1", new DeviceIdentity("foo.azure-device.net", "d1") }; + yield return new object[] { "foo.azure-device.net", "d1/m1", new ModuleIdentity("foo.azure-device.net", "d1", "m1") }; + } + + static IEnumerable GetCreateTestParameters2() + { + yield return new object[] { "foo.azure-device.net", "d1", string.Empty, new DeviceIdentity("foo.azure-device.net", "d1") }; + yield return new object[] { "foo.azure-device.net", "d1", "m1", new ModuleIdentity("foo.azure-device.net", "d1", "m1") }; + } + } +} diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/routing/RoutingEdgeHubTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/routing/RoutingEdgeHubTest.cs index 8da8238170e..f4d3ced868b 100644 --- a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/routing/RoutingEdgeHubTest.cs +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/routing/RoutingEdgeHubTest.cs @@ -249,7 +249,7 @@ public async Task InvokeMethodAsyncTest() var cloudConnectionProvider = new Mock(); cloudConnectionProvider.Setup(c => c.Connect(It.IsAny(), It.IsAny>())) .ReturnsAsync(Try.Success(cloudConnection)); - var connectionManager = new ConnectionManager(cloudConnectionProvider.Object, Mock.Of()); + var connectionManager = new ConnectionManager(cloudConnectionProvider.Object, Mock.Of(), new IdentityProvider("myIotHub")); IInvokeMethodHandler invokeMethodHandler = new InvokeMethodHandler(connectionManager); @@ -323,7 +323,7 @@ public async Task InvokeMethodNoSubscriptionTest() var cloudConnectionProvider = new Mock(); cloudConnectionProvider.Setup(c => c.Connect(It.IsAny(), It.IsAny>())) .ReturnsAsync(Try.Success(cloudConnection)); - var connectionManager = new ConnectionManager(cloudConnectionProvider.Object, Mock.Of()); + var connectionManager = new ConnectionManager(cloudConnectionProvider.Object, Mock.Of(), new IdentityProvider("myIotHub")); IInvokeMethodHandler invokeMethodHandler = new InvokeMethodHandler(connectionManager); @@ -390,7 +390,7 @@ public async Task InvokeMethodLateSubscriptionTest() var cloudConnectionProvider = new Mock(); cloudConnectionProvider.Setup(c => c.Connect(It.IsAny(), It.IsAny>())) .ReturnsAsync(Try.Success(cloudConnection)); - var connectionManager = new ConnectionManager(cloudConnectionProvider.Object, Mock.Of()); + var connectionManager = new ConnectionManager(cloudConnectionProvider.Object, Mock.Of(), new IdentityProvider("myIotHub")); IInvokeMethodHandler invokeMethodHandler = new InvokeMethodHandler(connectionManager); diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/routing/RoutingTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/routing/RoutingTest.cs index 37832e2a1f4..f8f79ad3954 100644 --- a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/routing/RoutingTest.cs +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Core.Test/routing/RoutingTest.cs @@ -426,7 +426,7 @@ public async Task TestRoutingTwinChangeNotificationFromModule() var cloudConnectionProvider = new Mock(); cloudConnectionProvider.Setup(c => c.Connect(It.IsAny(), It.IsAny>())).ReturnsAsync(Try.Success(cloudConnection)); - IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider.Object, Mock.Of()); + IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider.Object, Mock.Of(), new IdentityProvider(iotHubName)); var routingMessageConverter = new RoutingMessageConverter(); RouteFactory routeFactory = new EdgeRouteFactory(new EndpointFactory(connectionManager, routingMessageConverter, edgeDeviceId)); IEnumerable routesList = routeFactory.Create(routes).ToList(); diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.E2E.Test/EdgeHubConnectionTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.E2E.Test/EdgeHubConnectionTest.cs index 5d3f2bf3d20..97fe889d623 100644 --- a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.E2E.Test/EdgeHubConnectionTest.cs +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.E2E.Test/EdgeHubConnectionTest.cs @@ -50,7 +50,8 @@ public async Task TestEdgeHubConnection() await registryManager.OpenAsync(); string iothubHostName = iotHubConnectionStringBuilder.HostName; - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityProvider = new IdentityProvider(iothubHostName); + var identityFactory = new ClientCredentialsFactory(identityProvider); (string edgeDeviceId, string deviceConnStr) = await RegistryManagerHelper.CreateDevice(EdgeDeviceId, iotHubConnectionString, registryManager, true, false); string edgeHubConnectionString = $"{deviceConnStr};ModuleId={EdgeHubModuleId}"; @@ -68,7 +69,7 @@ public async Task TestEdgeHubConnection() edgeHubCredentials.Identity, TimeSpan.FromMinutes(60), true); - var connectionManager = new ConnectionManager(cloudConnectionProvider, Mock.Of()); + var connectionManager = new ConnectionManager(cloudConnectionProvider, Mock.Of(), identityProvider); try { diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Http.Test/AuthenticationMiddlewareTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Http.Test/AuthenticationMiddlewareTest.cs index 9b314a0c286..7d664fbf1de 100644 --- a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Http.Test/AuthenticationMiddlewareTest.cs +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Http.Test/AuthenticationMiddlewareTest.cs @@ -32,7 +32,7 @@ public async Task AuthenticateRequestTest_Success() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(true); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, deviceId); (bool success, string message) result = await authenticationMiddleware.AuthenticateRequest(httpContext); @@ -54,7 +54,7 @@ public async Task InvalidAuthenticateRequestTest_NoAuthHeader() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(true); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, deviceId); (bool success, string message) result = await authenticationMiddleware.AuthenticateRequest(httpContext); @@ -77,7 +77,7 @@ public async Task InvalidAuthenticateRequestTest_MultipleAuthHeaders() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(true); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, deviceId); (bool success, string message) result = await authenticationMiddleware.AuthenticateRequest(httpContext); @@ -100,7 +100,7 @@ public async Task InvalidAuthenticateRequestTest_InvalidToken() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(true); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, deviceId); (bool success, string message) result = await authenticationMiddleware.AuthenticateRequest(httpContext); @@ -124,7 +124,7 @@ public async Task InvalidAuthenticateRequestTest_TokenExpired() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(true); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, deviceId); (bool success, string message) result = await authenticationMiddleware.AuthenticateRequest(httpContext); @@ -147,7 +147,7 @@ public async Task InvalidAuthenticateRequestTest_NoModuleId() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(true); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, deviceId); (bool success, string message) result = await authenticationMiddleware.AuthenticateRequest(httpContext); @@ -170,7 +170,7 @@ public async Task AuthenticateRequestTest_NoApiVersion_Success() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(true); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, deviceId); (bool success, string message) result = await authenticationMiddleware.AuthenticateRequest(httpContext); @@ -194,7 +194,7 @@ public async Task InvalidCredentialsRequestTest_AuthFailed() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(false); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, deviceId); (bool success, string message) result = await authenticationMiddleware.AuthenticateRequest(httpContext); @@ -218,7 +218,7 @@ public async Task InvalidInvokeTest_ExceptionNotCaught() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).Throws(); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, deviceId); await Assert.ThrowsAsync(() => authenticationMiddleware.Invoke(httpContext)); @@ -240,7 +240,7 @@ public async Task InvalidAuthenticateRequestTest_InvalidDeviceId() var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(true); - var identityFactory = new ClientCredentialsFactory(iothubHostName); + var identityFactory = new ClientCredentialsFactory(new IdentityProvider(iothubHostName)); var authenticationMiddleware = new AuthenticationMiddleware(Mock.Of(), Task.FromResult(authenticator.Object), identityFactory, iothubHostName, edgeDeviceId); (bool success, string message) result = await authenticationMiddleware.AuthenticateRequest(httpContext); diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Mqtt.Test/DeviceIdentityProviderTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Mqtt.Test/DeviceIdentityProviderTest.cs index b5f53c013d0..c2b085fc321 100644 --- a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Mqtt.Test/DeviceIdentityProviderTest.cs +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Mqtt.Test/DeviceIdentityProviderTest.cs @@ -61,7 +61,7 @@ public async Task GetDeviceIdentityTest( var authenticator = new Mock(); authenticator.Setup(a => a.AuthenticateAsync(It.IsAny())).ReturnsAsync(authRetVal); - IDeviceIdentityProvider deviceIdentityProvider = new DeviceIdentityProvider(authenticator.Object, new ClientCredentialsFactory(iotHubHostName), false); + IDeviceIdentityProvider deviceIdentityProvider = new DeviceIdentityProvider(authenticator.Object, new ClientCredentialsFactory(new IdentityProvider(iotHubHostName)), false); IDeviceIdentity deviceIdentity = await deviceIdentityProvider.GetAsync(clientId, username, password, null); Assert.IsAssignableFrom(expectedType, deviceIdentity); } diff --git a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Mqtt.Test/IdentityTest.cs b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Mqtt.Test/IdentityTest.cs index 959186eddd3..495b5852dd6 100644 --- a/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Mqtt.Test/IdentityTest.cs +++ b/edge-hub/test/Microsoft.Azure.Devices.Edge.Hub.Mqtt.Test/IdentityTest.cs @@ -307,7 +307,7 @@ public async Task GetModuleIdentityTest(string value, static async Task GetClientCredentials(string iotHubHostName, string deviceId, string userName, string token, bool isCertAuthAllowed = false, string productInfo = "") { var authenticator = Mock.Of(a => a.AuthenticateAsync(It.IsAny()) == Task.FromResult(true)); - var factory = new ClientCredentialsFactory(iotHubHostName, productInfo); + var factory = new ClientCredentialsFactory(new IdentityProvider(iotHubHostName), productInfo); var sasTokenIdentityProvider = new DeviceIdentityProvider(authenticator, factory, isCertAuthAllowed); ProtocolGateway.Identity.IDeviceIdentity deviceIdentity = await sasTokenIdentityProvider.GetAsync(deviceId, userName, token, null);