Example #1
0
 public CloudConnectionProvider(
     IMessageConverterProvider messageConverterProvider,
     int connectionPoolSize,
     IClientProvider clientProvider,
     Option <UpstreamProtocol> upstreamProtocol,
     ITokenProvider edgeHubTokenProvider,
     IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
     ICredentialsCache credentialsCache,
     IIdentity edgeHubIdentity,
     TimeSpan idleTimeout,
     bool closeOnIdleTimeout,
     TimeSpan operationTimeout,
     bool useServerHeartbeat,
     Option <IWebProxy> proxy,
     IMetadataStore metadataStore,
     bool nestedEdgeEnabled = false)
 {
     this.messageConverterProvider = Preconditions.CheckNotNull(messageConverterProvider, nameof(messageConverterProvider));
     this.clientProvider           = Preconditions.CheckNotNull(clientProvider, nameof(clientProvider));
     this.upstreamProtocol         = upstreamProtocol;
     this.connectionPoolSize       = Preconditions.CheckRange(connectionPoolSize, 1, nameof(connectionPoolSize));
     this.proxy                      = proxy;
     this.edgeHub                    = Option.None <IEdgeHub>();
     this.idleTimeout                = idleTimeout;
     this.closeOnIdleTimeout         = closeOnIdleTimeout;
     this.useServerHeartbeat         = useServerHeartbeat;
     this.edgeHubTokenProvider       = Preconditions.CheckNotNull(edgeHubTokenProvider, nameof(edgeHubTokenProvider));
     this.deviceScopeIdentitiesCache = Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));
     this.credentialsCache           = Preconditions.CheckNotNull(credentialsCache, nameof(credentialsCache));
     this.edgeHubIdentity            = Preconditions.CheckNotNull(edgeHubIdentity, nameof(edgeHubIdentity));
     this.operationTimeout           = operationTimeout;
     this.metadataStore              = Preconditions.CheckNotNull(metadataStore, nameof(metadataStore));
     this.nestedEdgeEnabled          = nestedEdgeEnabled;
 }
Example #2
0
        public static async Task <EdgeHubConnection> Create(
            IIdentity edgeHubIdentity,
            IEdgeHub edgeHub,
            ITwinManager twinManager,
            IConnectionManager connectionManager,
            RouteFactory routeFactory,
            IMessageConverter <TwinCollection> twinCollectionMessageConverter,
            VersionInfo versionInfo,
            IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache)
        {
            Preconditions.CheckNotNull(edgeHubIdentity, nameof(edgeHubIdentity));
            Preconditions.CheckNotNull(edgeHub, nameof(edgeHub));
            Preconditions.CheckNotNull(connectionManager, nameof(connectionManager));
            Preconditions.CheckNotNull(twinCollectionMessageConverter, nameof(twinCollectionMessageConverter));
            Preconditions.CheckNotNull(routeFactory, nameof(routeFactory));
            Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));

            var edgeHubConnection = new EdgeHubConnection(
                edgeHubIdentity,
                twinManager,
                routeFactory,
                twinCollectionMessageConverter,
                versionInfo ?? VersionInfo.Empty,
                deviceScopeIdentitiesCache);

            await InitEdgeHub(edgeHubConnection, connectionManager, edgeHubIdentity, edgeHub);

            connectionManager.DeviceConnected    += edgeHubConnection.DeviceConnected;
            connectionManager.DeviceDisconnected += edgeHubConnection.DeviceDisconnected;
            Events.Initialized(edgeHubIdentity);
            return(edgeHubConnection);
        }
Example #3
0
 public CloudConnectionProvider(
     IMessageConverterProvider messageConverterProvider,
     int connectionPoolSize,
     IClientProvider clientProvider,
     Option <UpstreamProtocol> upstreamProtocol,
     ITokenProvider edgeHubTokenProvider,
     IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
     ICredentialsCache credentialsCache,
     IIdentity edgeHubIdentity,
     TimeSpan idleTimeout,
     bool closeOnIdleTimeout,
     TimeSpan operationTimeout,
     Option <IWebProxy> proxy,
     IProductInfoStore productInfoStore)
 {
     Preconditions.CheckRange(connectionPoolSize, 1, nameof(connectionPoolSize));
     this.messageConverterProvider = Preconditions.CheckNotNull(messageConverterProvider, nameof(messageConverterProvider));
     this.clientProvider           = Preconditions.CheckNotNull(clientProvider, nameof(clientProvider));
     this.transportSettings        = GetTransportSettings(upstreamProtocol, connectionPoolSize, proxy);
     this.edgeHub                    = Option.None <IEdgeHub>();
     this.idleTimeout                = idleTimeout;
     this.closeOnIdleTimeout         = closeOnIdleTimeout;
     this.edgeHubTokenProvider       = Preconditions.CheckNotNull(edgeHubTokenProvider, nameof(edgeHubTokenProvider));
     this.deviceScopeIdentitiesCache = Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));
     this.credentialsCache           = Preconditions.CheckNotNull(credentialsCache, nameof(credentialsCache));
     this.edgeHubIdentity            = Preconditions.CheckNotNull(edgeHubIdentity, nameof(edgeHubIdentity));
     this.operationTimeout           = operationTimeout;
     this.productInfoStore           = Preconditions.CheckNotNull(productInfoStore, nameof(productInfoStore));
 }
Example #4
0
        async Task <EdgeHubScopeResult> HandleDevicesAndModulesInTargetDeviceScopeAsync(string actorDeviceId, string actorModuleId, NestedScopeRequest request)
        {
            Events.ReceivedScopeRequest(actorDeviceId, actorModuleId, request);
            Preconditions.CheckNonWhiteSpace(request.AuthChain, nameof(request.AuthChain));

            if (!this.TryGetTargetDeviceId(request.AuthChain, out string targetDeviceId))
            {
                return(new EdgeHubScopeResultError(HttpStatusCode.BadRequest, Events.InvalidRequestAuthchain(request.AuthChain)));
            }

            // Check that the actor device is authorized to act OnBehalfOf the target
            IEdgeHub edgeHub = await this.edgeHubGetter;
            IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache();

            if (!await this.AuthorizeActorAsync(identitiesCache, actorDeviceId, actorModuleId, targetDeviceId))
            {
                return(new EdgeHubScopeResultError(HttpStatusCode.Unauthorized, Events.UnauthorizedActor(actorDeviceId, actorModuleId, targetDeviceId)));
            }

            // Get the children of the target device and the target device itself;
            IList <ServiceIdentity> identities = await identitiesCache.GetDevicesAndModulesInTargetScopeAsync(targetDeviceId);

            Option <ServiceIdentity> targetDevice = await identitiesCache.GetServiceIdentity(targetDeviceId);

            targetDevice.ForEach(d => identities.Add(d));

            // Construct the result from the identities
            Events.SendingScopeResult(targetDeviceId, identities);
            return(MakeResultFromIdentities(identities));
        }
        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()));
        }
Example #6
0
        async Task <bool> AuthorizeActorAsync(IDeviceScopeIdentitiesCache identitiesCache, string actorDeviceId, string actorModuleId, string targetId)
        {
            if (actorModuleId != Constants.EdgeHubModuleId)
            {
                // Only child EdgeHubs are allowed to act OnBehalfOf of devices/modules.
                Events.AuthFail_BadActor(actorDeviceId, actorModuleId, targetId);
                return(false);
            }

            // Actor device is claiming to be our child, and that the target device is its child.
            // So we should have an authchain already cached for the target device.
            Option <string> targetAuthChainOption = await identitiesCache.GetAuthChain(targetId);

            if (!targetAuthChainOption.HasValue)
            {
                Events.AuthFail_NoAuthChain(targetId);
                return(false);
            }

            // Validate the target auth-chain
            string targetAuthChain = targetAuthChainOption.Expect(() => new InvalidOperationException());

            if (!AuthChainHelpers.ValidateAuthChain(actorDeviceId, targetId, targetAuthChain))
            {
                Events.AuthFail_InvalidAuthChain(actorDeviceId, targetId, targetAuthChain);
                return(false);
            }

            return(true);
        }
Example #7
0
        public async Task GetDeviceAndModuleOnBehalfOfAsync([FromRoute] string actorDeviceId, [FromRoute] string actorModuleId, [FromBody] IdentityOnBehalfOfRequest request)
        {
            actorDeviceId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(actorDeviceId, nameof(actorDeviceId)));
            actorModuleId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(actorModuleId, nameof(actorModuleId)));
            Preconditions.CheckNonWhiteSpace(request.AuthChain, nameof(request.AuthChain));

            if (actorModuleId != Constants.EdgeHubModuleId)
            {
                // Only child EdgeHubs are allowed to act OnBehalfOf of devices/modules.
                var result = new EdgeHubScopeResultError(HttpStatusCode.Unauthorized, Events.UnauthorizedActor(actorDeviceId, actorModuleId, string.IsNullOrWhiteSpace(request.TargetModuleId) ? request.TargetDeviceId : $"{request.TargetDeviceId}/{request.TargetModuleId}"));
                await this.SendResponse(result.Status, JsonConvert.SerializeObject(result));
            }

            IHttpRequestAuthenticator authenticator = await this.authenticatorGetter;
            HttpAuthResult            authResult    = await authenticator.AuthenticateAsync(actorDeviceId, Option.Some(actorModuleId), Option.Some(request.AuthChain), this.HttpContext);

            if (authResult.Authenticated)
            {
                IEdgeHub edgeHub = await this.edgeHubGetter;
                IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache();
                EdgeHubScopeResult          reqResult       = await HandleGetDeviceAndModuleOnBehalfOfAsync(actorDeviceId, actorModuleId, request, identitiesCache);

                await this.SendResponse(reqResult.Status, JsonConvert.SerializeObject(reqResult));
            }
            else
            {
                var result = new EdgeHubScopeResultError(HttpStatusCode.Unauthorized, authResult.ErrorMessage);
                await this.SendResponse(result.Status, JsonConvert.SerializeObject(result));
            }
        }
 public DeviceScopeCertificateAuthenticator(
     IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
     IAuthenticator underlyingAuthenticator,
     IList <X509Certificate2> trustBundle,
     bool syncServiceIdentityOnFailure)
     : base(deviceScopeIdentitiesCache, underlyingAuthenticator, false, syncServiceIdentityOnFailure)
 {
     this.trustBundle = Preconditions.CheckNotNull(trustBundle, nameof(trustBundle));
 }
Example #9
0
        public async Task DeleteModuleAsync(
            [FromRoute] string deviceId,
            [FromRoute] string moduleId)
        {
            try
            {
                Events.ReceivedRequest(nameof(this.DeleteModuleAsync), deviceId, moduleId);

                try
                {
                    deviceId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(deviceId, nameof(deviceId)));
                    moduleId = WebUtility.UrlDecode(Preconditions.CheckNonWhiteSpace(moduleId, nameof(moduleId)));
                }
                catch (Exception ex)
                {
                    Events.BadRequest(nameof(this.DeleteModuleAsync), ex.Message);
                    await this.SendResponseAsync(HttpStatusCode.BadRequest, FormatErrorResponseMessage(ex.Message));

                    return;
                }

                IHttpRequestAuthenticator authenticator = await this.authenticatorGetter;
                if (!await AuthenticateAsync(deviceId, Option.None <string>(), Option.None <string>(), this.HttpContext, authenticator))
                {
                    await this.SendResponseAsync(HttpStatusCode.Unauthorized);

                    return;
                }

                IEdgeHub edgeHub = await this.edgeHubGetter;
                IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache();
                Option <string>             targetAuthChain = await identitiesCache.GetAuthChain(deviceId);

                if (!targetAuthChain.HasValue)
                {
                    Events.AuthorizationFail_NoAuthChain(deviceId);
                    await this.SendResponseAsync(HttpStatusCode.Unauthorized);

                    return;
                }

                string edgeDeviceId          = edgeHub.GetEdgeDeviceId();
                var    requestData           = new DeleteModuleOnBehalfOfData($"{targetAuthChain.OrDefault()}", moduleId);
                RegistryApiHttpResult result = await this.apiClient.DeleteModuleAsync(edgeDeviceId, requestData);

                await this.SendResponseAsync(result.StatusCode, result.JsonContent);

                Events.CompleteRequest(nameof(this.DeleteModuleAsync), edgeDeviceId, requestData.AuthChain, result);
            }
            catch (Exception ex)
            {
                Events.InternalServerError(nameof(this.DeleteModuleAsync), ex);
                await this.SendResponseAsync(HttpStatusCode.InternalServerError, FormatErrorResponseMessage(ex.ToString()));
            }
        }
 protected DeviceScopeAuthenticator(
     IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
     IAuthenticator underlyingAuthenticator,
     bool allowDeviceAuthForModule,
     bool syncServiceIdentityOnFailure)
 {
     this.underlyingAuthenticator      = Preconditions.CheckNotNull(underlyingAuthenticator, nameof(underlyingAuthenticator));
     this.deviceScopeIdentitiesCache   = Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));
     this.allowDeviceAuthForModule     = allowDeviceAuthForModule;
     this.syncServiceIdentityOnFailure = syncServiceIdentityOnFailure;
 }
Example #11
0
 public DeviceScopeTokenAuthenticator(
     IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
     string iothubHostName,
     string edgeHubHostName,
     IAuthenticator underlyingAuthenticator)
 {
     this.underlyingAuthenticator    = Preconditions.CheckNotNull(underlyingAuthenticator, nameof(underlyingAuthenticator));
     this.deviceScopeIdentitiesCache = Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));
     this.iothubHostName             = Preconditions.CheckNonWhiteSpace(iothubHostName, nameof(iothubHostName));
     this.edgeHubHostName            = Preconditions.CheckNotNull(edgeHubHostName, nameof(edgeHubHostName));
 }
 public DeviceScopeTokenAuthenticator(
     IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
     string iothubHostName,
     string edgeHubHostName,
     IAuthenticator underlyingAuthenticator,
     bool allowDeviceAuthForModule,
     bool syncServiceIdentityOnFailure)
     : base(deviceScopeIdentitiesCache, underlyingAuthenticator, allowDeviceAuthForModule, syncServiceIdentityOnFailure)
 {
     this.iothubHostName  = Preconditions.CheckNonWhiteSpace(iothubHostName, nameof(iothubHostName));
     this.edgeHubHostName = Preconditions.CheckNotNull(edgeHubHostName, nameof(edgeHubHostName));
 }
Example #13
0
 public DeviceScopeTokenAuthenticator(IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
                                      string iothubHostName,
                                      string edgeHubHostName,
                                      IAuthenticator underlyingAuthenticator,
                                      IConnectionManager connectionManager)
 {
     this.underlyingAuthenticator    = Preconditions.CheckNotNull(underlyingAuthenticator, nameof(underlyingAuthenticator));
     this.deviceScopeIdentitiesCache = Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));
     this.iothubHostName             = Preconditions.CheckNonWhiteSpace(iothubHostName, nameof(iothubHostName));
     this.edgeHubHostName            = Preconditions.CheckNotNull(edgeHubHostName, nameof(edgeHubHostName));
     this.connectionManager          = Preconditions.CheckNotNull(connectionManager, nameof(connectionManager));
     this.deviceScopeIdentitiesCache.ServiceIdentityUpdated += this.HandleServiceIdentityUpdate;
     this.deviceScopeIdentitiesCache.ServiceIdentityRemoved += this.HandleServiceIdentityRemove;
 }
Example #14
0
 internal EdgeHubConnection(
     IIdentity edgeHubIdentity,
     ITwinManager twinManager,
     RouteFactory routeFactory,
     IMessageConverter <TwinCollection> twinCollectionMessageConverter,
     VersionInfo versionInfo,
     IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache)
 {
     this.edgeHubIdentity = edgeHubIdentity;
     this.twinManager     = twinManager;
     this.twinCollectionMessageConverter = twinCollectionMessageConverter;
     this.routeFactory = routeFactory;
     this.versionInfo  = versionInfo ?? VersionInfo.Empty;
     this.deviceScopeIdentitiesCache = deviceScopeIdentitiesCache;
 }
Example #15
0
 public CloudConnectionProvider(IMessageConverterProvider messageConverterProvider,
                                int connectionPoolSize,
                                IClientProvider clientProvider,
                                Option <UpstreamProtocol> upstreamProtocol,
                                ITokenProvider edgeHubTokenProvider,
                                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
                                TimeSpan idleTimeout)
 {
     Preconditions.CheckRange(connectionPoolSize, 1, nameof(connectionPoolSize));
     this.messageConverterProvider = Preconditions.CheckNotNull(messageConverterProvider, nameof(messageConverterProvider));
     this.clientProvider           = Preconditions.CheckNotNull(clientProvider, nameof(clientProvider));
     this.transportSettings        = GetTransportSettings(upstreamProtocol, connectionPoolSize);
     this.edgeHub                    = Option.None <IEdgeHub>();
     this.idleTimeout                = idleTimeout;
     this.edgeHubTokenProvider       = Preconditions.CheckNotNull(edgeHubTokenProvider, nameof(edgeHubTokenProvider));
     this.deviceScopeIdentitiesCache = Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));
 }
Example #16
0
        public static async Task <EdgeHubConnection> Create(
            IClientCredentials edgeHubCredentials,
            IEdgeHub edgeHub,
            ITwinManager twinManager,
            IConnectionManager connectionManager,
            ICloudProxy cloudProxy,
            RouteFactory routeFactory,
            IMessageConverter <TwinCollection> twinCollectionMessageConverter,
            IMessageConverter <Twin> twinMessageConverter,
            VersionInfo versionInfo,
            IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache
            )
        {
            Preconditions.CheckNotNull(edgeHubCredentials, nameof(edgeHubCredentials));
            Preconditions.CheckNotNull(edgeHub, nameof(edgeHub));
            Preconditions.CheckNotNull(connectionManager, nameof(connectionManager));
            Preconditions.CheckNotNull(cloudProxy, nameof(cloudProxy));
            Preconditions.CheckNotNull(twinCollectionMessageConverter, nameof(twinCollectionMessageConverter));
            Preconditions.CheckNotNull(twinMessageConverter, nameof(twinMessageConverter));
            Preconditions.CheckNotNull(routeFactory, nameof(routeFactory));
            Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));

            var edgeHubConnection = new EdgeHubConnection(
                edgeHubCredentials.Identity as IModuleIdentity, twinManager, routeFactory,
                twinCollectionMessageConverter, twinMessageConverter,
                versionInfo ?? VersionInfo.Empty,
                deviceScopeIdentitiesCache
                );

            IDeviceProxy deviceProxy = new EdgeHubDeviceProxy(edgeHubConnection);
            await connectionManager.AddDeviceConnection(edgeHubCredentials);

            connectionManager.BindDeviceProxy(edgeHubCredentials.Identity, deviceProxy);

            await edgeHub.AddSubscription(edgeHubCredentials.Identity.Id, DeviceSubscription.DesiredPropertyUpdates);

            await edgeHub.AddSubscription(edgeHubCredentials.Identity.Id, DeviceSubscription.Methods);

            // Clear out all the reported devices.
            await edgeHubConnection.ClearDeviceConnectionStatuses();

            connectionManager.DeviceConnected    += edgeHubConnection.DeviceConnected;
            connectionManager.DeviceDisconnected += edgeHubConnection.DeviceDisconnected;
            Events.Initialized(edgeHubCredentials.Identity);
            return(edgeHubConnection);
        }
Example #17
0
 public CloudConnection(Action <string, CloudConnectionStatus> connectionStatusChangedHandler,
                        ITransportSettings[] transportSettings,
                        IMessageConverterProvider messageConverterProvider,
                        IClientProvider clientProvider,
                        ICloudListener cloudListener,
                        ITokenProvider edgeHubTokenProvider,
                        IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
                        TimeSpan idleTimeout)
 {
     this.connectionStatusChangedHandler = connectionStatusChangedHandler;
     this.transportSettingsList          = Preconditions.CheckNotNull(transportSettings, nameof(transportSettings));
     this.messageConverterProvider       = Preconditions.CheckNotNull(messageConverterProvider, nameof(messageConverterProvider));
     this.tokenGetter                = Option.None <TaskCompletionSource <string> >();
     this.clientProvider             = Preconditions.CheckNotNull(clientProvider, nameof(clientProvider));
     this.cloudListener              = Preconditions.CheckNotNull(cloudListener, nameof(cloudListener));
     this.idleTimeout                = idleTimeout;
     this.edgeHubTokenProvider       = Preconditions.CheckNotNull(edgeHubTokenProvider, nameof(edgeHubTokenProvider));
     this.deviceScopeIdentitiesCache = Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));
 }
Example #18
0
 public ConnectionReauthenticator(
     IConnectionManager connectionManager,
     IAuthenticator authenticator,
     ICredentialsCache credentialsCache,
     IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache,
     TimeSpan reauthenticateFrequency,
     IIdentity edgeHubIdentity)
 {
     this.connectionManager          = Preconditions.CheckNotNull(connectionManager, nameof(connectionManager));
     this.authenticator              = Preconditions.CheckNotNull(authenticator, nameof(authenticator));
     this.credentialsCache           = Preconditions.CheckNotNull(credentialsCache, nameof(credentialsCache));
     this.edgeHubIdentity            = Preconditions.CheckNotNull(edgeHubIdentity, nameof(edgeHubIdentity));
     this.deviceScopeIdentitiesCache = Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));
     this.timer          = new Timer(reauthenticateFrequency.TotalMilliseconds);
     this.timer.Elapsed += this.ReauthenticateConnections;
     this.connectionManager.CloudConnectionEstablished      += this.CloudConnectionEstablishedHandler;
     this.deviceScopeIdentitiesCache.ServiceIdentityUpdated += this.HandleServiceIdentityUpdate;
     this.deviceScopeIdentitiesCache.ServiceIdentityRemoved += this.HandleServiceIdentityRemove;
 }
Example #19
0
 public RoutingEdgeHub(
     Router router,
     Core.IMessageConverter <IRoutingMessage> messageConverter,
     IConnectionManager connectionManager,
     ITwinManager twinManager,
     string edgeDeviceId,
     IInvokeMethodHandler invokeMethodHandler,
     ISubscriptionProcessor subscriptionProcessor,
     IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache)
 {
     this.router                     = Preconditions.CheckNotNull(router, nameof(router));
     this.messageConverter           = Preconditions.CheckNotNull(messageConverter, nameof(messageConverter));
     this.connectionManager          = Preconditions.CheckNotNull(connectionManager, nameof(connectionManager));
     this.twinManager                = Preconditions.CheckNotNull(twinManager, nameof(twinManager));
     this.edgeDeviceId               = Preconditions.CheckNonWhiteSpace(edgeDeviceId, nameof(edgeDeviceId));
     this.invokeMethodHandler        = Preconditions.CheckNotNull(invokeMethodHandler, nameof(invokeMethodHandler));
     this.subscriptionProcessor      = Preconditions.CheckNotNull(subscriptionProcessor, nameof(subscriptionProcessor));
     this.deviceScopeIdentitiesCache = Preconditions.CheckNotNull(deviceScopeIdentitiesCache, nameof(deviceScopeIdentitiesCache));
 }
Example #20
0
        internal static async Task <Try <string> > AuthorizeOnBehalfOf(
            string actorDeviceId,
            string authChain,
            string source,
            HttpContext httpContext,
            IEdgeHub edgeHub,
            IHttpRequestAuthenticator authenticator)
        {
            if (!AuthChainHelpers.TryGetTargetDeviceId(authChain, out string targetDeviceId))
            {
                Events.InvalidRequestAuthChain(source, authChain);
                return(Try <string> .Failure(new ValidationException(HttpStatusCode.BadRequest, FormatErrorResponseMessage($"Invalid request auth chain {authChain}."))));
            }

            if (!await AuthenticateAsync(actorDeviceId, Option.Some(Constants.EdgeHubModuleId), Option.Some(authChain), httpContext, authenticator))
            {
                return(Try <string> .Failure(new ValidationException(HttpStatusCode.Unauthorized)));
            }

            IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache();
            Option <string>             targetAuthChain = await identitiesCache.GetAuthChain(targetDeviceId);

            return(targetAuthChain.Match(
                       ac =>
            {
                if (!AuthChainHelpers.ValidateAuthChain(actorDeviceId, targetDeviceId, ac))
                {
                    Events.AuthorizationFail_InvalidAuthChain(actorDeviceId, targetDeviceId, ac);
                    return Try <string> .Failure(new ValidationException(HttpStatusCode.Unauthorized));
                }

                return ac;
            },
                       () =>
            {
                Events.AuthorizationFail_NoAuthChain(targetDeviceId);
                return Try <string> .Failure(new ValidationException(HttpStatusCode.Unauthorized));
            }));
        }
Example #21
0
        async Task <EdgeHubScopeResult> HandleDevicesAndModulesInTargetDeviceScopeAsync(string actorDeviceId, string actorModuleId, NestedScopeRequest request)
        {
            Events.ReceivedScopeRequest(actorDeviceId, actorModuleId, request);

            if (!AuthChainHelpers.TryGetTargetDeviceId(request.AuthChain, out string targetDeviceId))
            {
                return(new EdgeHubScopeResultError(HttpStatusCode.BadRequest, Events.InvalidRequestAuthchain(request.AuthChain)));
            }

            // Get the children of the target device and the target device itself;
            IEdgeHub edgeHub = await this.edgeHubGetter;
            IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache();
            IList <ServiceIdentity>     identities      = await identitiesCache.GetDevicesAndModulesInTargetScopeAsync(targetDeviceId);

            Option <ServiceIdentity> targetDevice = await identitiesCache.GetServiceIdentity(targetDeviceId);

            targetDevice.ForEach(d => identities.Add(d));

            // Construct the result from the identities
            Events.SendingScopeResult(targetDeviceId, identities);
            return(MakeResultFromIdentities(identities));
        }
Example #22
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);
        }
Example #23
0
        protected override void Load(ContainerBuilder builder)
        {
            // IMessageConverter<IRoutingMessage>
            builder.Register(c => new RoutingMessageConverter())
            .As <Core.IMessageConverter <IRoutingMessage> >()
            .SingleInstance();

            // IRoutingPerfCounter
            builder.Register(
                c =>
            {
                Routing.PerfCounter = NullRoutingPerfCounter.Instance;
                return(Routing.PerfCounter);
            })
            .As <IRoutingPerfCounter>()
            .AutoActivate()
            .SingleInstance();

            // IRoutingUserAnalyticsLogger
            builder.Register(
                c =>
            {
                Routing.UserAnalyticsLogger = NullUserAnalyticsLogger.Instance;
                return(Routing.UserAnalyticsLogger);
            })
            .As <IRoutingUserAnalyticsLogger>()
            .AutoActivate()
            .SingleInstance();

            // IRoutingUserMetricLogger
            builder.Register(
                c =>
            {
                Routing.UserMetricLogger = NullRoutingUserMetricLogger.Instance;
                return(Routing.UserMetricLogger);
            })
            .As <IRoutingUserMetricLogger>()
            .AutoActivate()
            .SingleInstance();

            // IMessageConverter<Message>
            builder.Register(c => new DeviceClientMessageConverter())
            .As <Core.IMessageConverter <Message> >()
            .SingleInstance();

            // IMessageConverter<Twin>
            builder.Register(c => new TwinMessageConverter())
            .As <Core.IMessageConverter <Twin> >()
            .SingleInstance();

            // IMessageConverter<TwinCollection>
            builder.Register(c => new TwinCollectionMessageConverter())
            .As <Core.IMessageConverter <TwinCollection> >()
            .SingleInstance();

            // IMessageConverterProvider
            builder.Register(
                c => new MessageConverterProvider(
                    new Dictionary <Type, IMessageConverter>()
            {
                { typeof(Message), c.Resolve <Core.IMessageConverter <Message> >() },
                { typeof(Twin), c.Resolve <Core.IMessageConverter <Twin> >() },
                { typeof(TwinCollection), c.Resolve <Core.IMessageConverter <TwinCollection> >() }
            }))
            .As <IMessageConverterProvider>()
            .SingleInstance();

            // IDeviceConnectivityManager
            builder.Register(
                c =>
            {
                var edgeHubCredentials = c.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
                IDeviceConnectivityManager deviceConnectivityManager = this.experimentalFeatures.DisableConnectivityCheck
                            ? new NullDeviceConnectivityManager()
                            : new DeviceConnectivityManager(this.connectivityCheckFrequency, TimeSpan.FromMinutes(2), edgeHubCredentials.Identity) as IDeviceConnectivityManager;
                return(deviceConnectivityManager);
            })
            .As <IDeviceConnectivityManager>()
            .SingleInstance();

            // IDeviceClientProvider
            builder.Register(
                c =>
            {
                IClientProvider underlyingClientProvider        = new ClientProvider();
                IClientProvider connectivityAwareClientProvider = new ConnectivityAwareClientProvider(underlyingClientProvider, c.Resolve <IDeviceConnectivityManager>());
                return(connectivityAwareClientProvider);
            })
            .As <IClientProvider>()
            .SingleInstance();

            // Task<ICloudConnectionProvider>
            builder.Register(
                async c =>
            {
                var productInfoStore               = await c.Resolve <Task <IProductInfoStore> >();
                var messageConverterProvider       = c.Resolve <IMessageConverterProvider>();
                var clientProvider                 = c.Resolve <IClientProvider>();
                var tokenProvider                  = c.ResolveNamed <ITokenProvider>("EdgeHubClientAuthTokenProvider");
                var credentialsCacheTask           = c.Resolve <Task <ICredentialsCache> >();
                var edgeHubCredentials             = c.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
                var deviceScopeIdentitiesCacheTask = c.Resolve <Task <IDeviceScopeIdentitiesCache> >();
                var proxy = c.Resolve <Option <IWebProxy> >();
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await deviceScopeIdentitiesCacheTask;
                ICredentialsCache credentialsCache = await credentialsCacheTask;
                ICloudConnectionProvider cloudConnectionProvider = new CloudConnectionProvider(
                    messageConverterProvider,
                    this.connectionPoolSize,
                    clientProvider,
                    this.upstreamProtocol,
                    tokenProvider,
                    deviceScopeIdentitiesCache,
                    credentialsCache,
                    edgeHubCredentials.Identity,
                    this.cloudConnectionIdleTimeout,
                    this.closeCloudConnectionOnIdleTimeout,
                    this.operationTimeout,
                    this.useServerHeartbeat,
                    proxy,
                    productInfoStore);
                return(cloudConnectionProvider);
            })
            .As <Task <ICloudConnectionProvider> >()
            .SingleInstance();

            // IIdentityProvider
            builder.Register(_ => new IdentityProvider(this.iotHubName))
            .As <IIdentityProvider>()
            .SingleInstance();

            // Task<IConnectionManager>
            builder.Register(
                async c =>
            {
                var cloudConnectionProviderTask = c.Resolve <Task <ICloudConnectionProvider> >();
                var credentialsCacheTask        = c.Resolve <Task <ICredentialsCache> >();
                var identityProvider            = c.Resolve <IIdentityProvider>();
                var deviceConnectivityManager   = c.Resolve <IDeviceConnectivityManager>();
                ICloudConnectionProvider cloudConnectionProvider = await cloudConnectionProviderTask;
                ICredentialsCache credentialsCache   = await credentialsCacheTask;
                IConnectionManager connectionManager = new ConnectionManager(
                    cloudConnectionProvider,
                    credentialsCache,
                    identityProvider,
                    deviceConnectivityManager,
                    this.maxConnectedClients,
                    this.closeCloudConnectionOnDeviceDisconnect);
                return(connectionManager);
            })
            .As <Task <IConnectionManager> >()
            .SingleInstance();

            // Task<IEndpointFactory>
            builder.Register(
                async c =>
            {
                var messageConverter = c.Resolve <Core.IMessageConverter <IRoutingMessage> >();
                IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                return(new EndpointFactory(connectionManager, messageConverter, this.edgeDeviceId, this.maxUpstreamBatchSize, this.upstreamFanOutFactor) as IEndpointFactory);
            })
            .As <Task <IEndpointFactory> >()
            .SingleInstance();

            // Task<RouteFactory>
            builder.Register(async c => new EdgeRouteFactory(await c.Resolve <Task <IEndpointFactory> >()) as RouteFactory)
            .As <Task <RouteFactory> >()
            .SingleInstance();

            // RouterConfig
            builder.Register(c => new RouterConfig(Enumerable.Empty <Route>()))
            .As <RouterConfig>()
            .SingleInstance();

            if (!this.isStoreAndForwardEnabled)
            {
                // EndpointExecutorConfig
                builder.Register(
                    c =>
                {
                    RetryStrategy defaultRetryStrategy = new FixedInterval(0, TimeSpan.FromSeconds(1));
                    TimeSpan defaultRevivePeriod       = TimeSpan.FromHours(1);
                    TimeSpan defaultTimeout            = TimeSpan.FromSeconds(60);
                    return(new EndpointExecutorConfig(defaultTimeout, defaultRetryStrategy, defaultRevivePeriod, true));
                })
                .As <EndpointExecutorConfig>()
                .SingleInstance();

                // IEndpointExecutorFactory
                builder.Register(c => new SyncEndpointExecutorFactory(c.Resolve <EndpointExecutorConfig>()))
                .As <IEndpointExecutorFactory>()
                .SingleInstance();

                // Task<Router>
                builder.Register(
                    async c =>
                {
                    var endpointExecutorFactory = c.Resolve <IEndpointExecutorFactory>();
                    var routerConfig            = c.Resolve <RouterConfig>();
                    Router router = await Router.CreateAsync(Guid.NewGuid().ToString(), this.iotHubName, routerConfig, endpointExecutorFactory);
                    return(router);
                })
                .As <Task <Router> >()
                .SingleInstance();

                // Task<ITwinManager>
                builder.Register(
                    async c =>
                {
                    if (!this.useV1TwinManager)
                    {
                        var messageConverterProvider         = c.Resolve <IMessageConverterProvider>();
                        IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                        ITwinManager twinManager             = new PassThroughTwinManager(connectionManager, messageConverterProvider);
                        return(twinManager);
                    }
                    else
                    {
                        var messageConverterProvider         = c.Resolve <IMessageConverterProvider>();
                        IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                        return(TwinManager.CreateTwinManager(connectionManager, messageConverterProvider, Option.None <IStoreProvider>()));
                    }
                })
                .As <Task <ITwinManager> >()
                .SingleInstance();
            }
            else
            {
                // EndpointExecutorConfig
                builder.Register(
                    c =>
                {
                    // Endpoint executor config values -
                    // ExponentialBackoff - minBackoff = 1s, maxBackoff = 60s, delta (used to add randomness to backoff) - 1s (default)
                    // Num of retries = int.MaxValue(we want to keep retrying till the message is sent)
                    // Revive period - period for which the endpoint should be considered dead if it doesn't respond - 1 min (we want to try continuously till the message expires)
                    // Timeout - time for which we want for the ack from the endpoint = 30s
                    // TODO - Should the number of retries be tied to the Store and Forward ttl? Not
                    // doing that right now as that value can be changed at runtime, but these settings
                    // cannot. Need to make the number of retries dynamically configurable for that.
                    TimeSpan minWait            = TimeSpan.FromSeconds(1);
                    TimeSpan maxWait            = TimeSpan.FromSeconds(60);
                    TimeSpan delta              = TimeSpan.FromSeconds(1);
                    int retries                 = int.MaxValue;
                    RetryStrategy retryStrategy = new ExponentialBackoff(retries, minWait, maxWait, delta);
                    TimeSpan timeout            = TimeSpan.FromSeconds(30);
                    TimeSpan revivePeriod       = TimeSpan.FromSeconds(30);
                    return(new EndpointExecutorConfig(timeout, retryStrategy, revivePeriod));
                })
                .As <EndpointExecutorConfig>()
                .SingleInstance();

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

                // Task<IMessageStore>
                builder.Register(
                    async c =>
                {
                    var checkpointStore          = await c.Resolve <Task <ICheckpointStore> >();
                    var dbStoreProvider          = await c.Resolve <Task <IDbStoreProvider> >();
                    IStoreProvider storeProvider = new StoreProvider(dbStoreProvider);
                    IMessageStore messageStore   = new MessageStore(storeProvider, checkpointStore, this.storeAndForwardConfiguration.TimeToLive, this.checkEntireQueueOnCleanup);
                    return(messageStore);
                })
                .As <Task <IMessageStore> >()
                .SingleInstance();

                // Task<IEndpointExecutorFactory>
                builder.Register(
                    async c =>
                {
                    var endpointExecutorConfig = c.Resolve <EndpointExecutorConfig>();
                    var messageStore           = await c.Resolve <Task <IMessageStore> >();
                    IEndpointExecutorFactory endpointExecutorFactory = new StoringAsyncEndpointExecutorFactory(endpointExecutorConfig, new AsyncEndpointExecutorOptions(10, TimeSpan.FromSeconds(10)), messageStore);
                    return(endpointExecutorFactory);
                })
                .As <Task <IEndpointExecutorFactory> >()
                .SingleInstance();

                // Task<Router>
                builder.Register(
                    async c =>
                {
                    var checkpointStore         = await c.Resolve <Task <ICheckpointStore> >();
                    var routerConfig            = c.Resolve <RouterConfig>();
                    var endpointExecutorFactory = await c.Resolve <Task <IEndpointExecutorFactory> >();
                    return(await Router.CreateAsync(Guid.NewGuid().ToString(), this.iotHubName, routerConfig, endpointExecutorFactory, checkpointStore));
                })
                .As <Task <Router> >()
                .SingleInstance();

                // Task<ITwinManager>
                builder.Register(
                    async c =>
                {
                    if (this.useV1TwinManager)
                    {
                        var dbStoreProvider                  = await c.Resolve <Task <IDbStoreProvider> >();
                        var messageConverterProvider         = c.Resolve <IMessageConverterProvider>();
                        IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                        return(TwinManager.CreateTwinManager(connectionManager, messageConverterProvider, Option.Some <IStoreProvider>(new StoreProvider(dbStoreProvider))));
                    }
                    else
                    {
                        var messageConverterProvider  = c.Resolve <IMessageConverterProvider>();
                        var deviceConnectivityManager = c.Resolve <IDeviceConnectivityManager>();
                        var connectionManagerTask     = c.Resolve <Task <IConnectionManager> >();
                        IEntityStore <string, TwinStoreEntity> entityStore = await this.GetTwinStore(c);
                        IConnectionManager connectionManager = await connectionManagerTask;
                        ITwinManager twinManager             = StoringTwinManager.Create(
                            connectionManager,
                            messageConverterProvider,
                            entityStore,
                            deviceConnectivityManager,
                            new ReportedPropertiesValidator(),
                            this.minTwinSyncPeriod,
                            this.reportedPropertiesSyncFrequency);
                        return(twinManager);
                    }
                })
                .As <Task <ITwinManager> >()
                .SingleInstance();
            }

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

            // Task<IInvokeMethodHandler>
            builder.Register(
                async c =>
            {
                IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                return(new InvokeMethodHandler(connectionManager) as IInvokeMethodHandler);
            })
            .As <Task <IInvokeMethodHandler> >()
            .SingleInstance();

            // Task<ISubscriptionProcessor>
            builder.Register(
                async c =>
            {
                var connectionManagerTask = c.Resolve <Task <IConnectionManager> >();
                if (this.experimentalFeatures.DisableCloudSubscriptions)
                {
                    return(new LocalSubscriptionProcessor(await connectionManagerTask) as ISubscriptionProcessor);
                }
                else
                {
                    var invokeMethodHandlerTask              = c.Resolve <Task <IInvokeMethodHandler> >();
                    var deviceConnectivityManager            = c.Resolve <IDeviceConnectivityManager>();
                    IConnectionManager connectionManager     = await connectionManagerTask;
                    IInvokeMethodHandler invokeMethodHandler = await invokeMethodHandlerTask;
                    return(new SubscriptionProcessor(connectionManager, invokeMethodHandler, deviceConnectivityManager) as ISubscriptionProcessor);
                }
            })
            .As <Task <ISubscriptionProcessor> >()
            .SingleInstance();

            // Task<IEdgeHub>
            builder.Register(
                async c =>
            {
                var routingMessageConverter = c.Resolve <Core.IMessageConverter <IRoutingMessage> >();
                var routerTask                = c.Resolve <Task <Router> >();
                var twinManagerTask           = c.Resolve <Task <ITwinManager> >();
                var invokeMethodHandlerTask   = c.Resolve <Task <IInvokeMethodHandler> >();
                var connectionManagerTask     = c.Resolve <Task <IConnectionManager> >();
                var subscriptionProcessorTask = c.Resolve <Task <ISubscriptionProcessor> >();
                Router router                                = await routerTask;
                ITwinManager twinManager                     = await twinManagerTask;
                IConnectionManager connectionManager         = await connectionManagerTask;
                IInvokeMethodHandler invokeMethodHandler     = await invokeMethodHandlerTask;
                ISubscriptionProcessor subscriptionProcessor = await subscriptionProcessorTask;
                IEdgeHub hub = new RoutingEdgeHub(
                    router,
                    routingMessageConverter,
                    connectionManager,
                    twinManager,
                    this.edgeDeviceId,
                    invokeMethodHandler,
                    subscriptionProcessor);
                return(hub);
            })
            .As <Task <IEdgeHub> >()
            .SingleInstance();

            // Task<ConfigUpdater>
            builder.Register(
                async c =>
            {
                IMessageStore messageStore = this.isStoreAndForwardEnabled ? await c.Resolve <Task <IMessageStore> >() : null;
                var storageSpaceChecker    = c.Resolve <IStorageSpaceChecker>();
                var edgeHubCredentials     = c.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
                RouteFactory routeFactory  = await c.Resolve <Task <RouteFactory> >();
                Router router            = await c.Resolve <Task <Router> >();
                var twinManagerTask      = c.Resolve <Task <ITwinManager> >();
                var twinMessageConverter = c.Resolve <Core.IMessageConverter <Twin> >();
                var twinManager          = await twinManagerTask;
                var configUpdater        = new ConfigUpdater(router, messageStore, this.configUpdateFrequency, storageSpaceChecker);
                return(configUpdater);
            })
            .As <Task <ConfigUpdater> >()
            .SingleInstance();

            // Task<IConfigSource>
            builder.Register <Task <IConfigSource> >(
                async c =>
            {
                RouteFactory routeFactory = await c.Resolve <Task <RouteFactory> >();
                if (this.useTwinConfig)
                {
                    var edgeHubCredentials             = c.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
                    var twinCollectionMessageConverter = c.Resolve <Core.IMessageConverter <TwinCollection> >();
                    var twinMessageConverter           = c.Resolve <Core.IMessageConverter <Twin> >();
                    var twinManagerTask                  = c.Resolve <Task <ITwinManager> >();
                    var edgeHubTask                      = c.Resolve <Task <IEdgeHub> >();
                    ITwinManager twinManager             = await twinManagerTask;
                    IEdgeHub edgeHub                     = await edgeHubTask;
                    IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                    IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await c.Resolve <Task <IDeviceScopeIdentitiesCache> >();

                    var edgeHubConnection = await EdgeHubConnection.Create(
                        edgeHubCredentials.Identity,
                        edgeHub,
                        twinManager,
                        connectionManager,
                        routeFactory,
                        twinCollectionMessageConverter,
                        this.versionInfo,
                        deviceScopeIdentitiesCache);

                    return(new TwinConfigSource(edgeHubConnection, edgeHubCredentials.Identity.Id, this.versionInfo, twinManager, twinMessageConverter, twinCollectionMessageConverter, routeFactory));
                }
                else
                {
                    return(new LocalConfigSource(routeFactory, this.routes, this.storeAndForwardConfiguration));
                }
            })
            .As <Task <IConfigSource> >()
            .SingleInstance();

            // Task<IConnectionProvider>
            builder.Register(
                async c =>
            {
                var connectionManagerTask              = c.Resolve <Task <IConnectionManager> >();
                var edgeHubTask                        = c.Resolve <Task <IEdgeHub> >();
                IConnectionManager connectionManager   = await connectionManagerTask;
                IEdgeHub edgeHub                       = await edgeHubTask;
                IConnectionProvider connectionProvider = new ConnectionProvider(connectionManager, edgeHub, this.messageAckTimeout);
                return(connectionProvider);
            })
            .As <Task <IConnectionProvider> >()
            .SingleInstance();

            base.Load(builder);
        }
Example #24
0
        protected override void Load(ContainerBuilder builder)
        {
            // IMessageConverter<IRoutingMessage>
            builder.Register(c => new RoutingMessageConverter())
            .As <Core.IMessageConverter <IRoutingMessage> >()
            .SingleInstance();

            // IRoutingPerfCounter
            builder.Register(
                c =>
            {
                Routing.PerfCounter = NullRoutingPerfCounter.Instance;
                return(Routing.PerfCounter);
            })
            .As <IRoutingPerfCounter>()
            .AutoActivate()
            .SingleInstance();

            // IRoutingUserAnalyticsLogger
            builder.Register(
                c =>
            {
                Routing.UserAnalyticsLogger = NullUserAnalyticsLogger.Instance;
                return(Routing.UserAnalyticsLogger);
            })
            .As <IRoutingUserAnalyticsLogger>()
            .AutoActivate()
            .SingleInstance();

            // IRoutingUserMetricLogger
            builder.Register(
                c =>
            {
                Routing.UserMetricLogger = NullRoutingUserMetricLogger.Instance;
                return(Routing.UserMetricLogger);
            })
            .As <IRoutingUserMetricLogger>()
            .AutoActivate()
            .SingleInstance();

            // IMessageConverter<Message>
            builder.Register(c => new DeviceClientMessageConverter())
            .As <Core.IMessageConverter <Message> >()
            .SingleInstance();

            // IMessageConverter<Twin>
            builder.Register(c => new TwinMessageConverter())
            .As <Core.IMessageConverter <Twin> >()
            .SingleInstance();

            // IMessageConverter<TwinCollection>
            builder.Register(c => new TwinCollectionMessageConverter())
            .As <Core.IMessageConverter <TwinCollection> >()
            .SingleInstance();

            // IMessageConverterProvider
            builder.Register(
                c => new MessageConverterProvider(new Dictionary <Type, IMessageConverter>()
            {
                { typeof(Message), c.Resolve <Core.IMessageConverter <Message> >() },
                { typeof(Twin), c.Resolve <Core.IMessageConverter <Twin> >() },
                { typeof(TwinCollection), c.Resolve <Core.IMessageConverter <TwinCollection> >() }
            }))
            .As <IMessageConverterProvider>()
            .SingleInstance();

            // IDeviceConnectivityManager
            builder.Register(
                c =>
            {
                IDeviceConnectivityManager deviceConnectivityManager = new DeviceConnectivityManager(this.connectivityCheckFrequency, TimeSpan.FromMinutes(2));
                return(deviceConnectivityManager);
            })
            .As <IDeviceConnectivityManager>()
            .SingleInstance();

            // IDeviceClientProvider
            builder.Register(c =>
            {
                IClientProvider underlyingClientProvider        = new ClientProvider();
                IClientProvider connectivityAwareClientProvider = new ConnectivityAwareClientProvider(underlyingClientProvider, c.Resolve <IDeviceConnectivityManager>());
                return(connectivityAwareClientProvider);
            })
            .As <IClientProvider>()
            .SingleInstance();

            // Task<ICloudConnectionProvider>
            builder.Register(
                async c =>
            {
                var messageConverterProvider = c.Resolve <IMessageConverterProvider>();
                var clientProvider           = c.Resolve <IClientProvider>();
                var tokenProvider            = c.ResolveNamed <ITokenProvider>("EdgeHubClientAuthTokenProvider");
                IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await c.Resolve <Task <IDeviceScopeIdentitiesCache> >();
                ICloudConnectionProvider cloudConnectionProvider       = new CloudConnectionProvider(
                    messageConverterProvider,
                    this.connectionPoolSize,
                    clientProvider,
                    this.upstreamProtocol,
                    tokenProvider,
                    deviceScopeIdentitiesCache,
                    TimeSpan.FromMinutes(60));
                return(cloudConnectionProvider);
            })
            .As <Task <ICloudConnectionProvider> >()
            .SingleInstance();

            // Task<ICredentialsStore>
            builder.Register(async c =>
            {
                if (this.cacheTokens)
                {
                    IKeyValueStore <string, string> encryptedStore = await c.ResolveNamed <Task <IKeyValueStore <string, string> > >("EncryptedStore");
                    return(new TokenCredentialsStore(encryptedStore));
                }
                else
                {
                    return(new NullCredentialsStore() as ICredentialsStore);
                }
            })
            .As <Task <ICredentialsStore> >()
            .SingleInstance();

            // Task<IConnectionManager>
            builder.Register(
                async c =>
            {
                ICloudConnectionProvider cloudConnectionProvider = await c.Resolve <Task <ICloudConnectionProvider> >();
                IConnectionManager connectionManager             = new ConnectionManager(cloudConnectionProvider, this.maxConnectedClients);
                return(connectionManager);
            })
            .As <Task <IConnectionManager> >()
            .SingleInstance();

            // Task<IEndpointFactory>
            builder.Register(async c =>
            {
                var messageConverter = c.Resolve <Core.IMessageConverter <IRoutingMessage> >();
                IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                return(new EndpointFactory(connectionManager, messageConverter, this.edgeDeviceId) as IEndpointFactory);
            })
            .As <Task <IEndpointFactory> >()
            .SingleInstance();

            // Task<RouteFactory>
            builder.Register(async c => new EdgeRouteFactory(await c.Resolve <Task <IEndpointFactory> >()) as RouteFactory)
            .As <Task <RouteFactory> >()
            .SingleInstance();

            // RouterConfig
            builder.Register(c => new RouterConfig(Enumerable.Empty <Route>()))
            .As <RouterConfig>()
            .SingleInstance();

            if (!this.isStoreAndForwardEnabled)
            {
                // EndpointExecutorConfig
                builder.Register(
                    c =>
                {
                    RetryStrategy defaultRetryStrategy = new FixedInterval(0, TimeSpan.FromSeconds(1));
                    TimeSpan defaultRevivePeriod       = TimeSpan.FromHours(1);
                    TimeSpan defaultTimeout            = TimeSpan.FromSeconds(60);
                    return(new EndpointExecutorConfig(defaultTimeout, defaultRetryStrategy, defaultRevivePeriod, true));
                })
                .As <EndpointExecutorConfig>()
                .SingleInstance();

                // IEndpointExecutorFactory
                builder.Register(c => new SyncEndpointExecutorFactory(c.Resolve <EndpointExecutorConfig>()))
                .As <IEndpointExecutorFactory>()
                .SingleInstance();

                // Task<Router>
                builder.Register(
                    async c =>
                {
                    var endpointExecutorFactory = c.Resolve <IEndpointExecutorFactory>();
                    var routerConfig            = c.Resolve <RouterConfig>();
                    Router router = await Router.CreateAsync(Guid.NewGuid().ToString(), this.iotHubName, routerConfig, endpointExecutorFactory);
                    return(router);
                })
                .As <Task <Router> >()
                .SingleInstance();

                // Task<ITwinManager>
                builder.Register(async c =>
                {
                    var messageConverterProvider         = c.Resolve <IMessageConverterProvider>();
                    IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                    return(TwinManager.CreateTwinManager(connectionManager, messageConverterProvider, Option.None <IStoreProvider>()));
                })
                .As <Task <ITwinManager> >()
                .SingleInstance();
            }
            else
            {
                // EndpointExecutorConfig
                builder.Register(
                    c =>
                {
                    // Endpoint executor config values -
                    // ExponentialBackoff - minBackoff = 1s, maxBackoff = 60s, delta (used to add randomness to backoff) - 1s (default)
                    // Num of retries = int.MaxValue(we want to keep retrying till the message is sent)
                    // Revive period - period for which the endpoint should be considered dead if it doesn't respond - 1 min (we want to try continuously till the message expires)
                    // Timeout - time for which we want for the ack from the endpoint = 30s
                    // TODO - Should the number of retries be tied to the Store and Forward ttl? Not
                    // doing that right now as that value can be changed at runtime, but these settings
                    // cannot. Need to make the number of retries dynamically configurable for that.

                    TimeSpan minWait            = TimeSpan.FromSeconds(1);
                    TimeSpan maxWait            = TimeSpan.FromSeconds(60);
                    TimeSpan delta              = TimeSpan.FromSeconds(1);
                    int retries                 = int.MaxValue;
                    RetryStrategy retryStrategy = new ExponentialBackoff(retries, minWait, maxWait, delta);
                    TimeSpan timeout            = TimeSpan.FromSeconds(30);
                    TimeSpan revivePeriod       = TimeSpan.FromSeconds(30);
                    return(new EndpointExecutorConfig(timeout, retryStrategy, revivePeriod));
                })
                .As <EndpointExecutorConfig>()
                .SingleInstance();

                // ICheckpointStore
                builder.Register(c => CheckpointStore.Create(c.Resolve <IDbStoreProvider>()))
                .As <ICheckpointStore>()
                .SingleInstance();

                // IMessageStore
                builder.Register(
                    c =>
                {
                    var checkpointStore          = c.Resolve <ICheckpointStore>();
                    var dbStoreProvider          = c.Resolve <IDbStoreProvider>();
                    IStoreProvider storeProvider = new StoreProvider(dbStoreProvider);
                    IMessageStore messageStore   = new MessageStore(storeProvider, checkpointStore, TimeSpan.MaxValue);
                    return(messageStore);
                })
                .As <IMessageStore>()
                .SingleInstance();

                // IEndpointExecutorFactory
                builder.Register(
                    c =>
                {
                    var endpointExecutorConfig = c.Resolve <EndpointExecutorConfig>();
                    var messageStore           = c.Resolve <IMessageStore>();
                    IEndpointExecutorFactory endpointExecutorFactory = new StoringAsyncEndpointExecutorFactory(endpointExecutorConfig, new AsyncEndpointExecutorOptions(10, TimeSpan.FromSeconds(10)), messageStore);
                    return(endpointExecutorFactory);
                })
                .As <IEndpointExecutorFactory>()
                .SingleInstance();

                // Task<Router>
                builder.Register(
                    async c =>
                {
                    var checkpointStore         = c.Resolve <ICheckpointStore>();
                    var routerConfig            = c.Resolve <RouterConfig>();
                    var endpointExecutorFactory = c.Resolve <IEndpointExecutorFactory>();
                    return(await Router.CreateAsync(Guid.NewGuid().ToString(), this.iotHubName, routerConfig, endpointExecutorFactory, checkpointStore));
                })
                .As <Task <Router> >()
                .SingleInstance();

                // Task<ITwinManager>
                builder.Register(async c =>
                {
                    var dbStoreProvider                  = c.Resolve <IDbStoreProvider>();
                    var messageConverterProvider         = c.Resolve <IMessageConverterProvider>();
                    IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                    return(TwinManager.CreateTwinManager(connectionManager, messageConverterProvider, Option.Some <IStoreProvider>(new StoreProvider(dbStoreProvider))));
                })
                .As <Task <ITwinManager> >()
                .SingleInstance();
            }

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

            // Task<ICloudProxy> "EdgeHubCloudProxy"
            builder.Register(
                async c =>
            {
                var edgeHubCredentials = c.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
                IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                Try <ICloudProxy> cloudProxyTry      = await connectionManager.CreateCloudConnectionAsync(edgeHubCredentials);
                if (!cloudProxyTry.Success)
                {
                    throw new EdgeHubConnectionException("Edge hub is unable to connect to IoT Hub", cloudProxyTry.Exception);
                }

                ICloudProxy cloudProxy = cloudProxyTry.Value;
                return(cloudProxy);
            })
            .Named <Task <ICloudProxy> >("EdgeHubCloudProxy")
            .SingleInstance();

            // Task<IInvokeMethodHandler>
            builder.Register(async c =>
            {
                IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                return(new InvokeMethodHandler(connectionManager) as IInvokeMethodHandler);
            })
            .As <Task <IInvokeMethodHandler> >()
            .SingleInstance();

            // Task<IEdgeHub>
            builder.Register(
                async c =>
            {
                var routingMessageConverter = c.Resolve <Core.IMessageConverter <IRoutingMessage> >();
                var routerTask              = c.Resolve <Task <Router> >();
                var twinManagerTask         = c.Resolve <Task <ITwinManager> >();
                var invokeMethodHandlerTask = c.Resolve <Task <IInvokeMethodHandler> >();
                var connectionManagerTask   = c.Resolve <Task <IConnectionManager> >();
                Router router                            = await routerTask;
                ITwinManager twinManager                 = await twinManagerTask;
                IConnectionManager connectionManager     = await connectionManagerTask;
                IInvokeMethodHandler invokeMethodHandler = await invokeMethodHandlerTask;
                IEdgeHub hub = new RoutingEdgeHub(router, routingMessageConverter,
                                                  connectionManager, twinManager, this.edgeDeviceId, invokeMethodHandler);
                return(hub);
            })
            .As <Task <IEdgeHub> >()
            .SingleInstance();

            // Task<ConfigUpdater>
            builder.Register(
                async c =>
            {
                IMessageStore messageStore = this.isStoreAndForwardEnabled ? c.Resolve <IMessageStore>() : null;
                Router router     = await c.Resolve <Task <Router> >();
                var configUpdater = new ConfigUpdater(router, messageStore);
                return(configUpdater);
            })
            .As <Task <ConfigUpdater> >()
            .SingleInstance();

            // Task<IConfigSource>
            builder.Register(
                async c =>
            {
                RouteFactory routeFactory = await c.Resolve <Task <RouteFactory> >();
                if (this.useTwinConfig)
                {
                    var edgeHubCredentials             = c.ResolveNamed <IClientCredentials>("EdgeHubCredentials");
                    var twinCollectionMessageConverter = c.Resolve <Core.IMessageConverter <TwinCollection> >();
                    var twinMessageConverter           = c.Resolve <Core.IMessageConverter <Twin> >();
                    ITwinManager twinManager           = await c.Resolve <Task <ITwinManager> >();
                    ICloudProxy cloudProxy             = await c.ResolveNamed <Task <ICloudProxy> >("EdgeHubCloudProxy");
                    IEdgeHub edgeHub = await c.Resolve <Task <IEdgeHub> >();
                    IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                    IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache = await c.Resolve <Task <IDeviceScopeIdentitiesCache> >();
                    IConfigSource edgeHubConnection = await EdgeHubConnection.Create(
                        edgeHubCredentials,
                        edgeHub,
                        twinManager,
                        connectionManager,
                        cloudProxy,
                        routeFactory,
                        twinCollectionMessageConverter,
                        twinMessageConverter,
                        this.versionInfo,
                        deviceScopeIdentitiesCache
                        );
                    return(edgeHubConnection);
                }
                else
                {
                    return(new LocalConfigSource(routeFactory, this.routes, this.storeAndForwardConfiguration));
                }
            })
            .As <Task <IConfigSource> >()
            .SingleInstance();

            // Task<IConnectionProvider>
            builder.Register(
                async c =>
            {
                IConnectionManager connectionManager = await c.Resolve <Task <IConnectionManager> >();
                IEdgeHub edgeHub = await c.Resolve <Task <IEdgeHub> >();
                IConnectionProvider connectionProvider = new ConnectionProvider(connectionManager, edgeHub);
                return(connectionProvider);
            })
            .As <Task <IConnectionProvider> >()
            .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);
        }
Example #27
0
        async Task <EdgeHubScopeResult> HandleGetDeviceAndModuleOnBehalfOfAsync(string actorDeviceId, string actorModuleId, IdentityOnBehalfOfRequest request)
        {
            Events.ReceivedIdentityOnBehalfOfRequest(actorDeviceId, actorModuleId, request);
            Preconditions.CheckNonWhiteSpace(request.TargetDeviceId, nameof(request.TargetDeviceId));

            bool   isModule = false;
            string targetId = request.TargetDeviceId;

            if (!request.TargetModuleId.IsNullOrWhiteSpace())
            {
                isModule  = true;
                targetId += "/" + request.TargetModuleId;
            }

            IEdgeHub edgeHub = await this.edgeHubGetter;

            // Check if the actor has provided the originating EdgeHub ID,
            // if not, then we must be by definition by the origin.
            string originatingEdge = edgeHub.GetEdgeDeviceId();

            if (this.Request.Headers.TryGetValue(Constants.OriginEdgeHeaderKey, out StringValues originHeader) && originHeader.Count > 0)
            {
                originatingEdge = originHeader.First();
            }

            // We must always forward the call further upstream first,
            // as this is invoked for refreshing an identity on-demand,
            // and we don't know whether our cache is out-of-date.
            IDeviceScopeIdentitiesCache identitiesCache = edgeHub.GetDeviceScopeIdentitiesCache();
            await identitiesCache.RefreshServiceIdentityOnBehalfOf(targetId, originatingEdge);

            Option <ServiceIdentity> targetIdentity = await identitiesCache.GetServiceIdentity(targetId);

            if (!targetIdentity.HasValue)
            {
                // Identity still doesn't exist, this can happen if the identity
                // is newly added and we couldn't refresh the individual identity
                // because we don't know where it resides in the nested hierarchy.
                // In this case our only recourse is to refresh the whole cache
                // and hope the identity shows up.
                identitiesCache.InitiateCacheRefresh();
                await identitiesCache.WaitForCacheRefresh(TimeSpan.FromSeconds(100));

                targetIdentity = await identitiesCache.GetServiceIdentity(targetId);
            }

            // Add the identity to the result
            var identityList = new List <ServiceIdentity>();

            targetIdentity.ForEach(i => identityList.Add(i));

            // If the target is a module, we also need to
            // include the parent device as well to match
            // IoT Hub API behavior
            if (isModule)
            {
                Option <ServiceIdentity> device = await identitiesCache.GetServiceIdentity(request.TargetDeviceId);

                device.ForEach(i => identityList.Add(i));
            }

            Events.SendingScopeResult(targetId, identityList);
            return(MakeResultFromIdentities(identityList));
        }
Example #28
0
        static async Task <IList <BrokerServiceIdentity> > ConvertIdsToBrokerServiceIdentities(IList <string> ids, IDeviceScopeIdentitiesCache deviceScopeIdentitiesCache)
        {
            IList <BrokerServiceIdentity> brokerServiceIdentities = new List <BrokerServiceIdentity>();

            foreach (string id in ids)
            {
                brokerServiceIdentities.Add(
                    new BrokerServiceIdentity(id, await deviceScopeIdentitiesCache.GetAuthChain(id)));
            }

            return(brokerServiceIdentities);
        }
Example #29
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 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"));
        }