public void DeviceScopeIdentitiesCacheOnDeviceConnectedEvent()
        {
            // Arrange
            var      connectionManager          = new Mock <IConnectionManager>(MockBehavior.Strict);
            var      authenticator              = new Mock <IAuthenticator>(MockBehavior.Strict);
            var      credentialsStore           = new Mock <ICredentialsCache>(MockBehavior.Strict);
            var      deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>(MockBehavior.Strict);
            var      deviceConnectivityManager  = Mock.Of <IDeviceConnectivityManager>();
            TimeSpan reauthFrequency            = TimeSpan.FromHours(1);
            var      connectionReauthenticator  = new ConnectionReauthenticator(
                connectionManager.Object,
                authenticator.Object,
                credentialsStore.Object,
                deviceScopeIdentitiesCache.Object,
                reauthFrequency,
                Mock.Of <IIdentity>(i => i.Id == "d1/$edgeHub"),
                deviceConnectivityManager);

            deviceScopeIdentitiesCache.Setup(d => d.InitiateCacheRefresh());

            // Act
            Mock.Get(deviceConnectivityManager).Raise(d => d.DeviceConnected += null, new EventArgs());

            // Assert
            deviceScopeIdentitiesCache.VerifyAll();
        }
        public void TestHandleEdgeHubServiceIdentityRemove()
        {
            // Arrange
            var      connectionManager          = new Mock <IConnectionManager>(MockBehavior.Strict);
            var      authenticator              = new Mock <IAuthenticator>(MockBehavior.Strict);
            var      credentialsStore           = new Mock <ICredentialsCache>(MockBehavior.Strict);
            var      deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>(MockBehavior.Strict);
            var      deviceConnectivityManager  = Mock.Of <IDeviceConnectivityManager>();
            TimeSpan reauthFrequency            = TimeSpan.FromSeconds(3);
            var      edgeHubIdentity            = Mock.Of <IIdentity>(i => i.Id == "d2/$edgeHub");

            connectionManager.Setup(c => c.RemoveDeviceConnection("d2/$edgeHub")).Returns(Task.CompletedTask);

            // Act
            var connectionReauthenticator = new ConnectionReauthenticator(
                connectionManager.Object,
                authenticator.Object,
                credentialsStore.Object,
                deviceScopeIdentitiesCache.Object,
                reauthFrequency,
                edgeHubIdentity,
                deviceConnectivityManager);

            deviceScopeIdentitiesCache.Raise(d => d.ServiceIdentityRemoved += null, null, "d2/$edgeHub");

            // Assert
            Assert.NotNull(connectionReauthenticator);
            connectionManager.Verify(c => c.RemoveDeviceConnection("d2/$edgeHub"), Times.Never);
            authenticator.VerifyAll();
            credentialsStore.VerifyAll();
            deviceScopeIdentitiesCache.VerifyAll();
        }
        public void TestHandleServiceIdentityUpdateSuccess()
        {
            // Arrange
            var      connectionManager          = new Mock <IConnectionManager>(MockBehavior.Strict);
            var      authenticator              = new Mock <IAuthenticator>(MockBehavior.Strict);
            var      credentialsStore           = new Mock <ICredentialsCache>(MockBehavior.Strict);
            var      deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>(MockBehavior.Strict);
            var      deviceConnectivityManager  = Mock.Of <IDeviceConnectivityManager>();
            TimeSpan reauthFrequency            = TimeSpan.FromSeconds(3);

            var deviceIdentity = new DeviceIdentity(IoTHubHostName, "d1");
            var moduleIdentity = new ModuleIdentity(IoTHubHostName, "d1", "m1");

            var deviceCredentials = Mock.Of <IClientCredentials>(c => c.Identity == deviceIdentity && c.AuthenticationType == AuthenticationType.SasKey);
            var moduleCredentials = Mock.Of <IClientCredentials>(c => c.Identity == moduleIdentity && c.AuthenticationType == AuthenticationType.SasKey);

            credentialsStore.Setup(c => c.Get(deviceIdentity)).ReturnsAsync(Option.Some(deviceCredentials));
            credentialsStore.Setup(c => c.Get(moduleIdentity)).ReturnsAsync(Option.Some(moduleCredentials));

            var deviceProxy = Mock.Of <IDeviceProxy>(d => d.IsActive && d.Identity == deviceIdentity);
            var moduleProxy = Mock.Of <IDeviceProxy>(d => d.IsActive && d.Identity == moduleIdentity);

            connectionManager.Setup(c => c.GetDeviceConnection("d1")).Returns(Option.Some(deviceProxy));
            connectionManager.Setup(c => c.GetDeviceConnection("d1/m1")).Returns(Option.Some(moduleProxy));

            connectionManager.Setup(c => c.RemoveDeviceConnection("d1")).Returns(Task.CompletedTask);
            connectionManager.Setup(c => c.RemoveDeviceConnection("d1/m1")).Returns(Task.CompletedTask);

            authenticator.Setup(a => a.ReauthenticateAsync(deviceCredentials)).ReturnsAsync(true);
            authenticator.Setup(a => a.ReauthenticateAsync(moduleCredentials)).ReturnsAsync(true);

            var serviceAuthentication = new ServiceAuthentication(ServiceAuthenticationType.None);
            var deviceServiceIdentity = new ServiceIdentity("d1", "1234", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);
            var moduleServiceIdentity = new ServiceIdentity("d1/m1", "1234", Enumerable.Empty <string>(), serviceAuthentication, ServiceIdentityStatus.Enabled);

            // Act
            var connectionReauthenticator = new ConnectionReauthenticator(
                connectionManager.Object,
                authenticator.Object,
                credentialsStore.Object,
                deviceScopeIdentitiesCache.Object,
                reauthFrequency,
                Mock.Of <IIdentity>(e => e.Id == "ed/$edgeHub"),
                deviceConnectivityManager);

            deviceScopeIdentitiesCache.Raise(d => d.ServiceIdentityUpdated += null, null, deviceServiceIdentity);
            deviceScopeIdentitiesCache.Raise(d => d.ServiceIdentityUpdated += null, null, moduleServiceIdentity);

            // Assert
            Assert.NotNull(connectionReauthenticator);
            connectionManager.Verify(c => c.RemoveDeviceConnection("d1"), Times.Never);
            connectionManager.Verify(c => c.RemoveDeviceConnection("d1/m1"), Times.Never);
            connectionManager.Verify(c => c.GetDeviceConnection("d1"), Times.Once);
            connectionManager.Verify(c => c.GetDeviceConnection("d1/m1"), Times.Once);
            authenticator.VerifyAll();
            credentialsStore.VerifyAll();
            deviceScopeIdentitiesCache.VerifyAll();
        }
        public async Task TestConnectionReauthentication_MultipleLoopsTest()
        {
            // Arrange
            var      connectionManager          = new Mock <IConnectionManager>(MockBehavior.Strict);
            var      authenticator              = new Mock <IAuthenticator>(MockBehavior.Strict);
            var      credentialsStore           = new Mock <ICredentialsCache>(MockBehavior.Strict);
            var      deviceScopeIdentitiesCache = Mock.Of <IDeviceScopeIdentitiesCache>();
            var      deviceConnectivityManager  = Mock.Of <IDeviceConnectivityManager>();
            TimeSpan reauthFrequency            = TimeSpan.FromSeconds(5);

            var deviceIdentity = new DeviceIdentity(IoTHubHostName, "d1");
            var moduleIdentity = new ModuleIdentity(IoTHubHostName, "d1", "m1");
            var clients        = new List <IIdentity>
            {
                deviceIdentity,
                moduleIdentity
            };

            connectionManager.Setup(c => c.GetConnectedClients()).Returns(clients);
            connectionManager.Setup(c => c.RemoveDeviceConnection("d1")).Returns(Task.CompletedTask);

            var deviceCredentials = Mock.Of <IClientCredentials>(c => c.Identity == deviceIdentity && c.AuthenticationType == AuthenticationType.SasKey);
            var moduleCredentials = Mock.Of <IClientCredentials>(c => c.Identity == moduleIdentity && c.AuthenticationType == AuthenticationType.SasKey);

            credentialsStore.Setup(c => c.Get(deviceIdentity)).ReturnsAsync(Option.Some(deviceCredentials));
            credentialsStore.Setup(c => c.Get(moduleIdentity)).ReturnsAsync(Option.Some(moduleCredentials));

            authenticator.SetupSequence(a => a.ReauthenticateAsync(deviceCredentials))
            .ReturnsAsync(true)
            .ReturnsAsync(false);
            authenticator.SetupSequence(a => a.ReauthenticateAsync(moduleCredentials))
            .ReturnsAsync(true)
            .ReturnsAsync(true);

            // Act
            var connectionReauthenticator = new ConnectionReauthenticator(
                connectionManager.Object,
                authenticator.Object,
                credentialsStore.Object,
                deviceScopeIdentitiesCache,
                reauthFrequency,
                Mock.Of <IIdentity>(e => e.Id == "ed/$edgeHub"),
                deviceConnectivityManager);

            connectionReauthenticator.Init();

            // Assert
            connectionManager.Verify(c => c.GetConnectedClients(), Times.Never);

            await Task.Delay(reauthFrequency * 2 + TimeSpan.FromSeconds(1));

            connectionManager.Verify(c => c.GetConnectedClients(), Times.Exactly(2));
            connectionManager.VerifyAll();
            authenticator.VerifyAll();
            credentialsStore.VerifyAll();
            Mock.Get(deviceScopeIdentitiesCache).VerifyAll();
        }
Exemple #5
0
        static async Task <int> MainAsync(IConfigurationRoot configuration)
        {
            string logLevel = configuration.GetValue($"{Logger.RuntimeLogLevelEnvKey}", "info");

            Logger.SetLogLevel(logLevel);

            // Set the LoggerFactory used by the Routing code.
            if (configuration.GetValue("EnableRoutingLogging", false))
            {
                Routing.LoggerFactory = Logger.Factory;
            }

            ILogger logger = Logger.Factory.CreateLogger("EdgeHub");

            EdgeHubCertificates certificates = await EdgeHubCertificates.LoadAsync(configuration, logger);

            bool clientCertAuthEnabled = configuration.GetValue(Constants.ConfigKey.EdgeHubClientCertAuthEnabled, false);

            string       sslProtocolsConfig = configuration.GetValue(Constants.ConfigKey.SslProtocols, string.Empty);
            SslProtocols sslProtocols       = SslProtocolsHelper.Parse(sslProtocolsConfig, DefaultSslProtocols, logger);

            logger.LogInformation($"Enabling SSL protocols: {sslProtocols.Print()}");

            IDependencyManager dependencyManager = new DependencyManager(configuration, certificates.ServerCertificate, certificates.TrustBundle, sslProtocols);
            Hosting            hosting           = Hosting.Initialize(configuration, certificates.ServerCertificate, dependencyManager, clientCertAuthEnabled, sslProtocols);
            IContainer         container         = hosting.Container;

            logger.LogInformation("Initializing Edge Hub");
            LogLogo(logger);
            LogVersionInfo(logger);
            logger.LogInformation($"OptimizeForPerformance={configuration.GetValue("OptimizeForPerformance", true)}");
            logger.LogInformation($"MessageAckTimeoutSecs={configuration.GetValue("MessageAckTimeoutSecs", 30)}");
            logger.LogInformation("Loaded server certificate with expiration date of {0}", certificates.ServerCertificate.NotAfter.ToString("o"));

            var metricsProvider = container.Resolve <IMetricsProvider>();

            Metrics.InitWithAspNet(metricsProvider, logger); // Note this requires App.UseMetricServer() to be called in Startup.cs

            // Init V0 Metrics
            MetricsV0.BuildMetricsCollector(configuration);

            // EdgeHub and CloudConnectionProvider have a circular dependency. So need to Bind the EdgeHub to the CloudConnectionProvider.
            IEdgeHub edgeHub = await container.Resolve <Task <IEdgeHub> >();

            ICloudConnectionProvider cloudConnectionProvider = await container.Resolve <Task <ICloudConnectionProvider> >();

            cloudConnectionProvider.BindEdgeHub(edgeHub);

            // EdgeHub cloud proxy and DeviceConnectivityManager have a circular dependency,
            // so the cloud proxy has to be set on the DeviceConnectivityManager after both have been initialized.
            var deviceConnectivityManager        = container.Resolve <IDeviceConnectivityManager>();
            IConnectionManager connectionManager = await container.Resolve <Task <IConnectionManager> >();

            (deviceConnectivityManager as DeviceConnectivityManager)?.SetConnectionManager(connectionManager);

            // Register EdgeHub credentials
            var edgeHubCredentials             = container.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
            ICredentialsCache credentialsCache = await container.Resolve <Task <ICredentialsCache> >();

            await credentialsCache.Add(edgeHubCredentials);

            // Initializing configuration
            logger.LogInformation("Initializing configuration");
            IConfigSource configSource = await container.Resolve <Task <IConfigSource> >();

            ConfigUpdater configUpdater = await container.Resolve <Task <ConfigUpdater> >();

            await configUpdater.Init(configSource);

            if (!Enum.TryParse(configuration.GetValue("AuthenticationMode", string.Empty), true, out AuthenticationMode authenticationMode) ||
                authenticationMode != AuthenticationMode.Cloud)
            {
                ConnectionReauthenticator connectionReauthenticator = await container.Resolve <Task <ConnectionReauthenticator> >();

                connectionReauthenticator.Init();
            }

            TimeSpan shutdownWaitPeriod = TimeSpan.FromSeconds(configuration.GetValue("ShutdownWaitPeriod", DefaultShutdownWaitPeriod));

            (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(shutdownWaitPeriod, logger);

            using (IProtocolHead protocolHead = await GetEdgeHubProtocolHeadAsync(logger, configuration, container, hosting))
                using (var renewal = new CertificateRenewal(certificates, logger))
                {
                    await protocolHead.StartAsync();

                    await Task.WhenAny(cts.Token.WhenCanceled(), renewal.Token.WhenCanceled());

                    logger.LogInformation("Stopping the protocol heads...");
                    await protocolHead.CloseAsync(CancellationToken.None);

                    logger.LogInformation("Protocol heads stopped.");

                    await CloseDbStoreProviderAsync(container);
                }

            completed.Set();
            handler.ForEach(h => GC.KeepAlive(h));
            logger.LogInformation("Shutdown complete.");
            return(0);
        }
Exemple #6
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);
        }
Exemple #7
0
        static async Task <int> MainAsync(IConfigurationRoot configuration)
        {
            string logLevel = configuration.GetValue($"{Logger.RuntimeLogLevelEnvKey}", "info");

            Logger.SetLogLevel(logLevel);

            // Set the LoggerFactory used by the Routing code.
            if (configuration.GetValue("EnableRoutingLogging", false))
            {
                Routing.LoggerFactory = Logger.Factory;
            }

            EdgeHubCertificates certificates = await EdgeHubCertificates.LoadAsync(configuration);

            bool       clientCertAuthEnabled = configuration.GetValue(Constants.ConfigKey.EdgeHubClientCertAuthEnabled, false);
            Hosting    hosting   = Hosting.Initialize(configuration, certificates.ServerCertificate, new DependencyManager(configuration, certificates.ServerCertificate, certificates.TrustBundle), clientCertAuthEnabled);
            IContainer container = hosting.Container;

            ILogger logger = container.Resolve <ILoggerFactory>().CreateLogger("EdgeHub");

            logger.LogInformation("Initializing Edge Hub");
            LogLogo(logger);
            LogVersionInfo(logger);

            logger.LogInformation("Loaded server certificate with expiration date of {0}", certificates.ServerCertificate.NotAfter.ToString("o"));

            // EdgeHub and CloudConnectionProvider have a circular dependency. So need to Bind the EdgeHub to the CloudConnectionProvider.
            IEdgeHub edgeHub = await container.Resolve <Task <IEdgeHub> >();

            ICloudConnectionProvider cloudConnectionProvider = await container.Resolve <Task <ICloudConnectionProvider> >();

            cloudConnectionProvider.BindEdgeHub(edgeHub);

            // EdgeHub cloud proxy and DeviceConnectivityManager have a circular dependency,
            // so the cloud proxy has to be set on the DeviceConnectivityManager after both have been initialized.
            var deviceConnectivityManager        = container.Resolve <IDeviceConnectivityManager>();
            IConnectionManager connectionManager = await container.Resolve <Task <IConnectionManager> >();

            (deviceConnectivityManager as DeviceConnectivityManager)?.SetConnectionManager(connectionManager);

            // Register EdgeHub credentials
            var edgeHubCredentials             = container.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
            ICredentialsCache credentialsCache = await container.Resolve <Task <ICredentialsCache> >();

            await credentialsCache.Add(edgeHubCredentials);

            // Initializing configuration
            logger.LogInformation("Initializing configuration");
            IConfigSource configSource = await container.Resolve <Task <IConfigSource> >();

            ConfigUpdater configUpdater = await container.Resolve <Task <ConfigUpdater> >();

            await configUpdater.Init(configSource);

            if (!Enum.TryParse(configuration.GetValue("AuthenticationMode", string.Empty), true, out AuthenticationMode authenticationMode) ||
                authenticationMode != AuthenticationMode.Cloud)
            {
                ConnectionReauthenticator connectionReauthenticator = await container.Resolve <Task <ConnectionReauthenticator> >();

                connectionReauthenticator.Init();
            }

            (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(ShutdownWaitPeriod, logger);

            Metrics.BuildMetricsCollector(configuration);

            using (IProtocolHead protocolHead = await GetEdgeHubProtocolHeadAsync(logger, configuration, container, hosting))
                using (var renewal = new CertificateRenewal(certificates, logger))
                {
                    await protocolHead.StartAsync();

                    await Task.WhenAny(cts.Token.WhenCanceled(), renewal.Token.WhenCanceled());

                    logger.LogInformation("Stopping the protocol heads...");
                    await Task.WhenAny(protocolHead.CloseAsync(CancellationToken.None), Task.Delay(TimeSpan.FromSeconds(10), CancellationToken.None));

                    logger.LogInformation("Protocol heads stopped.");
                }

            completed.Set();
            handler.ForEach(h => GC.KeepAlive(h));
            logger.LogInformation("Shutdown complete.");
            return(0);
        }
Exemple #8
0
        static async Task <int> MainAsync(IConfigurationRoot configuration)
        {
            string logLevel = configuration.GetValue($"{Logger.RuntimeLogLevelEnvKey}", "info");

            Logger.SetLogLevel(logLevel);

            // Set the LoggerFactory used by the Routing code.
            if (configuration.GetValue("EnableRoutingLogging", false))
            {
                Routing.LoggerFactory = Logger.Factory;
            }

            ILogger logger = Logger.Factory.CreateLogger("EdgeHub");

            EdgeHubCertificates certificates = await EdgeHubCertificates.LoadAsync(configuration, logger);

            bool clientCertAuthEnabled = configuration.GetValue(Constants.ConfigKey.EdgeHubClientCertAuthEnabled, false);

            string       sslProtocolsConfig = configuration.GetValue(Constants.ConfigKey.SslProtocols, string.Empty);
            SslProtocols sslProtocols       = SslProtocolsHelper.Parse(sslProtocolsConfig, DefaultSslProtocols, logger);

            logger.LogInformation($"Enabling SSL protocols: {sslProtocols.Print()}");

            IDependencyManager dependencyManager = new DependencyManager(configuration, certificates.ServerCertificate, certificates.TrustBundle, certificates.ManifestTrustBundle, sslProtocols);
            Hosting            hosting           = Hosting.Initialize(configuration, certificates.ServerCertificate, dependencyManager, clientCertAuthEnabled, sslProtocols);
            IContainer         container         = hosting.Container;

            logger.LogInformation("Initializing Edge Hub");
            LogLogo(logger);
            LogVersionInfo(logger);
            logger.LogInformation($"OptimizeForPerformance={configuration.GetValue("OptimizeForPerformance", true)}");
            logger.LogInformation($"MessageAckTimeoutSecs={configuration.GetValue("MessageAckTimeoutSecs", 30)}");
            logger.LogInformation("Loaded server certificate with expiration date of {0}", certificates.ServerCertificate.NotAfter.ToString("o"));

            var metricsProvider = container.Resolve <IMetricsProvider>();

            Metrics.InitWithAspNet(metricsProvider, logger); // Note this requires App.UseMetricServer() to be called in Startup.cs

            // EdgeHub and CloudConnectionProvider have a circular dependency. So need to Bind the EdgeHub to the CloudConnectionProvider.
            IEdgeHub edgeHub = await container.Resolve <Task <IEdgeHub> >();

            ICloudConnectionProvider cloudConnectionProvider = await container.Resolve <Task <ICloudConnectionProvider> >();

            cloudConnectionProvider.BindEdgeHub(edgeHub);

            // EdgeHub cloud proxy and DeviceConnectivityManager have a circular dependency,
            // so the cloud proxy has to be set on the DeviceConnectivityManager after both have been initialized.
            var deviceConnectivityManager        = container.Resolve <IDeviceConnectivityManager>();
            IConnectionManager connectionManager = await container.Resolve <Task <IConnectionManager> >();

            (deviceConnectivityManager as DeviceConnectivityManager)?.SetConnectionManager(connectionManager);

            // Register EdgeHub credentials
            var edgeHubCredentials             = container.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
            ICredentialsCache credentialsCache = await container.Resolve <Task <ICredentialsCache> >();

            await credentialsCache.Add(edgeHubCredentials);

            // Register EdgeHub indentity in device scopes cache.
            // When we connect upstream, we verify that identity is in scope.
            // On a fresh start, we may not yet received the scopes from the upstream, so we need
            // to force add edgeHub in the cache so it is able to connect upstream.
            // Once we get the scopes from the upstream, this record is replaced.
            ServiceIdentity           edgeHubIdentity = container.ResolveNamed <ServiceIdentity>("EdgeHubIdentity");
            IServiceIdentityHierarchy identityScopes  = container.Resolve <IServiceIdentityHierarchy>();
            await identityScopes.InsertOrUpdate(edgeHubIdentity);

            // Initializing configuration
            logger.LogInformation("Initializing configuration");
            IConfigSource configSource = await container.Resolve <Task <IConfigSource> >();

            ConfigUpdater configUpdater = await container.Resolve <Task <ConfigUpdater> >();

            ExperimentalFeatures experimentalFeatures = CreateExperimentalFeatures(configuration);
            var configUpdaterStartupFailed            = new TaskCompletionSource <bool>();
            var configDownloadTask = configUpdater.Init(configSource);

            _ = configDownloadTask.ContinueWith(
                _ => configUpdaterStartupFailed.SetResult(false),
                TaskContinuationOptions.OnlyOnFaulted);

            if (!Enum.TryParse(configuration.GetValue("AuthenticationMode", string.Empty), true, out AuthenticationMode authenticationMode) ||
                authenticationMode != AuthenticationMode.Cloud)
            {
                ConnectionReauthenticator connectionReauthenticator = await container.Resolve <Task <ConnectionReauthenticator> >();

                connectionReauthenticator.Init();
            }

            TimeSpan shutdownWaitPeriod = TimeSpan.FromSeconds(configuration.GetValue("ShutdownWaitPeriod", DefaultShutdownWaitPeriod));

            (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(shutdownWaitPeriod, logger);

            using (IProtocolHead mqttBrokerProtocolHead = await GetMqttBrokerProtocolHeadAsync(experimentalFeatures, container))
                using (IProtocolHead edgeHubProtocolHead = await GetEdgeHubProtocolHeadAsync(logger, configuration, experimentalFeatures, container, hosting))
                    using (var renewal = new CertificateRenewal(certificates, logger))
                    {
                        try
                        {
                            await Task.WhenAll(mqttBrokerProtocolHead.StartAsync(), configDownloadTask);

                            await edgeHubProtocolHead.StartAsync();

                            await Task.WhenAny(cts.Token.WhenCanceled(), renewal.Token.WhenCanceled(), configUpdaterStartupFailed.Task);
                        }
                        catch (Exception ex)
                        {
                            logger.LogError($"Error starting protocol heads: {ex.Message}");
                        }

                        logger.LogInformation("Stopping the protocol heads...");
                        await Task.WhenAll(mqttBrokerProtocolHead.CloseAsync(CancellationToken.None), edgeHubProtocolHead.CloseAsync(CancellationToken.None));

                        logger.LogInformation("Protocol heads stopped.");

                        await CloseDbStoreProviderAsync(container);
                    }

            completed.Set();
            handler.ForEach(h => GC.KeepAlive(h));
            logger.LogInformation("Shutdown complete.");
            return(0);
        }
Exemple #9
0
        public static async Task <int> MainAsync(IConfigurationRoot configuration)
        {
            string logLevel = configuration.GetValue($"{Logger.RuntimeLogLevelEnvKey}", "info");

            Logger.SetLogLevel(logLevel);

            // Set the LoggerFactory used by the Routing code.
            if (configuration.GetValue("EnableRoutingLogging", false))
            {
                Routing.Core.Routing.LoggerFactory = Logger.Factory;
            }

            X509Certificate2 cert;
            IEnumerable <X509Certificate2> chain;
            string edgeHubConnectionString = configuration.GetValue <string>(Constants.IotHubConnectionStringVariableName);

            // When connection string is not set it is edged mode
            if (string.IsNullOrEmpty(edgeHubConnectionString))
            {
                var      workloadUri     = new Uri(configuration.GetValue <string>(Constants.WorkloadUriVariableName));
                string   edgeHubHostname = configuration.GetValue <string>(Constants.EdgeDeviceHostnameVariableName);
                string   moduleId        = configuration.GetValue <string>(Constants.ModuleIdVariableName);
                string   generationId    = configuration.GetValue <string>(Constants.ModuleGenerationIdVariableName);
                DateTime expiration      = DateTime.UtcNow.AddDays(Constants.CertificateValidityDays);
                (cert, chain) = await CertificateHelper.GetServerCertificatesFromEdgelet(workloadUri, Constants.WorkloadApiVersion, moduleId, generationId, edgeHubHostname, expiration);
            }
            else
            {
                string edgeHubCertPath = configuration.GetValue <string>(Constants.EdgeHubServerCertificateFileKey);
                cert = new X509Certificate2(edgeHubCertPath);
                string edgeHubCaChainCertPath = configuration.GetValue <string>(Constants.EdgeHubServerCAChainCertificateFileKey);
                chain = CertificateHelper.GetServerCACertificatesFromFile(edgeHubCaChainCertPath);
            }

            // TODO: set certificate for Startup without the cache
            ServerCertificateCache.X509Certificate = cert;

            int     port    = configuration.GetValue("httpSettings:port", 443);
            Hosting hosting = Hosting.Initialize(port);

            IContainer container = hosting.Container;

            ILogger logger = container.Resolve <ILoggerFactory>().CreateLogger("EdgeHub");

            logger.LogInformation("Starting Edge Hub");
            VersionInfo versionInfo = VersionInfo.Get(Constants.VersionInfoFileName);

            if (versionInfo != VersionInfo.Empty)
            {
                logger.LogInformation($"Version - {versionInfo.ToString(true)}");
            }
            LogLogo(logger);

            if (chain != null)
            {
                logger.LogInformation("Installing intermediate certificates.");

                CertificateHelper.InstallCerts(
                    RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? StoreName.CertificateAuthority : StoreName.Root,
                    StoreLocation.CurrentUser,
                    chain);
            }
            else
            {
                logger.LogWarning("Unable to find intermediate certificates.");
            }

            // EdgeHub and CloudConnectionProvider have a circular dependency. So need to Bind the EdgeHub to the CloudConnectionProvider.
            IEdgeHub edgeHub = await container.Resolve <Task <IEdgeHub> >();

            ICloudConnectionProvider cloudConnectionProvider = await container.Resolve <Task <ICloudConnectionProvider> >();

            cloudConnectionProvider.BindEdgeHub(edgeHub);

            // Register EdgeHub credentials
            var edgeHubCredentials             = container.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
            ICredentialsCache credentialsCache = await container.Resolve <Task <ICredentialsCache> >();

            await credentialsCache.Add(edgeHubCredentials);

            // EdgeHub cloud proxy and DeviceConnectivityManager have a circular dependency,
            // so the cloud proxy has to be set on the DeviceConnectivityManager after both have been initialized.
            var deviceConnectivityManager        = container.Resolve <IDeviceConnectivityManager>();
            IConnectionManager connectionManager = await container.Resolve <Task <IConnectionManager> >();

            (deviceConnectivityManager as DeviceConnectivityManager)?.SetConnectionManager(connectionManager);

            // Initializing configuration
            logger.LogInformation("Initializing configuration");
            IConfigSource configSource = await container.Resolve <Task <IConfigSource> >();

            ConfigUpdater configUpdater = await container.Resolve <Task <ConfigUpdater> >();

            await configUpdater.Init(configSource);

            if (!Enum.TryParse(configuration.GetValue("AuthenticationMode", string.Empty), true, out AuthenticationMode authenticationMode) ||
                authenticationMode != AuthenticationMode.Cloud)
            {
                ConnectionReauthenticator connectionReauthenticator = await container.Resolve <Task <ConnectionReauthenticator> >();

                connectionReauthenticator.Init();
            }

            (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler)
                = ShutdownHandler.Init(ShutdownWaitPeriod, logger);

            var protocolHeads = new List <IProtocolHead>();

            if (configuration.GetValue("mqttSettings:enabled", true))
            {
                protocolHeads.Add(await container.Resolve <Task <MqttProtocolHead> >());
            }

            if (configuration.GetValue("amqpSettings:enabled", true))
            {
                protocolHeads.Add(await container.Resolve <Task <AmqpProtocolHead> >());
            }

            if (configuration.GetValue("httpSettings:enabled", true))
            {
                protocolHeads.Add(new HttpProtocolHead(hosting.WebHost));
            }

            using (IProtocolHead protocolHead = new EdgeHubProtocolHead(protocolHeads, logger))
            {
                await protocolHead.StartAsync();

                await cts.Token.WhenCanceled();

                await Task.WhenAny(protocolHead.CloseAsync(CancellationToken.None), Task.Delay(TimeSpan.FromSeconds(10), CancellationToken.None));
            }

            completed.Set();
            handler.ForEach(h => GC.KeepAlive(h));
            return(0);
        }
Exemple #10
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);
        }