public async Task GetServiceIdentityFromServiceTest()
        {
            // Arrange
            var store = GetEntityStore("cache");
            var serviceAuthenticationNone = new ServiceAuthentication(ServiceAuthenticationType.None);
            var serviceAuthenticationSas  = new ServiceAuthentication(new SymmetricKeyAuthentication(GetKey(), GetKey()));

            var si_device = new ServiceIdentity("d2", "1234", Enumerable.Empty <string>(), serviceAuthenticationNone, ServiceIdentityStatus.Enabled);
            var si_module = new ServiceIdentity("d1", "m1", "1234", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Disabled);

            var serviceProxy = new Mock <IServiceProxy>();

            serviceProxy.Setup(s => s.GetServiceIdentity("d2")).ReturnsAsync(Option.Some(si_device));
            serviceProxy.Setup(s => s.GetServiceIdentity("d1", "m1")).ReturnsAsync(Option.Some(si_module));

            DeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromHours(1));

            // Act
            Option <ServiceIdentity> deviceServiceIdentity = await deviceScopeIdentitiesCache.GetServiceIdentityFromService("d2");

            Option <ServiceIdentity> moduleServiceIdentity = await deviceScopeIdentitiesCache.GetServiceIdentityFromService("d1/m1");

            // Assert
            Assert.True(deviceServiceIdentity.HasValue);
            Assert.True(si_device.Equals(deviceServiceIdentity.OrDefault()));
            Assert.True(moduleServiceIdentity.HasValue);
            Assert.True(si_module.Equals(moduleServiceIdentity.OrDefault()));
        }
        public async Task InitializeFromStoreTest()
        {
            // Arrange
            var iterator = new Mock <IServiceIdentitiesIterator>();

            iterator.Setup(i => i.HasNext).Returns(true);
            iterator.Setup(i => i.GetNext()).ThrowsAsync(new InvalidOperationException("Some error"));
            var serviceProxy = new Mock <IServiceProxy>();

            serviceProxy.Setup(s => s.GetServiceIdentitiesIterator()).Returns(iterator.Object);

            var store = GetEntityStore("cache");
            var serviceAuthentication = new ServiceAuthentication(ServiceAuthenticationType.None);
            var si1       = new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);
            var si2       = new ServiceIdentity("d2", "m1", "2345", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);
            var storedSi1 = new DeviceScopeIdentitiesCache.StoredServiceIdentity(si1);
            await store.Put(si1.Id, storedSi1.ToJson());

            var storedSi2 = new DeviceScopeIdentitiesCache.StoredServiceIdentity(si2);
            await store.Put(si2.Id, storedSi2.ToJson());

            // Act
            IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromHours(1));

            Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1");

            Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1");

            // Assert
            Assert.True(si1.Equals(receivedServiceIdentity1.OrDefault()));
            Assert.True(si2.Equals(receivedServiceIdentity2.OrDefault()));
        }
Esempio n. 3
0
        protected override void Load(ContainerBuilder builder)
        {
            // ISignatureProvider
            builder.Register(
                c =>
            {
                ISignatureProvider signatureProvider = this.edgeHubConnectionString.Map(
                    cs =>
                {
                    IotHubConnectionStringBuilder csBuilder = IotHubConnectionStringBuilder.Create(cs);
                    return(new SharedAccessKeySignatureProvider(csBuilder.SharedAccessKey) as ISignatureProvider);
                })
                                                       .GetOrElse(
                    () =>
                {
                    string edgeHubGenerationId = this.edgeHubGenerationId.Expect(() => new InvalidOperationException("Generation ID missing"));
                    string workloadUri         = this.workloadUri.Expect(() => new InvalidOperationException("workloadUri is missing"));
                    return(new HttpHsmSignatureProvider(this.edgeHubModuleId, edgeHubGenerationId, workloadUri, Constants.WorkloadApiVersion) as ISignatureProvider);
                });
                return(signatureProvider);
            })
            .As <ISignatureProvider>()
            .SingleInstance();

            // Detect system environment
            builder.Register(c => new SystemEnvironment())
            .As <ISystemEnvironment>()
            .SingleInstance();

            // DataBase options
            builder.Register(c => new RocksDbOptionsProvider(c.Resolve <ISystemEnvironment>(), this.optimizeForPerformance))
            .As <IRocksDbOptionsProvider>()
            .SingleInstance();

            // IDbStoreProvider
            builder.Register(
                c =>
            {
                var loggerFactory = c.Resolve <ILoggerFactory>();
                ILogger logger    = loggerFactory.CreateLogger(typeof(RoutingModule));

                if (this.usePersistentStorage)
                {
                    // Create partitions for messages and twins
                    var partitionsList = new List <string> {
                        Core.Constants.MessageStorePartitionKey, Core.Constants.TwinStorePartitionKey, Core.Constants.CheckpointStorePartitionKey
                    };
                    try
                    {
                        IDbStoreProvider dbStoreprovider = DbStoreProvider.Create(
                            c.Resolve <IRocksDbOptionsProvider>(),
                            this.storagePath,
                            partitionsList);
                        logger.LogInformation($"Created persistent store at {this.storagePath}");
                        return(dbStoreprovider);
                    }
                    catch (Exception ex) when(!ExceptionEx.IsFatal(ex))
                    {
                        logger.LogError(ex, "Error creating RocksDB store. Falling back to in-memory store.");
                        return(new InMemoryDbStoreProvider());
                    }
                }
                else
                {
                    logger.LogInformation($"Using in-memory store");
                    return(new InMemoryDbStoreProvider());
                }
            })
            .As <IDbStoreProvider>()
            .SingleInstance();

            // Task<Option<IEncryptionProvider>>
            builder.Register(
                async c =>
            {
                Option <IEncryptionProvider> encryptionProviderOption = await this.workloadUri
                                                                        .Map(
                    async uri =>
                {
                    var encryptionProvider = await EncryptionProvider.CreateAsync(
                        this.storagePath,
                        new Uri(uri),
                        Constants.WorkloadApiVersion,
                        this.edgeHubModuleId,
                        this.edgeHubGenerationId.Expect(() => new InvalidOperationException("Missing generation ID")),
                        Constants.InitializationVectorFileName) as IEncryptionProvider;
                    return(Option.Some(encryptionProvider));
                })
                                                                        .GetOrElse(() => Task.FromResult(Option.None <IEncryptionProvider>()));
                return(encryptionProviderOption);
            })
            .As <Task <Option <IEncryptionProvider> > >()
            .SingleInstance();

            // IStoreProvider
            builder.Register(c => new StoreProvider(c.Resolve <IDbStoreProvider>()))
            .As <IStoreProvider>()
            .SingleInstance();

            // ITokenProvider
            builder.Register(c => new ClientTokenProvider(c.Resolve <ISignatureProvider>(), this.iothubHostName, this.edgeDeviceId, this.edgeHubModuleId, TimeSpan.FromHours(1)))
            .Named <ITokenProvider>("EdgeHubClientAuthTokenProvider")
            .SingleInstance();

            // ITokenProvider
            builder.Register(
                c =>
            {
                string deviceId = WebUtility.UrlEncode(this.edgeDeviceId);
                string moduleId = WebUtility.UrlEncode(this.edgeHubModuleId);
                return(new ClientTokenProvider(c.Resolve <ISignatureProvider>(), this.iothubHostName, deviceId, moduleId, TimeSpan.FromHours(1)));
            })
            .Named <ITokenProvider>("EdgeHubServiceAuthTokenProvider")
            .SingleInstance();

            // Task<IDeviceScopeIdentitiesCache>
            builder.Register(
                async c =>
            {
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache;
                if (this.authenticationMode == AuthenticationMode.CloudAndScope || this.authenticationMode == AuthenticationMode.Scope)
                {
                    var edgeHubTokenProvider = c.ResolveNamed <ITokenProvider>("EdgeHubServiceAuthTokenProvider");
                    IDeviceScopeApiClient securityScopesApiClient = new DeviceScopeApiClient(this.iothubHostName, this.edgeDeviceId, this.edgeHubModuleId, 10, edgeHubTokenProvider);
                    IServiceProxy serviceProxy = new ServiceProxy(securityScopesApiClient);
                    IKeyValueStore <string, string> encryptedStore = await GetEncryptedStore(c, "DeviceScopeCache");
                    deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy, encryptedStore, this.scopeCacheRefreshRate);
                }
                else
                {
                    deviceScopeIdentitiesCache = new NullDeviceScopeIdentitiesCache();
                }

                return(deviceScopeIdentitiesCache);
            })
            .As <Task <IDeviceScopeIdentitiesCache> >()
            .AutoActivate()
            .SingleInstance();

            // Task<ICredentialsCache>
            builder.Register(
                async c =>
            {
                ICredentialsCache underlyingCredentialsCache;
                if (this.persistTokens)
                {
                    IKeyValueStore <string, string> encryptedStore = await GetEncryptedStore(c, "CredentialsCache");
                    return(new PersistedTokenCredentialsCache(encryptedStore));
                }
                else
                {
                    underlyingCredentialsCache = new NullCredentialsCache();
                }

                ICredentialsCache credentialsCache = new CredentialsCache(underlyingCredentialsCache);
                return(credentialsCache);
            })
            .As <Task <ICredentialsCache> >()
            .SingleInstance();

            // Task<IAuthenticator>
            builder.Register(
                async c =>
            {
                IAuthenticator tokenAuthenticator;
                IAuthenticator certificateAuthenticator;
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache;
                var credentialsCacheTask = c.Resolve <Task <ICredentialsCache> >();
                // by default regardless of how the authenticationMode, X.509 certificate validation will always be scoped
                deviceScopeIdentitiesCache = await c.Resolve <Task <IDeviceScopeIdentitiesCache> >();
                certificateAuthenticator   = new DeviceScopeCertificateAuthenticator(deviceScopeIdentitiesCache, new NullAuthenticator(), this.trustBundle, true);
                switch (this.authenticationMode)
                {
                case AuthenticationMode.Cloud:
                    tokenAuthenticator = await this.GetCloudTokenAuthenticator(c);
                    break;

                case AuthenticationMode.Scope:
                    tokenAuthenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache, this.iothubHostName, this.edgeDeviceHostName, new NullAuthenticator(), true, true);
                    break;

                default:
                    IAuthenticator cloudTokenAuthenticator = await this.GetCloudTokenAuthenticator(c);
                    tokenAuthenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache, this.iothubHostName, this.edgeDeviceHostName, cloudTokenAuthenticator, true, true);
                    break;
                }

                ICredentialsCache credentialsCache = await credentialsCacheTask;
                return(new Authenticator(tokenAuthenticator, certificateAuthenticator, credentialsCache) as IAuthenticator);
            })
            .As <Task <IAuthenticator> >()
            .SingleInstance();

            // IClientCredentialsFactory
            builder.Register(c => new ClientCredentialsFactory(c.Resolve <IIdentityProvider>(), this.productInfo))
            .As <IClientCredentialsFactory>()
            .SingleInstance();

            // ConnectionReauthenticator
            builder.Register(
                async c =>
            {
                var edgeHubCredentials               = c.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
                var connectionManagerTask            = c.Resolve <Task <IConnectionManager> >();
                var authenticatorTask                = c.Resolve <Task <IAuthenticator> >();
                var credentialsCacheTask             = c.Resolve <Task <ICredentialsCache> >();
                var deviceScopeIdentitiesCacheTask   = c.Resolve <Task <IDeviceScopeIdentitiesCache> >();
                var deviceConnectivityManager        = c.Resolve <IDeviceConnectivityManager>();
                IConnectionManager connectionManager = await connectionManagerTask;
                IAuthenticator authenticator         = await authenticatorTask;
                ICredentialsCache credentialsCache   = await credentialsCacheTask;
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await deviceScopeIdentitiesCacheTask;
                var connectionReauthenticator = new ConnectionReauthenticator(
                    connectionManager,
                    authenticator,
                    credentialsCache,
                    deviceScopeIdentitiesCache,
                    TimeSpan.FromMinutes(5),
                    edgeHubCredentials.Identity,
                    deviceConnectivityManager);
                return(connectionReauthenticator);
            })
            .As <Task <ConnectionReauthenticator> >()
            .SingleInstance();

            base.Load(builder);
        }
        public async Task GetServiceIdentityTest_Module()
        {
            // Arrange
            var store = GetEntityStore("cache");
            var serviceAuthenticationNone = new ServiceAuthentication(ServiceAuthenticationType.None);
            var serviceAuthenticationSas  = new ServiceAuthentication(new SymmetricKeyAuthentication(GetKey(), GetKey()));

            var si1_initial = new ServiceIdentity("d1", "m1", "1234", Enumerable.Empty <string>(), serviceAuthenticationNone, ServiceIdentityStatus.Enabled);
            var si1_updated = new ServiceIdentity("d1", "m1", "1234", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Disabled);
            var si2         = new ServiceIdentity("d2", "m2", "5678", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Enabled);
            var si3         = new ServiceIdentity("d3", "m3", "0987", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Enabled);

            var iterator1 = new Mock <IServiceIdentitiesIterator>();

            iterator1.SetupSequence(i => i.HasNext)
            .Returns(true)
            .Returns(false);
            iterator1.SetupSequence(i => i.GetNext())
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si1_initial,
                si2
            });

            var serviceProxy = new Mock <IServiceProxy>();

            serviceProxy.Setup(s => s.GetServiceIdentitiesIterator())
            .Returns(iterator1.Object);
            serviceProxy.Setup(s => s.GetServiceIdentity("d1", "m1")).ReturnsAsync(Option.Some(si1_updated));
            serviceProxy.Setup(s => s.GetServiceIdentity("d2", "m2")).ReturnsAsync(Option.None <ServiceIdentity>());
            serviceProxy.Setup(s => s.GetServiceIdentity("d3", "m3")).ReturnsAsync(Option.Some(si3));

            var updatedIdentities = new List <ServiceIdentity>();
            var removedIdentities = new List <string>();

            // Act
            IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromHours(1));

            deviceScopeIdentitiesCache.ServiceIdentityUpdated += (sender, identity) => updatedIdentities.Add(identity);
            deviceScopeIdentitiesCache.ServiceIdentityRemoved += (sender, s) => removedIdentities.Add(s);

            // Wait for refresh to complete
            await Task.Delay(TimeSpan.FromSeconds(3));

            Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1/m1");

            Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m2");

            Option <ServiceIdentity> receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3/m3");

            // Assert
            Assert.True(si1_initial.Equals(receivedServiceIdentity1.OrDefault()));
            Assert.True(si2.Equals(receivedServiceIdentity2.OrDefault()));
            Assert.False(receivedServiceIdentity3.HasValue);

            // Get the identities with refresh
            receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1/m1", true);

            receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m2", true);

            receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3/m3", true);

            // Assert
            Assert.True(si1_initial.Equals(receivedServiceIdentity1.OrDefault()));
            Assert.True(si2.Equals(receivedServiceIdentity2.OrDefault()));
            Assert.True(si3.Equals(receivedServiceIdentity3.OrDefault()));
            Assert.Empty(removedIdentities);
            Assert.Empty(updatedIdentities);
        }
        public async Task RefreshCacheTest()
        {
            // Arrange
            var store = GetEntityStore("cache");
            var serviceAuthentication  = new ServiceAuthentication(ServiceAuthenticationType.None);
            Func <ServiceIdentity> si1 = () => new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);
            Func <ServiceIdentity> si2 = () => new ServiceIdentity("d2", "m1", "2345", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);
            Func <ServiceIdentity> si3 = () => new ServiceIdentity("d3", "5678", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);
            Func <ServiceIdentity> si4 = () => new ServiceIdentity("d2", "m4", "9898", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);

            var iterator1 = new Mock <IServiceIdentitiesIterator>();

            iterator1.SetupSequence(i => i.HasNext)
            .Returns(true)
            .Returns(true)
            .Returns(false);
            iterator1.SetupSequence(i => i.GetNext())
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si1(),
                si2()
            })
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si3(),
                si4()
            });

            var iterator2 = new Mock <IServiceIdentitiesIterator>();

            iterator2.SetupSequence(i => i.HasNext)
            .Returns(true)
            .Returns(false);
            iterator2.SetupSequence(i => i.GetNext())
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si1(),
                si2(),
                si3()
            });

            var serviceProxy = new Mock <IServiceProxy>();

            serviceProxy.SetupSequence(s => s.GetServiceIdentitiesIterator())
            .Returns(iterator1.Object)
            .Returns(iterator2.Object);
            var updatedIdentities = new List <ServiceIdentity>();
            var removedIdentities = new List <string>();

            // Act
            IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromSeconds(8));

            deviceScopeIdentitiesCache.ServiceIdentityUpdated += (sender, identity) => updatedIdentities.Add(identity);
            deviceScopeIdentitiesCache.ServiceIdentityRemoved += (sender, s) => removedIdentities.Add(s);

            // Wait for refresh to complete
            await Task.Delay(TimeSpan.FromSeconds(3));

            Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1");

            Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1");

            Option <ServiceIdentity> receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3");

            Option <ServiceIdentity> receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4");

            // Assert
            Assert.True(si1().Equals(receivedServiceIdentity1.OrDefault()));
            Assert.True(si2().Equals(receivedServiceIdentity2.OrDefault()));
            Assert.True(si3().Equals(receivedServiceIdentity3.OrDefault()));
            Assert.True(si4().Equals(receivedServiceIdentity4.OrDefault()));

            Assert.Empty(updatedIdentities);
            Assert.Empty(removedIdentities);

            // Wait for another refresh cycle to complete
            await Task.Delay(TimeSpan.FromSeconds(8));

            receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1");

            receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1");

            receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3");

            receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4");

            // Assert
            Assert.True(si1().Equals(receivedServiceIdentity1.OrDefault()));
            Assert.True(si2().Equals(receivedServiceIdentity2.OrDefault()));
            Assert.True(si3().Equals(receivedServiceIdentity3.OrDefault()));
            Assert.False(receivedServiceIdentity4.HasValue);

            Assert.Empty(updatedIdentities);
            Assert.Single(removedIdentities);
            Assert.Contains("d2/m4", removedIdentities);
        }
        public async Task RefreshCacheWithRefreshRequestTest()
        {
            // Arrange
            var store = new EntityStore <string, string>(new InMemoryDbStore(), "cache");
            var serviceAuthentication  = new ServiceAuthentication(ServiceAuthenticationType.None);
            Func <ServiceIdentity> si1 = () => new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);
            Func <ServiceIdentity> si2 = () => new ServiceIdentity("d2", "m1", "2345", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);
            Func <ServiceIdentity> si3 = () => new ServiceIdentity("d3", "5678", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);
            Func <ServiceIdentity> si4 = () => new ServiceIdentity("d2", "m4", "9898", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);

            var iterator1 = new Mock <IServiceIdentitiesIterator>();

            iterator1.SetupSequence(i => i.HasNext)
            .Returns(true)
            .Returns(true)
            .Returns(false);
            iterator1.SetupSequence(i => i.GetNext())
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si1(),
                si2()
            })
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si3(),
                si4()
            });

            var iterator2 = new Mock <IServiceIdentitiesIterator>();

            iterator2.SetupSequence(i => i.HasNext)
            .Returns(true)
            .Returns(false);
            iterator2.SetupSequence(i => i.GetNext())
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si1(),
                si2(),
                si3()
            });

            var iterator3 = new Mock <IServiceIdentitiesIterator>();

            iterator3.SetupSequence(i => i.HasNext)
            .Returns(true)
            .Returns(false);
            iterator3.SetupSequence(i => i.GetNext())
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si1(),
                si2()
            });

            var iterator4 = new Mock <IServiceIdentitiesIterator>();

            iterator4.SetupSequence(i => i.HasNext)
            .Returns(true)
            .Returns(false);
            iterator4.SetupSequence(i => i.GetNext())
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si3(),
                si4()
            });

            var serviceProxy = new Mock <IServiceProxy>();

            serviceProxy.SetupSequence(s => s.GetServiceIdentitiesIterator())
            .Returns(iterator1.Object)
            .Returns(iterator2.Object)
            .Returns(iterator3.Object)
            .Returns(iterator4.Object);
            var updatedIdentities = new List <ServiceIdentity>();
            var removedIdentities = new List <string>();

            // Act
            IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromSeconds(7));

            deviceScopeIdentitiesCache.ServiceIdentityUpdated += (sender, identity) => updatedIdentities.Add(identity);
            deviceScopeIdentitiesCache.ServiceIdentityRemoved += (sender, s) => removedIdentities.Add(s);

            // Wait for refresh to complete
            await Task.Delay(TimeSpan.FromSeconds(3));

            Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1");

            Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1");

            Option <ServiceIdentity> receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3");

            Option <ServiceIdentity> receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4");

            // Assert
            Assert.True(si1().Equals(receivedServiceIdentity1.OrDefault()));
            Assert.True(si2().Equals(receivedServiceIdentity2.OrDefault()));
            Assert.True(si3().Equals(receivedServiceIdentity3.OrDefault()));
            Assert.True(si4().Equals(receivedServiceIdentity4.OrDefault()));

            Assert.Equal(0, updatedIdentities.Count);
            Assert.Equal(0, removedIdentities.Count);

            // Act - Signal refresh cache multiple times. It should get picked up twice.
            deviceScopeIdentitiesCache.InitiateCacheRefresh();
            deviceScopeIdentitiesCache.InitiateCacheRefresh();
            deviceScopeIdentitiesCache.InitiateCacheRefresh();
            deviceScopeIdentitiesCache.InitiateCacheRefresh();

            // Wait for the 2 refresh cycles to complete, this time because of the refresh request
            await Task.Delay(TimeSpan.FromSeconds(5));

            receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1");

            receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1");

            receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3");

            receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4");

            // Assert
            Assert.True(si1().Equals(receivedServiceIdentity1.OrDefault()));
            Assert.True(si2().Equals(receivedServiceIdentity2.OrDefault()));
            Assert.False(receivedServiceIdentity3.HasValue);
            Assert.False(receivedServiceIdentity4.HasValue);

            Assert.Equal(0, updatedIdentities.Count);
            Assert.Equal(2, removedIdentities.Count);
            Assert.True(removedIdentities.Contains("d2/m4"));
            Assert.True(removedIdentities.Contains("d3"));

            // Wait for another refresh cycle to complete, this time because timeout
            await Task.Delay(TimeSpan.FromSeconds(8));

            receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1");

            receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m1");

            receivedServiceIdentity3 = await deviceScopeIdentitiesCache.GetServiceIdentity("d3");

            receivedServiceIdentity4 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2/m4");

            // Assert
            Assert.True(si3().Equals(receivedServiceIdentity3.OrDefault()));
            Assert.True(si4().Equals(receivedServiceIdentity4.OrDefault()));
            Assert.False(receivedServiceIdentity1.HasValue);
            Assert.False(receivedServiceIdentity2.HasValue);

            Assert.Equal(0, updatedIdentities.Count);
            Assert.Equal(4, removedIdentities.Count);
            Assert.True(removedIdentities.Contains("d2/m1"));
            Assert.True(removedIdentities.Contains("d1"));
        }
Esempio n. 7
0
        public async Task RefreshServiceIdentityTest_List()
        {
            // Arrange
            var store = new EntityStore <string, string>(new InMemoryDbStore(), "cache");
            var serviceAuthenticationNone = new ServiceAuthentication(ServiceAuthenticationType.None);
            var serviceAuthenticationSas  = new ServiceAuthentication(new SymmetricKeyAuthentication(GetKey(), GetKey()));

            var si1_initial = new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthenticationNone, ServiceIdentityStatus.Enabled);
            var si1_updated = new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Enabled);
            var si2         = new ServiceIdentity("d2", "5678", Enumerable.Empty <string>(), serviceAuthenticationSas, ServiceIdentityStatus.Enabled);

            var iterator1 = new Mock <IServiceIdentitiesIterator>();

            iterator1.SetupSequence(i => i.HasNext)
            .Returns(true)
            .Returns(false);
            iterator1.SetupSequence(i => i.GetNext())
            .ReturnsAsync(
                new List <ServiceIdentity>
            {
                si1_initial,
                si2
            });

            var serviceProxy = new Mock <IServiceProxy>();

            serviceProxy.Setup(s => s.GetServiceIdentitiesIterator())
            .Returns(iterator1.Object);
            serviceProxy.Setup(s => s.GetServiceIdentity(It.Is <string>(id => id == "d1"))).ReturnsAsync(Option.Some(si1_updated));
            serviceProxy.Setup(s => s.GetServiceIdentity(It.Is <string>(id => id == "d2"))).ReturnsAsync(Option.None <ServiceIdentity>());

            var updatedIdentities = new List <ServiceIdentity>();
            var removedIdentities = new List <string>();

            // Act
            IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy.Object, store, TimeSpan.FromHours(1));

            deviceScopeIdentitiesCache.ServiceIdentityUpdated += (sender, identity) => updatedIdentities.Add(identity);
            deviceScopeIdentitiesCache.ServiceIdentityRemoved += (sender, s) => removedIdentities.Add(s);

            // Wait for refresh to complete
            await Task.Delay(TimeSpan.FromSeconds(3));

            Option <ServiceIdentity> receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1");

            Option <ServiceIdentity> receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2");

            // Assert
            Assert.True(si1_initial.Equals(receivedServiceIdentity1.OrDefault()));
            Assert.True(si2.Equals(receivedServiceIdentity2.OrDefault()));

            // Update the identities
            await deviceScopeIdentitiesCache.RefreshServiceIdentities(new[] { "d1", "d2" });

            receivedServiceIdentity1 = await deviceScopeIdentitiesCache.GetServiceIdentity("d1");

            receivedServiceIdentity2 = await deviceScopeIdentitiesCache.GetServiceIdentity("d2");

            // Assert
            Assert.True(si1_updated.Equals(receivedServiceIdentity1.OrDefault()));
            Assert.False(receivedServiceIdentity2.HasValue);
            Assert.Equal(1, removedIdentities.Count);
            Assert.Equal("d2", removedIdentities[0]);
            Assert.Equal(1, updatedIdentities.Count);
            Assert.Equal("d1", updatedIdentities[0].Id);
        }
Esempio n. 8
0
        protected override void Load(ContainerBuilder builder)
        {
            // ISignatureProvider
            builder.Register(
                c =>
            {
                ISignatureProvider signatureProvider = this.edgeHubConnectionString.Map(
                    cs =>
                {
                    IotHubConnectionStringBuilder csBuilder = IotHubConnectionStringBuilder.Create(cs);
                    return(new SharedAccessKeySignatureProvider(csBuilder.SharedAccessKey) as ISignatureProvider);
                })
                                                       .GetOrElse(
                    () =>
                {
                    string edgeHubGenerationId = this.edgeHubGenerationId.Expect(() => new InvalidOperationException("Generation ID missing"));
                    string workloadUri         = this.workloadUri.Expect(() => new InvalidOperationException("workloadUri is missing"));
                    return(new HttpHsmSignatureProvider(this.edgeHubModuleId, edgeHubGenerationId, workloadUri, Service.Constants.WorkloadApiVersion) as ISignatureProvider);
                });
                return(signatureProvider);
            })
            .As <ISignatureProvider>()
            .SingleInstance();

            // Detect system environment
            builder.Register(c => new SystemEnvironment())
            .As <ISystemEnvironment>()
            .SingleInstance();

            // DataBase options
            builder.Register(c => new Storage.RocksDb.RocksDbOptionsProvider(c.Resolve <ISystemEnvironment>(), this.optimizeForPerformance))
            .As <Storage.RocksDb.IRocksDbOptionsProvider>()
            .SingleInstance();

            // IDbStoreProvider
            builder.Register(
                c =>
            {
                var loggerFactory = c.Resolve <ILoggerFactory>();
                ILogger logger    = loggerFactory.CreateLogger(typeof(RoutingModule));

                if (this.usePersistentStorage)
                {
                    // Create partitions for messages and twins
                    var partitionsList = new List <string> {
                        Core.Constants.MessageStorePartitionKey, Core.Constants.TwinStorePartitionKey, Core.Constants.CheckpointStorePartitionKey
                    };
                    try
                    {
                        IDbStoreProvider dbStoreprovider = Storage.RocksDb.DbStoreProvider.Create(c.Resolve <Storage.RocksDb.IRocksDbOptionsProvider>(),
                                                                                                  this.storagePath, partitionsList);
                        logger.LogInformation($"Created persistent store at {this.storagePath}");
                        return(dbStoreprovider);
                    }
                    catch (Exception ex) when(!ExceptionEx.IsFatal(ex))
                    {
                        logger.LogError(ex, "Error creating RocksDB store. Falling back to in-memory store.");
                        return(new InMemoryDbStoreProvider());
                    }
                }
                else
                {
                    logger.LogInformation($"Using in-memory store");
                    return(new InMemoryDbStoreProvider());
                }
            })
            .As <IDbStoreProvider>()
            .SingleInstance();

            // Task<IEncryptionProvider>
            builder.Register(
                async c =>
            {
                IEncryptionProvider encryptionProvider = await this.workloadUri.Map(
                    async uri => await EncryptionProvider.CreateAsync(
                        this.storagePath,
                        new Uri(uri),
                        Service.Constants.WorkloadApiVersion,
                        this.edgeHubModuleId,
                        this.edgeHubGenerationId.Expect(() => new InvalidOperationException("Missing generation ID")),
                        Service.Constants.InitializationVectorFileName) as IEncryptionProvider)
                                                         .GetOrElse(() => Task.FromResult <IEncryptionProvider>(NullEncryptionProvider.Instance));
                return(encryptionProvider);
            })
            .As <Task <IEncryptionProvider> >()
            .SingleInstance();

            // IStoreProvider
            builder.Register(c => new StoreProvider(c.Resolve <IDbStoreProvider>()))
            .As <IStoreProvider>()
            .SingleInstance();

            // ITokenProvider
            builder.Register(c => new ModuleTokenProvider(c.Resolve <ISignatureProvider>(), this.iothubHostName, this.edgeDeviceId, this.edgeHubModuleId, TimeSpan.FromHours(1)))
            .Named <ITokenProvider>("EdgeHubClientAuthTokenProvider")
            .SingleInstance();

            // ITokenProvider
            builder.Register(c =>
            {
                string deviceId = WebUtility.UrlEncode(this.edgeDeviceId);
                string moduleId = WebUtility.UrlEncode(this.edgeHubModuleId);
                return(new ModuleTokenProvider(c.Resolve <ISignatureProvider>(), this.iothubHostName, deviceId, moduleId, TimeSpan.FromHours(1)));
            })
            .Named <ITokenProvider>("EdgeHubServiceAuthTokenProvider")
            .SingleInstance();

            // Task<IKeyValueStore<string, string>> - EncryptedStore
            builder.Register(
                async c =>
            {
                var storeProvider = c.Resolve <IStoreProvider>();
                IEncryptionProvider encryptionProvider         = await c.Resolve <Task <IEncryptionProvider> >();
                IEntityStore <string, string> entityStore      = storeProvider.GetEntityStore <string, string>("SecurityScopeCache");
                IKeyValueStore <string, string> encryptedStore = new EncryptedStore <string, string>(entityStore, encryptionProvider);
                return(encryptedStore);
            })
            .Named <Task <IKeyValueStore <string, string> > >("EncryptedStore")
            .SingleInstance();


            // Task<IDeviceScopeIdentitiesCache>
            builder.Register(
                async c =>
            {
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache;
                if (this.authenticationMode == AuthenticationMode.CloudAndScope || this.authenticationMode == AuthenticationMode.Scope)
                {
                    var edgeHubTokenProvider = c.ResolveNamed <ITokenProvider>("EdgeHubServiceAuthTokenProvider");
                    IDeviceScopeApiClient securityScopesApiClient = new DeviceScopeApiClient(this.iothubHostName, this.edgeDeviceId, this.edgeHubModuleId, 10, edgeHubTokenProvider);
                    IServiceProxy serviceProxy = new ServiceProxy(securityScopesApiClient);
                    IKeyValueStore <string, string> encryptedStore = await c.ResolveNamed <Task <IKeyValueStore <string, string> > >("EncryptedStore");
                    deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceProxy, encryptedStore, this.scopeCacheRefreshRate);
                }
                else
                {
                    deviceScopeIdentitiesCache = new NullDeviceScopeIdentitiesCache();
                }

                return(deviceScopeIdentitiesCache);
            })
            .As <Task <IDeviceScopeIdentitiesCache> >()
            .SingleInstance();

            // Task<IAuthenticator>
            builder.Register(async c =>
            {
                IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                IAuthenticator tokenAuthenticator;
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache;
                switch (this.authenticationMode)
                {
                case AuthenticationMode.Cloud:
                    if (this.cacheTokens)
                    {
                        ICredentialsStore credentialsStore = await c.Resolve <Task <ICredentialsStore> >();
                        IAuthenticator authenticator       = new CloudTokenAuthenticator(connectionManager);
                        tokenAuthenticator = new TokenCacheAuthenticator(authenticator, credentialsStore, this.iothubHostName);
                    }
                    else
                    {
                        tokenAuthenticator = new CloudTokenAuthenticator(connectionManager);
                    }
                    break;

                case AuthenticationMode.Scope:
                    deviceScopeIdentitiesCache = await c.Resolve <Task <IDeviceScopeIdentitiesCache> >();
                    tokenAuthenticator         = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache, this.iothubHostName, this.edgeDeviceHostName, new NullAuthenticator(), connectionManager);
                    break;

                default:
                    deviceScopeIdentitiesCache        = await c.Resolve <Task <IDeviceScopeIdentitiesCache> >();
                    IAuthenticator cloudAuthenticator = new CloudTokenAuthenticator(connectionManager);
                    tokenAuthenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache, this.iothubHostName, this.edgeDeviceHostName, cloudAuthenticator, connectionManager);
                    break;
                }

                return(new Authenticator(tokenAuthenticator, this.edgeDeviceId, connectionManager) as IAuthenticator);
            })
            .As <Task <IAuthenticator> >()
            .SingleInstance();

            // IClientCredentialsFactory
            builder.Register(c => new ClientCredentialsFactory(this.iothubHostName, this.productInfo))
            .As <IClientCredentialsFactory>()
            .SingleInstance();

            base.Load(builder);
        }
Esempio n. 9
0
        protected override void Load(ContainerBuilder builder)
        {
            // IMetricsListener
            builder.Register(
                c =>
                this.metricsConfig.Enabled
                            ? new MetricsListener(this.metricsConfig.ListenerConfig, c.Resolve <IMetricsProvider>())
                            : new NullMetricsListener() as IMetricsListener)
            .As <IMetricsListener>()
            .SingleInstance();

            // IMetricsProvider
            builder.Register(
                c =>
                this.metricsConfig.Enabled
                            ? new MetricsProvider(MetricsConstants.EdgeHubMetricPrefix, this.iothubHostName, this.edgeDeviceId, this.metricsConfig.HistogramMaxAge)
                            : new NullMetricsProvider() as IMetricsProvider)
            .As <IMetricsProvider>()
            .SingleInstance();

            // ISignatureProvider
            builder.Register(
                c =>
            {
                ISignatureProvider signatureProvider = this.edgeHubConnectionString.Map(
                    cs =>
                {
                    IotHubConnectionStringBuilder csBuilder = IotHubConnectionStringBuilder.Create(cs);
                    return(new SharedAccessKeySignatureProvider(csBuilder.SharedAccessKey) as ISignatureProvider);
                })
                                                       .GetOrElse(
                    () =>
                {
                    string edgeHubGenerationId = this.edgeHubGenerationId.Expect(() => new InvalidOperationException("Generation ID missing"));
                    string workloadUri         = this.workloadUri.Expect(() => new InvalidOperationException("workloadUri is missing"));
                    string workloadApiVersion  = this.workloadApiVersion.Expect(() => new InvalidOperationException("workloadUri version is missing"));
                    return(new HttpHsmSignatureProvider(this.edgeHubModuleId, edgeHubGenerationId, workloadUri, workloadApiVersion, Constants.WorkloadApiVersion) as ISignatureProvider);
                });
                return(signatureProvider);
            })
            .As <ISignatureProvider>()
            .SingleInstance();

            // Detect system environment
            builder.Register(c => new SystemEnvironment())
            .As <ISystemEnvironment>()
            .SingleInstance();

            // DataBase options
            builder.Register(c => new RocksDbOptionsProvider(c.Resolve <ISystemEnvironment>(), this.optimizeForPerformance, this.storageMaxTotalWalSize, this.storageMaxOpenFiles, this.storageLogLevel))
            .As <IRocksDbOptionsProvider>()
            .SingleInstance();

            if (!this.usePersistentStorage && this.useBackupAndRestore)
            {
                // Backup and restore serialization
                builder.Register(c => new ProtoBufDataBackupRestore())
                .As <IDataBackupRestore>()
                .SingleInstance();
            }

            // IStorageSpaceChecker
            builder.Register(
                c =>
            {
                IStorageSpaceChecker spaceChecker = !this.usePersistentStorage
                       ? new MemorySpaceChecker(() => 0L) as IStorageSpaceChecker
                       : new NullStorageSpaceChecker();
                return(spaceChecker);
            })
            .As <IStorageSpaceChecker>()
            .SingleInstance();

            // IDbStoreProvider
            builder.Register(
                async c =>
            {
                var loggerFactory = c.Resolve <ILoggerFactory>();
                ILogger logger    = loggerFactory.CreateLogger(typeof(RoutingModule));

                if (this.usePersistentStorage)
                {
                    // Create partitions for messages and twins
                    var partitionsList = new List <string> {
                        Core.Constants.MessageStorePartitionKey, Core.Constants.TwinStorePartitionKey, Core.Constants.CheckpointStorePartitionKey
                    };
                    try
                    {
                        IDbStoreProvider dbStoreProvider = DbStoreProvider.Create(
                            c.Resolve <IRocksDbOptionsProvider>(),
                            this.storagePath,
                            partitionsList);
                        logger.LogInformation($"Created persistent store at {this.storagePath}");
                        return(dbStoreProvider);
                    }
                    catch (Exception ex) when(!ex.IsFatal())
                    {
                        logger.LogError(ex, "Error creating RocksDB store. Falling back to in-memory store.");
                        IDbStoreProvider dbStoreProvider = await this.BuildInMemoryDbStoreProvider(c);
                        return(dbStoreProvider);
                    }
                }
                else
                {
                    logger.LogInformation($"Using in-memory store");
                    IDbStoreProvider dbStoreProvider = await this.BuildInMemoryDbStoreProvider(c);
                    return(dbStoreProvider);
                }
            })
            .As <Task <IDbStoreProvider> >()
            .SingleInstance();

            // Task<Option<IEncryptionProvider>>
            builder.Register(
                async c =>
            {
                Option <IEncryptionProvider> encryptionProviderOption = await this.workloadUri
                                                                        .Map(
                    async uri =>
                {
                    var encryptionProvider = await EncryptionProvider.CreateAsync(
                        this.storagePath,
                        new Uri(uri),
                        this.workloadApiVersion.Expect(() => new InvalidOperationException("Missing workload API version")),
                        Constants.WorkloadApiVersion,
                        this.edgeHubModuleId,
                        this.edgeHubGenerationId.Expect(() => new InvalidOperationException("Missing generation ID")),
                        Constants.InitializationVectorFileName) as IEncryptionProvider;
                    return(Option.Some(encryptionProvider));
                })
                                                                        .GetOrElse(() => Task.FromResult(Option.None <IEncryptionProvider>()));
                return(encryptionProviderOption);
            })
            .As <Task <Option <IEncryptionProvider> > >()
            .SingleInstance();

            // Task<IStoreProvider>
            builder.Register(async c =>
            {
                var dbStoreProvider          = await c.Resolve <Task <IDbStoreProvider> >();
                IStoreProvider storeProvider = new StoreProvider(dbStoreProvider);
                return(storeProvider);
            })
            .As <Task <IStoreProvider> >()
            .SingleInstance();

            // Task<IMetadataStore>
            builder.Register(
                async c =>
            {
                var storeProvider = await c.Resolve <Task <IStoreProvider> >();
                IKeyValueStore <string, string> entityStore = storeProvider.GetEntityStore <string, string>("ProductInfo", "MetadataStore");
                IMetadataStore metadataStore = new MetadataStore(entityStore, this.productInfo);
                return(metadataStore);
            })
            .As <Task <IMetadataStore> >()
            .SingleInstance();

            // ITokenProvider
            builder.Register(c => new ClientTokenProvider(c.Resolve <ISignatureProvider>(), this.iothubHostName, this.edgeDeviceId, this.edgeHubModuleId, TimeSpan.FromHours(1)))
            .Named <ITokenProvider>("EdgeHubClientAuthTokenProvider")
            .SingleInstance();

            // ITokenProvider
            builder.Register(
                c =>
            {
                string deviceId = WebUtility.UrlEncode(this.edgeDeviceId);
                string moduleId = WebUtility.UrlEncode(this.edgeHubModuleId);
                return(new ClientTokenProvider(c.Resolve <ISignatureProvider>(), this.iothubHostName, deviceId, moduleId, TimeSpan.FromHours(1)));
            })
            .Named <ITokenProvider>("EdgeHubServiceAuthTokenProvider")
            .SingleInstance();

            builder.Register(
                c =>
            {
                var loggerFactory = c.Resolve <ILoggerFactory>();
                var logger        = loggerFactory.CreateLogger <RoutingModule>();
                return(Proxy.Parse(this.proxy, logger));
            })
            .As <Option <IWebProxy> >()
            .SingleInstance();

            // IServiceIdentityHierarchy
            builder.Register <IServiceIdentityHierarchy>(
                c =>
            {
                if (this.nestedEdgeEnabled)
                {
                    return(new ServiceIdentityTree(this.edgeDeviceId));
                }
                else
                {
                    return(new ServiceIdentityDictionary(this.edgeDeviceId));
                }
            })
            .As <IServiceIdentityHierarchy>()
            .SingleInstance();

            // Task<IDeviceScopeIdentitiesCache>
            builder.Register(
                async c =>
            {
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache;
                if (this.authenticationMode == AuthenticationMode.CloudAndScope || this.authenticationMode == AuthenticationMode.Scope)
                {
                    var edgeHubTokenProvider = c.ResolveNamed <ITokenProvider>("EdgeHubServiceAuthTokenProvider");
                    var proxy = c.Resolve <Option <IWebProxy> >();

                    IServiceIdentityHierarchy serviceIdentityHierarchy = c.Resolve <IServiceIdentityHierarchy>();

                    string hostName = this.gatewayHostName.GetOrElse(this.iothubHostName);
                    IDeviceScopeApiClientProvider securityScopesApiClientProvider = new DeviceScopeApiClientProvider(hostName, this.edgeDeviceId, this.edgeHubModuleId, 10, edgeHubTokenProvider, serviceIdentityHierarchy, proxy);
                    IServiceProxy serviceProxy = new ServiceProxy(securityScopesApiClientProvider, this.nestedEdgeEnabled);
                    IKeyValueStore <string, string> encryptedStore = await GetEncryptedStore(c, "DeviceScopeCache");
                    deviceScopeIdentitiesCache = await DeviceScopeIdentitiesCache.Create(serviceIdentityHierarchy, serviceProxy, encryptedStore, this.scopeCacheRefreshRate, this.scopeCacheRefreshDelay);
                }
                else
                {
                    deviceScopeIdentitiesCache = new NullDeviceScopeIdentitiesCache();
                }

                return(deviceScopeIdentitiesCache);
            })
            .As <Task <IDeviceScopeIdentitiesCache> >()
            .AutoActivate()
            .SingleInstance();

            // IRegistryApiClient
            builder.Register(
                c =>
            {
                string upstreamHostname = this.gatewayHostName.GetOrElse(this.iothubHostName);
                var proxy = c.Resolve <Option <IWebProxy> >();
                var edgeHubTokenProvider = c.ResolveNamed <ITokenProvider>("EdgeHubServiceAuthTokenProvider");
                return(new RegistryOnBehalfOfApiClient(upstreamHostname, proxy, edgeHubTokenProvider));
            })
            .As <IRegistryOnBehalfOfApiClient>()
            .SingleInstance();

            // Task<ICredentialsCache>
            builder.Register(
                async c =>
            {
                ICredentialsCache underlyingCredentialsCache;
                if (this.persistTokens)
                {
                    IKeyValueStore <string, string> encryptedStore = await GetEncryptedStore(c, "CredentialsCache");
                    return(new PersistedTokenCredentialsCache(encryptedStore));
                }
                else
                {
                    underlyingCredentialsCache = new NullCredentialsCache();
                }

                ICredentialsCache credentialsCache;

                if (this.nestedEdgeEnabled)
                {
                    credentialsCache = new NestedCredentialsCache(underlyingCredentialsCache);
                }
                else
                {
                    credentialsCache = new CredentialsCache(underlyingCredentialsCache);
                }

                return(credentialsCache);
            })
            .As <Task <ICredentialsCache> >()
            .SingleInstance();

            // Task<IAuthenticator>
            builder.Register(
                async c =>
            {
                IAuthenticator tokenAuthenticator;
                IAuthenticator certificateAuthenticator;
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache;
                var credentialsCacheTask = c.Resolve <Task <ICredentialsCache> >();
                // by default regardless of how the authenticationMode, X.509 certificate validation will always be scoped
                deviceScopeIdentitiesCache = await c.Resolve <Task <IDeviceScopeIdentitiesCache> >();
                certificateAuthenticator   = new DeviceScopeCertificateAuthenticator(deviceScopeIdentitiesCache, new NullAuthenticator(), this.trustBundle, true, this.nestedEdgeEnabled);
                switch (this.authenticationMode)
                {
                case AuthenticationMode.Cloud:
                    tokenAuthenticator = await this.GetCloudTokenAuthenticator(c);
                    break;

                case AuthenticationMode.Scope:
                    tokenAuthenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache, this.iothubHostName, this.edgeDeviceHostName, new NullAuthenticator(), true, true, this.nestedEdgeEnabled);
                    break;

                default:
                    IAuthenticator cloudTokenAuthenticator = await this.GetCloudTokenAuthenticator(c);
                    tokenAuthenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache, this.iothubHostName, this.edgeDeviceHostName, cloudTokenAuthenticator, true, true, this.nestedEdgeEnabled);
                    break;
                }

                ICredentialsCache credentialsCache = await credentialsCacheTask;
                return(new Authenticator(tokenAuthenticator, certificateAuthenticator, credentialsCache) as IAuthenticator);
            })
            .As <Task <IAuthenticator> >()
            .SingleInstance();

            // IClientCredentialsFactory
            builder.Register(c => new ClientCredentialsFactory(c.Resolve <IIdentityProvider>(), this.productInfo))
            .As <IClientCredentialsFactory>()
            .SingleInstance();

            // IClientCredentials "EdgeHubCredentials"
            builder.Register(
                c =>
            {
                var identityFactory = c.Resolve <IClientCredentialsFactory>();
                IClientCredentials edgeHubCredentials = this.edgeHubConnectionString.Map(cs => identityFactory.GetWithConnectionString(cs)).GetOrElse(
                    () => identityFactory.GetWithIotEdged(this.edgeDeviceId, this.edgeHubModuleId));
                return(edgeHubCredentials);
            })
            .Named <IClientCredentials>("EdgeHubCredentials")
            .SingleInstance();

            // ServiceIdentity "EdgeHubIdentity"
            builder.Register(
                c =>
            {
                return(new ServiceIdentity(
                           this.edgeDeviceId,
                           this.edgeHubModuleId,
                           deviceScope: null,
                           parentScopes: new List <string>(),
                           this.edgeHubGenerationId.GetOrElse("0"),
                           capabilities: new List <string>(),
                           new ServiceAuthentication(ServiceAuthenticationType.None),
                           ServiceIdentityStatus.Enabled));
            })
            .Named <ServiceIdentity>("EdgeHubIdentity")
            .SingleInstance();

            // ConnectionReauthenticator
            builder.Register(
                async c =>
            {
                var edgeHubCredentials               = c.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
                var connectionManagerTask            = c.Resolve <Task <IConnectionManager> >();
                var authenticatorTask                = c.Resolve <Task <IAuthenticator> >();
                var credentialsCacheTask             = c.Resolve <Task <ICredentialsCache> >();
                var deviceScopeIdentitiesCacheTask   = c.Resolve <Task <IDeviceScopeIdentitiesCache> >();
                var deviceConnectivityManager        = c.Resolve <IDeviceConnectivityManager>();
                IConnectionManager connectionManager = await connectionManagerTask;
                IAuthenticator authenticator         = await authenticatorTask;
                ICredentialsCache credentialsCache   = await credentialsCacheTask;
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await deviceScopeIdentitiesCacheTask;
                var connectionReauthenticator = new ConnectionReauthenticator(
                    connectionManager,
                    authenticator,
                    credentialsCache,
                    deviceScopeIdentitiesCache,
                    TimeSpan.FromMinutes(5),
                    edgeHubCredentials.Identity,
                    deviceConnectivityManager);
                return(connectionReauthenticator);
            })
            .As <Task <ConnectionReauthenticator> >()
            .SingleInstance();

            base.Load(builder);
        }