Example #1
0
        public async Task <Try <ICloudConnection> > Connect(IClientCredentials clientCredentials, Action <string, CloudConnectionStatus> connectionStatusChangedHandler)
        {
            Preconditions.CheckNotNull(clientCredentials, nameof(clientCredentials));

            try
            {
                Events.CreatingCloudConnectionUsingClientCredentials(clientCredentials);
                var    cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), clientCredentials.Identity.Id);
                string productInfo   = await this.productInfoStore.GetEdgeProductInfo(clientCredentials.Identity.Id);

                Option <string> modelId = await this.modelIdStore.GetModelId(clientCredentials.Identity.Id);

                if (this.edgeHubIdentity.Id.Equals(clientCredentials.Identity.Id))
                {
                    ICloudConnection cc = await CloudConnection.Create(
                        clientCredentials.Identity,
                        connectionStatusChangedHandler,
                        this.transportSettings,
                        this.messageConverterProvider,
                        this.clientProvider,
                        cloudListener,
                        this.edgeHubTokenProvider,
                        this.idleTimeout,
                        this.closeOnIdleTimeout,
                        this.operationTimeout,
                        productInfo,
                        modelId);

                    Events.SuccessCreatingCloudConnection(clientCredentials.Identity);
                    return(Try.Success(cc));
                }
                else if (clientCredentials is ITokenCredentials clientTokenCredentails)
                {
                    ICloudConnection cc = await ClientTokenCloudConnection.Create(
                        clientTokenCredentails,
                        connectionStatusChangedHandler,
                        this.transportSettings,
                        this.messageConverterProvider,
                        this.clientProvider,
                        cloudListener,
                        this.idleTimeout,
                        this.closeOnIdleTimeout,
                        this.operationTimeout,
                        productInfo,
                        modelId);

                    Events.SuccessCreatingCloudConnection(clientCredentials.Identity);
                    return(Try.Success(cc));
                }
                else
                {
                    throw new InvalidOperationException($"Cannot connect using client credentials of type {clientCredentials.AuthenticationType} for identity {clientCredentials.Identity.Id}");
                }
            }
            catch (Exception ex)
            {
                Events.ErrorCreatingCloudConnection(clientCredentials.Identity, ex);
                return(Try <ICloudConnection> .Failure(ex));
            }
        }
Example #2
0
        public async Task <Try <ICloudConnection> > Connect(IClientCredentials identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler)
        {
            Preconditions.CheckNotNull(identity, nameof(identity));

            try
            {
                var cloudListener   = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), identity.Identity.Id);
                var cloudConnection = new CloudConnection(
                    connectionStatusChangedHandler,
                    this.transportSettings,
                    this.messageConverterProvider,
                    this.clientProvider,
                    cloudListener,
                    this.edgeHubTokenProvider,
                    this.deviceScopeIdentitiesCache,
                    this.idleTimeout,
                    this.closeOnIdleTimeout);

                await cloudConnection.CreateOrUpdateAsync(identity);

                Events.SuccessCreatingCloudConnection(identity.Identity);
                return(Try.Success <ICloudConnection>(cloudConnection));
            }
            catch (Exception ex)
            {
                Events.ErrorCreatingCloudConnection(identity.Identity, ex);
                return(Try <ICloudConnection> .Failure(ex));
            }
        }
Example #3
0
        public async Task CallMethodAsync_InvokesDeviceProxy()
        {
            var    edgeHub       = Mock.Of <IEdgeHub>();
            var    identity      = Mock.Of <IIdentity>(i => i.Id == "device1");
            string testMethod    = "testMethod";
            var    testByteArray = new byte[] { 0x00, 0x01, 0x02 };
            string id            = "1";
            var    request       = new DirectMethodRequest(id, testMethod, testByteArray, TimeSpan.FromSeconds(30));

            var cloudListener = new CloudListener(edgeHub, identity.Id);
            await cloudListener.CallMethodAsync(request);

            Mock.Get(edgeHub).Verify(eh => eh.InvokeMethodAsync("upstream", request), Times.Once);
        }
Example #4
0
        public async Task <Try <ICloudConnection> > Connect(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler)
        {
            Preconditions.CheckNotNull(identity, nameof(identity));

            try
            {
                var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), identity.Id);
                Option <ServiceIdentity> serviceIdentity = (await this.deviceScopeIdentitiesCache.GetServiceIdentity(identity.Id))
                                                           .Filter(s => s.Status == ServiceIdentityStatus.Enabled);
                return(await serviceIdentity
                       .Map(
                           async si =>
                {
                    Events.CreatingCloudConnectionOnBehalfOf(identity);
                    ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(identity.Id);
                    string productInfo = connectionMetadata.EdgeProductInfo;
                    Option <string> modelId = connectionMetadata.ModelId;
                    ICloudConnection cc = await CloudConnection.Create(
                        identity,
                        connectionStatusChangedHandler,
                        this.transportSettings,
                        this.messageConverterProvider,
                        this.clientProvider,
                        cloudListener,
                        this.edgeHubTokenProvider,
                        this.idleTimeout,
                        this.closeOnIdleTimeout,
                        this.operationTimeout,
                        productInfo,
                        modelId);
                    Events.SuccessCreatingCloudConnection(identity);
                    return Try.Success(cc);
                })
                       .GetOrElse(
                           async() =>
                {
                    Events.ServiceIdentityNotFound(identity);
                    Option <IClientCredentials> clientCredentials = await this.credentialsCache.Get(identity);
                    return await clientCredentials
                    .Map(cc => this.Connect(cc, connectionStatusChangedHandler))
                    .GetOrElse(() => throw new InvalidOperationException($"Unable to find identity {identity.Id} in device scopes cache or credentials cache"));
                }));
            }
            catch (Exception ex)
            {
                Events.ErrorCreatingCloudConnection(identity, ex);
                return(Try <ICloudConnection> .Failure(ex));
            }
        }
Example #5
0
        public async Task OnDesiredPropertyUpdatesForwardsToEdgeHub()
        {
            var      edgeHub  = new Mock <IEdgeHub>();
            var      identity = Mock.Of <IIdentity>(i => i.Id == "device1");
            IMessage actual   = null;

            edgeHub.Setup(r => r.UpdateDesiredPropertiesAsync(It.IsAny <string>(), It.IsAny <IMessage>()))
            .Callback <string, IMessage>((s, m) => actual = m)
            .Returns(Task.FromResult(true));

            IMessage expected      = new EdgeMessage.Builder(Encoding.UTF8.GetBytes("{\"abc\":\"xyz\"}")).Build();
            var      cloudListener = new CloudListener(edgeHub.Object, identity.Id);
            await cloudListener.OnDesiredPropertyUpdates(expected);

            Assert.Equal(expected, actual);
        }
Example #6
0
        public async Task TestProcessMessage()
        {
            var edgeHub  = new Mock <IEdgeHub>();
            var identity = Mock.Of <IIdentity>(i => i.Id == "device1");

            IMessage sentMessage = null;

            edgeHub.Setup(r => r.SendC2DMessageAsync(It.IsAny <string>(), It.IsAny <IMessage>()))
            .Returns(Task.FromResult(true))
            .Callback <string, IMessage>((id, m) => sentMessage = m);

            var cloudListener = new CloudListener(edgeHub.Object, identity.Id);

            var      payload = new byte[] { 1, 2, 3 };
            IMessage message = new EdgeMessage.Builder(payload).Build();
            await cloudListener.ProcessMessageAsync(message);

            Assert.NotNull(sentMessage);
        }
        async Task <Try <ICloudConnection> > ConnectInternalWithDeviceStateTracking(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler, bool refreshCachedIdentity)
        {
            Preconditions.CheckNotNull(identity, nameof(identity));

            try
            {
                var    cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), identity.Id);
                string authChain     = await this.deviceScopeIdentitiesCache.VerifyServiceIdentityAuthChainState(identity.Id, this.nestedEdgeEnabled, refreshCachedIdentity);

                return(await this.TryCreateCloudConnectionFromServiceIdentity(identity, connectionStatusChangedHandler, refreshCachedIdentity, cloudListener, authChain));
            }
            catch (DeviceInvalidStateException ex)
            {
                return(await this.TryRecoverCloudConnection(identity, connectionStatusChangedHandler, refreshCachedIdentity, ex));
            }
            catch (Exception ex)
            {
                Events.ErrorCreatingCloudConnection(identity, ex);
                return(Try <ICloudConnection> .Failure(ex));
            }
        }
Example #8
0
        public async Task <Try <ICloudConnection> > Connect(IClientCredentials clientCredentials, Action <string, CloudConnectionStatus> connectionStatusChangedHandler)
        {
            Preconditions.CheckNotNull(clientCredentials, nameof(clientCredentials));

            try
            {
                Events.CreatingCloudConnectionUsingClientCredentials(clientCredentials);
                var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), clientCredentials.Identity.Id);
                ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(clientCredentials.Identity.Id);

                string          productInfo = connectionMetadata.EdgeProductInfo;
                Option <string> modelId     = clientCredentials.ModelId.HasValue ? clientCredentials.ModelId : connectionMetadata.ModelId;
                string          authChain   = string.Empty;
                if (this.nestedEdgeEnabled)
                {
                    Option <string> authChainMaybe = await this.deviceScopeIdentitiesCache.GetAuthChain(clientCredentials.Identity.Id);

                    // It's possible to have no auth-chain for out-of-scope leaf devices connecting through
                    // us as a gateway. In this case we let the upstream connection happen anyways, as any
                    // unauthorized attempt here would be denied by IoTHub.
                    authChain = authChainMaybe.OrDefault();
                }

                // Get the transport settings
                ITransportSettings[] transportSettings = GetTransportSettings(
                    this.upstreamProtocol,
                    this.connectionPoolSize,
                    this.proxy,
                    this.useServerHeartbeat,
                    authChain);

                if (this.edgeHubIdentity.Id.Equals(clientCredentials.Identity.Id))
                {
                    ICloudConnection cc = await CloudConnection.Create(
                        clientCredentials.Identity,
                        connectionStatusChangedHandler,
                        transportSettings,
                        this.messageConverterProvider,
                        this.clientProvider,
                        cloudListener,
                        this.edgeHubTokenProvider,
                        this.idleTimeout,
                        this.closeOnIdleTimeout,
                        this.operationTimeout,
                        productInfo,
                        modelId);

                    Events.SuccessCreatingCloudConnection(clientCredentials.Identity);
                    return(Try.Success(cc));
                }
                else if (clientCredentials is ITokenCredentials clientTokenCredentails)
                {
                    ICloudConnection cc = await ClientTokenCloudConnection.Create(
                        clientTokenCredentails,
                        connectionStatusChangedHandler,
                        transportSettings,
                        this.messageConverterProvider,
                        this.clientProvider,
                        cloudListener,
                        this.idleTimeout,
                        this.closeOnIdleTimeout,
                        this.operationTimeout,
                        productInfo,
                        modelId);

                    Events.SuccessCreatingCloudConnection(clientCredentials.Identity);
                    return(Try.Success(cc));
                }
                else
                {
                    throw new InvalidOperationException($"Cannot connect using client credentials of type {clientCredentials.AuthenticationType} for identity {clientCredentials.Identity.Id}");
                }
            }
            catch (Exception ex)
            {
                Events.ErrorCreatingCloudConnection(clientCredentials.Identity, ex);
                return(Try <ICloudConnection> .Failure(ex));
            }
        }
        async Task <Try <ICloudConnection> > TryCreateCloudConnectionFromServiceIdentity(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler, bool refreshOutOfDateCache, CloudListener cloudListener, string authChain)
        {
            Events.CreatingCloudConnectionOnBehalfOf(identity);
            ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(identity.Id);

            string          productInfo = connectionMetadata.EdgeProductInfo;
            Option <string> modelId     = connectionMetadata.ModelId;

            ITransportSettings[] transportSettings = GetTransportSettings(
                this.upstreamProtocol,
                this.connectionPoolSize,
                this.proxy,
                this.useServerHeartbeat,
                authChain);

            try
            {
                ICloudConnection cc = await CloudConnection.Create(
                    identity,
                    connectionStatusChangedHandler,
                    transportSettings,
                    this.messageConverterProvider,
                    this.clientProvider,
                    cloudListener,
                    this.edgeHubTokenProvider,
                    this.idleTimeout,
                    this.closeOnIdleTimeout,
                    this.operationTimeout,
                    productInfo,
                    modelId);

                Events.SuccessCreatingCloudConnection(identity);
                return(Try.Success(cc));
            }
            catch (UnauthorizedException ex) when(this.trackDeviceState)
            {
                return(await this.TryRecoverCloudConnection(identity, connectionStatusChangedHandler, refreshOutOfDateCache, ex));
            }
        }
Example #10
0
        async Task <Try <ICloudConnection> > ConnectInternal(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler)
        {
            Preconditions.CheckNotNull(identity, nameof(identity));

            try
            {
                var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), identity.Id);
                Option <ServiceIdentity> serviceIdentity = (await this.deviceScopeIdentitiesCache.GetServiceIdentity(identity.Id))
                                                           .Filter(s => s.Status == ServiceIdentityStatus.Enabled);

                string authChain = string.Empty;
                if (this.nestedEdgeEnabled)
                {
                    Option <string> authChainMaybe = await this.deviceScopeIdentitiesCache.GetAuthChain(identity.Id);

                    authChain = authChainMaybe.Expect(() => new InvalidOperationException($"No auth chain for the client identity: {identity.Id}"));
                }

                ITransportSettings[] transportSettings = GetTransportSettings(
                    this.upstreamProtocol,
                    this.connectionPoolSize,
                    this.proxy,
                    this.useServerHeartbeat,
                    authChain);

                return(await serviceIdentity
                       .Map(
                           async si =>
                {
                    Events.CreatingCloudConnectionOnBehalfOf(identity);
                    ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(identity.Id);
                    string productInfo = connectionMetadata.EdgeProductInfo;
                    Option <string> modelId = connectionMetadata.ModelId;
                    ICloudConnection cc = await CloudConnection.Create(
                        identity,
                        connectionStatusChangedHandler,
                        transportSettings,
                        this.messageConverterProvider,
                        this.clientProvider,
                        cloudListener,
                        this.edgeHubTokenProvider,
                        this.idleTimeout,
                        this.closeOnIdleTimeout,
                        this.operationTimeout,
                        productInfo,
                        modelId);
                    Events.SuccessCreatingCloudConnection(identity);
                    return Try.Success(cc);
                })
                       .GetOrElse(
                           async() =>
                {
                    // allow to use credential cache when auth mode is not Scope only (could be CloudAndScope or Cloud) or identity is for edgeHub
                    if (!this.scopeAuthenticationOnly || this.edgeHubIdentity.Id.Equals(identity.Id))
                    {
                        Events.ServiceIdentityNotFound(identity);
                        Option <IClientCredentials> clientCredentials = await this.credentialsCache.Get(identity);
                        var clientCredential = clientCredentials.Expect(() => new InvalidOperationException($"Unable to find identity {identity.Id} in device scopes cache or credentials cache"));
                        return await this.Connect(clientCredential, connectionStatusChangedHandler);
                    }
                    else
                    {
                        throw new InvalidOperationException($"Unable to find identity {identity.Id} in device scopes cache");
                    }
                }));
            }
            catch (Exception ex)
            {
                Events.ErrorCreatingCloudConnection(identity, ex);
                return(Try <ICloudConnection> .Failure(ex));
            }
        }