Exemple #1
0
        public async Task UpdateInvalidIdentityWithTokenTest()
        {
            var deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.SetupSequence(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <ITokenProvider>(), It.IsAny <ITransportSettings[]>()))
            .Returns(GetMockDeviceClient())
            .Throws(new UnauthorizedException("Unauthorized"));

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            ITokenCredentials          identity1       = GetMockClientCredentialsWithToken();
            ClientTokenCloudConnection cloudConnection = await ClientTokenCloudConnection.Create(
                identity1,
                (_, __) => { },
                transportSettings,
                messageConverterProvider,
                deviceClientProvider.Object,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20));

            Option <ICloudProxy> cloudProxy1 = cloudConnection.CloudProxy;

            Assert.True(cloudProxy1.HasValue);
            Assert.True(cloudProxy1.OrDefault().IsActive);

            ITokenCredentials identity2 = GetMockClientCredentialsWithToken();
            await Assert.ThrowsAsync <UnauthorizedException>(() => cloudConnection.UpdateTokenAsync(identity2));

            Assert.True(cloudProxy1.OrDefault().IsActive);
        }
        private static SigningCredentials BuildSigningCredentials(ITokenCredentials request)
        {
            MaybeSelfCreateMissingKeyStrings(request);
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(request.SigningKeyString));

            return(new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256));
        }
Exemple #3
0
        public async Task GetCloudConnectionForIdentityWithTokenTest()
        {
            IClientProvider clientProvider           = GetMockDeviceClientProviderWithToken();
            var             transportSettings        = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };
            var             messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            ITokenCredentials          clientCredentials1 = GetMockClientCredentialsWithToken();
            ClientTokenCloudConnection cloudConnection    = await ClientTokenCloudConnection.Create(
                clientCredentials1,
                (_, __) => { },
                transportSettings,
                messageConverterProvider,
                clientProvider,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20));

            Option <ICloudProxy> cloudProxy1 = cloudConnection.CloudProxy;

            Assert.True(cloudProxy1.HasValue);
            Assert.True(cloudProxy1.OrDefault().IsActive);

            ITokenCredentials clientCredentials2 = GetMockClientCredentialsWithToken();
            ICloudProxy       cloudProxy2        = await cloudConnection.UpdateTokenAsync(clientCredentials2);

            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy2.IsActive);
            Assert.False(cloudProxy1.OrDefault().IsActive);
            Assert.NotEqual(cloudProxy1.OrDefault(), cloudProxy2);
        }
Exemple #4
0
        public static async Task <ClientTokenCloudConnection> Create(
            ITokenCredentials tokenCredentials,
            Action <string, CloudConnectionStatus> connectionStatusChangedHandler,
            ITransportSettings[] transportSettings,
            IMessageConverterProvider messageConverterProvider,
            IClientProvider clientProvider,
            ICloudListener cloudListener,
            TimeSpan idleTimeout,
            bool closeOnIdleTimeout,
            TimeSpan operationTimeout)
        {
            Preconditions.CheckNotNull(tokenCredentials, nameof(tokenCredentials));
            var cloudConnection = new ClientTokenCloudConnection(
                tokenCredentials.Identity,
                connectionStatusChangedHandler,
                transportSettings,
                messageConverterProvider,
                clientProvider,
                cloudListener,
                idleTimeout,
                closeOnIdleTimeout,
                operationTimeout);
            ITokenProvider tokenProvider = new ClientTokenBasedTokenProvider(tokenCredentials, cloudConnection);
            ICloudProxy    cloudProxy    = await cloudConnection.CreateNewCloudProxyAsync(tokenProvider);

            cloudConnection.cloudProxy = Option.Some(cloudProxy);
            return(cloudConnection);
        }
        private static EncryptingCredentials BuildEncryptingCredentials(ITokenCredentials request)
        {
            MaybeSelfCreateMissingKeyStrings(request);
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(request.EncryptingKeyString));

            return(new EncryptingCredentials(securityKey, JwtConstants.DirectKeyUseAlg,
                                             SecurityAlgorithms.Aes256CbcHmacSha512));
        }
        public async Task InitializeAndGetCloudProxyTest()
        {
            string iothubHostName = "test.azure-devices.net";
            string deviceId       = "device1";

            ITokenCredentials GetClientCredentialsWithNonExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddMinutes(10));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty, Option.None <string>(), Option.None <string>(), false));
            }

            IClient client = GetMockDeviceClient();
            var     deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.Setup(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <ITokenProvider>(), It.IsAny <ITransportSettings[]>(), Option.None <string>()))
            .Returns(() => client);

            var transportSettings        = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };
            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });

            ITokenCredentials          clientCredentialsWithNonExpiringToken = GetClientCredentialsWithNonExpiringToken();
            ClientTokenCloudConnection cloudConnection = await ClientTokenCloudConnection.Create(
                clientCredentialsWithNonExpiringToken,
                (_, __) => { },
                transportSettings,
                messageConverterProvider,
                deviceClientProvider.Object,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20),
                DummyProductInfo,
                Option.None <string>());

            Option <ICloudProxy> cloudProxy = cloudConnection.CloudProxy;

            Assert.True(cloudProxy.HasValue);
            Assert.True(cloudProxy.OrDefault().IsActive);
            Mock.Get(client).Verify(c => c.OpenAsync(), Times.Once);
        }
Exemple #7
0
        async Task <bool> AuthenticateInternalAsync(ITokenCredentials tokenCredentials, ServiceIdentity serviceIdentity)
        {
            if (!this.TryGetSharedAccessSignature(tokenCredentials.Token, tokenCredentials.Identity, out SharedAccessSignature sharedAccessSignature))
            {
                return(false);
            }

            bool result = this.ValidateCredentials(sharedAccessSignature, serviceIdentity, tokenCredentials.Identity);

            if (!result && tokenCredentials.Identity is IModuleIdentity moduleIdentity && serviceIdentity.IsModule)
            {
                // Module can use the Device key to authenticate
                Option <ServiceIdentity> deviceServiceIdentity = await this.deviceScopeIdentitiesCache.GetServiceIdentity(moduleIdentity.DeviceId);

                result = await deviceServiceIdentity.Map(d => this.AuthenticateInternalAsync(tokenCredentials, d))
                         .GetOrElse(Task.FromResult(false));
            }
            return(result);
        }
        public static bool MaybeSelfCreateMissingKeyStrings(ITokenCredentials feature)
        {
            var changed = false;

            if (feature.SigningKey == null || feature.SigningKeyString == Constants.Tokens.NoSigningKeySet)
            {
                Trace.TraceWarning("No JWT signing key found, creating temporary key.");
                feature.SigningKeyString = Encoding.UTF8.GetString(SodiumCore.GetRandomBytes(128));
                changed = true;
            }

            if (feature.EncryptingKey == null || feature.EncryptingKeyString == Constants.Tokens.NoEncryptingKeySet)
            {
                Trace.TraceWarning("No JWT encryption key found, using signing key.");
                feature.EncryptingKeyString = feature.SigningKeyString;
                changed = true;
            }

            return(changed);
        }
Exemple #9
0
 /// <summary>
 /// This is the super slow token updater. It simulates situations where a token needs to be retrieved from a potato server.
 /// It waits for 10 seconds and then simply appends '0' to the current token.
 /// </summary>
 private static Task <TimeSpan> SlowTokenUpdater(ITokenCredentials credential)
 {
     Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false).GetAwaiter().GetResult();
     credential.SetToken(credential.Token + "0");
     return(Task.FromResult(TimeSpan.FromSeconds(1)));
 }
Exemple #10
0
 /// <summary>
 /// This is the fast token updater.
 /// It simply appends '0' to the current token.
 /// </summary>
 private static Task <TimeSpan> FastTokenUpdater(ITokenCredentials credential)
 {
     credential.SetToken(credential.Token + "0");
     return(Task.FromResult(TimeSpan.FromSeconds(1)));
 }
Exemple #11
0
        public async Task UpdateDeviceConnectionTest()
        {
            int receivedConnectedStatusCount = 0;
            ConnectionStatusChangesHandler connectionStatusChangesHandler = null;
            string hostname = "dummy.azure-devices.net";
            string deviceId = "device1";

            ITokenCredentials GetClientCredentials(TimeSpan tokenExpiryDuration)
            {
                string token    = TokenHelper.CreateSasToken(hostname, DateTime.UtcNow.AddSeconds(tokenExpiryDuration.TotalSeconds));
                var    identity = new DeviceIdentity(hostname, deviceId);

                return(new TokenCredentials(identity, token, string.Empty, false));
            }

            IDeviceProxy GetMockDeviceProxy()
            {
                var deviceProxyMock1 = new Mock <IDeviceProxy>();

                deviceProxyMock1.SetupGet(dp => dp.IsActive).Returns(true);
                deviceProxyMock1.Setup(dp => dp.CloseAsync(It.IsAny <Exception>()))
                .Callback(() => deviceProxyMock1.SetupGet(dp => dp.IsActive).Returns(false))
                .Returns(Task.CompletedTask);
                return(deviceProxyMock1.Object);
            }

            IClient GetMockedDeviceClient()
            {
                var deviceClient = new Mock <IClient>();

                deviceClient.SetupGet(dc => dc.IsActive).Returns(true);
                deviceClient.Setup(dc => dc.CloseAsync())
                .Callback(() => deviceClient.SetupGet(dc => dc.IsActive).Returns(false))
                .Returns(Task.FromResult(true));

                deviceClient.Setup(dc => dc.SetConnectionStatusChangedHandler(It.IsAny <ConnectionStatusChangesHandler>()))
                .Callback <ConnectionStatusChangesHandler>(c => connectionStatusChangesHandler = c);

                deviceClient.Setup(dc => dc.OpenAsync())
                .Callback(
                    () =>
                {
                    int currentCount = receivedConnectedStatusCount;
                    Assert.NotNull(connectionStatusChangesHandler);
                    connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
                    Assert.Equal(receivedConnectedStatusCount, currentCount);
                })
                .Returns(Task.CompletedTask);
                return(deviceClient.Object);
            }

            ITokenProvider tokenProvider        = null;
            var            deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.Setup(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <ITokenProvider>(), It.IsAny <ITransportSettings[]>()))
            .Callback <IIdentity, ITokenProvider, ITransportSettings[]>((s, a, t) => tokenProvider = a)
            .Returns(() => GetMockedDeviceClient());

            var messageConverterProvider = Mock.Of <IMessageConverterProvider>();

            var credentialsCache = Mock.Of <ICredentialsCache>();
            ICloudConnectionProvider cloudConnectionProvider = new CloudConnectionProvider(
                messageConverterProvider,
                1,
                deviceClientProvider.Object,
                Option.None <UpstreamProtocol>(),
                TokenProvider,
                DeviceScopeIdentitiesCache,
                credentialsCache,
                Mock.Of <IIdentity>(i => i.Id == $"{deviceId}/$edgeHub"),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20));

            cloudConnectionProvider.BindEdgeHub(Mock.Of <IEdgeHub>());
            IConnectionManager connectionManager = new ConnectionManager(cloudConnectionProvider, Mock.Of <ICredentialsCache>(), new IdentityProvider(hostname));

            ITokenCredentials clientCredentials1 = GetClientCredentials(TimeSpan.FromSeconds(10));
            Try <ICloudProxy> cloudProxyTry1     = await connectionManager.CreateCloudConnectionAsync(clientCredentials1);

            Assert.True(cloudProxyTry1.Success);

            IDeviceProxy deviceProxy1 = GetMockDeviceProxy();
            await connectionManager.AddDeviceConnection(clientCredentials1.Identity, deviceProxy1);

            await Task.Delay(TimeSpan.FromSeconds(10));

            Assert.NotNull(tokenProvider);
            Task <string> tokenGetter = tokenProvider.GetTokenAsync(Option.None <TimeSpan>());

            Assert.False(tokenGetter.IsCompleted);

            ITokenCredentials clientCredentials2 = GetClientCredentials(TimeSpan.FromMinutes(2));
            Try <ICloudProxy> cloudProxyTry2     = await connectionManager.CreateCloudConnectionAsync(clientCredentials2);

            Assert.True(cloudProxyTry2.Success);

            IDeviceProxy deviceProxy2 = GetMockDeviceProxy();
            await connectionManager.AddDeviceConnection(clientCredentials2.Identity, deviceProxy2);

            await Task.Delay(TimeSpan.FromSeconds(3));

            Assert.False(tokenGetter.IsCompleted);

            ITokenCredentials clientCredentials3 = GetClientCredentials(TimeSpan.FromMinutes(10));
            Try <ICloudProxy> cloudProxyTry3     = await connectionManager.CreateCloudConnectionAsync(clientCredentials3);

            Assert.True(cloudProxyTry3.Success);

            IDeviceProxy deviceProxy3 = GetMockDeviceProxy();
            await connectionManager.AddDeviceConnection(clientCredentials3.Identity, deviceProxy3);

            await Task.Delay(TimeSpan.FromSeconds(23));

            Assert.True(tokenGetter.IsCompleted);
            Assert.Equal(tokenGetter.Result, clientCredentials3.Token);
        }
Exemple #12
0
        public async Task CloudConnectionCallbackTest()
        {
            int receivedConnectedStatusCount = 0;
            ConnectionStatusChangesHandler connectionStatusChangesHandler = (_, __) => { };

            IClient GetMockedDeviceClient()
            {
                var deviceClient = new Mock <IClient>();

                deviceClient.SetupGet(dc => dc.IsActive).Returns(true);
                deviceClient.Setup(dc => dc.CloseAsync())
                .Callback(() => deviceClient.SetupGet(dc => dc.IsActive).Returns(false))
                .Returns(Task.FromResult(true));

                deviceClient.Setup(dc => dc.SetConnectionStatusChangedHandler(It.IsAny <ConnectionStatusChangesHandler>()))
                .Callback <ConnectionStatusChangesHandler>(c => connectionStatusChangesHandler = c);

                deviceClient.Setup(dc => dc.OpenAsync())
                .Callback(
                    () =>
                {
                    Assert.NotNull(connectionStatusChangesHandler);
                    connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
                })
                .Returns(Task.CompletedTask);
                return(deviceClient.Object);
            }

            var deviceClientProvider = new Mock <IClientProvider>();

            deviceClientProvider.Setup(dc => dc.Create(It.IsAny <IIdentity>(), It.IsAny <ITokenProvider>(), It.IsAny <ITransportSettings[]>()))
            .Returns(() => GetMockedDeviceClient());

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            void ConnectionStatusHandler(string id, CloudConnectionStatus status)
            {
                if (status == CloudConnectionStatus.ConnectionEstablished)
                {
                    receivedConnectedStatusCount++;
                }
            }

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });
            ITokenCredentials          clientCredentialsWithExpiringToken1 = GetMockClientCredentialsWithToken();
            ClientTokenCloudConnection cloudConnection = await ClientTokenCloudConnection.Create(
                clientCredentialsWithExpiringToken1,
                ConnectionStatusHandler,
                transportSettings,
                messageConverterProvider,
                deviceClientProvider.Object,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20));

            Assert.Equal(receivedConnectedStatusCount, 1);
            Option <ICloudProxy> cloudProxy1 = cloudConnection.CloudProxy;

            Assert.True(cloudProxy1.HasValue);
            Assert.True(cloudProxy1.OrDefault().IsActive);

            Assert.NotNull(connectionStatusChangesHandler);
            connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
            Assert.Equal(receivedConnectedStatusCount, 2);

            ITokenCredentials clientCredentialsWithExpiringToken2 = GetMockClientCredentialsWithToken();
            ICloudProxy       cloudProxy2 = await cloudConnection.UpdateTokenAsync(clientCredentialsWithExpiringToken2);

            Assert.True(cloudProxy2.IsActive);
            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.Equal(receivedConnectedStatusCount, 2);

            connectionStatusChangesHandler.Invoke(ConnectionStatus.Connected, ConnectionStatusChangeReason.Connection_Ok);
            Assert.Equal(receivedConnectedStatusCount, 3);
        }
Exemple #13
0
        /// <summary>
        /// This method does the following -
        ///     1. Updates the Identity to be used for the cloud connection
        ///     2. Updates the cloud proxy -
        ///         i. If there is an existing device client and
        ///             a. If is waiting for an updated token, and the Identity has a token,
        ///                then it uses that to give it to the waiting client authentication method.
        ///             b. If not, then it creates a new cloud proxy (and device client) and closes the existing one
        ///         ii. Else, if there is no cloud proxy, then opens a device client and creates a cloud proxy.
        /// </summary>
        public async Task <ICloudProxy> UpdateTokenAsync(ITokenCredentials newTokenCredentials)
        {
            Preconditions.CheckNotNull(newTokenCredentials, nameof(newTokenCredentials));

            using (await this.identityUpdateLock.LockAsync())
            {
                // Disable callbacks while we update the cloud proxy.
                // TODO - instead of this, make convert Option<ICloudProxy> CloudProxy to Task<Option<ICloudProxy>> GetCloudProxy
                // which can be awaited when an update is in progress.
                this.callbacksEnabled = false;
                try
                {
                    ITokenProvider tokenProvider = new ClientTokenBasedTokenProvider(newTokenCredentials, this);
                    // First check if there is an existing cloud proxy
                    ICloudProxy proxy = await this.CloudProxy.Map(
                        async cp =>
                    {
                        // If the Identity has a token, and we have a tokenGetter, that means
                        // the connection is waiting for a new token. So give it the token and
                        // complete the tokenGetter
                        if (this.tokenGetter.HasValue)
                        {
                            if (TokenHelper.IsTokenExpired(this.Identity.IotHubHostName, newTokenCredentials.Token))
                            {
                                throw new InvalidOperationException($"Token for client {this.Identity.Id} is expired");
                            }

                            this.tokenGetter.ForEach(
                                tg =>
                            {
                                // First reset the token getter and then set the result.
                                this.tokenGetter = Option.None <TaskCompletionSource <string> >();
                                tg.SetResult(newTokenCredentials.Token);
                            });
                            return(cp);
                        }
                        // Else this is a new connection for the same device Id. So open a new connection,
                        // and if that is successful, close the existing one.
                        else
                        {
                            ICloudProxy newCloudProxy = await this.CreateNewCloudProxyAsync(tokenProvider);
                            await cp.CloseAsync();
                            return(newCloudProxy);
                        }
                    })
                                        // No existing cloud proxy, so just create a new one.
                                        .GetOrElse(() => this.CreateNewCloudProxyAsync(tokenProvider));

                    // Set Identity only after successfully opening cloud proxy
                    // That way, if a we have one existing connection for a deviceA,
                    // and a new connection for deviceA comes in with an invalid key/token,
                    // the existing connection is not affected.
                    this.cloudProxy = Option.Some(proxy);
                    Events.UpdatedCloudConnection(this.Identity);
                    return(proxy);
                }
                catch (Exception ex)
                {
                    Events.CreateException(ex, this.Identity);
                    throw;
                }
                finally
                {
                    this.callbacksEnabled = true;
                }
            }
        }
Exemple #14
0
 public ClientTokenBasedTokenProvider(ITokenCredentials tokenCredentials, ClientTokenCloudConnection cloudConnection)
 {
     this.cloudConnection = cloudConnection;
     this.token           = tokenCredentials.Token;
 }
 public TokenCreator(string consumerKey, string consumerSecret)
 {
     _credentials    = new TokenCredentials(null, null, consumerKey, consumerSecret);
     _tokenRequester = new OAuthToken(_credentials);
 }
Exemple #16
0
 /// <summary>
 /// This updater throws exceptions. It simulates situations where errors occur while retrieving a token from a potato server.
 /// </summary>
 private static Task <TimeSpan> BrokenTokenUpdater(ITokenCredentials credential)
 => throw new Exception();
Exemple #17
0
        public async Task RefreshTokenWithRetryTest()
        {
            string iothubHostName = "test.azure-devices.net";
            string deviceId       = "device1";

            ITokenCredentials GetClientCredentialsWithExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddMinutes(3));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty, false));
            }

            ITokenCredentials GetClientCredentialsWithNonExpiringToken()
            {
                string token    = TokenHelper.CreateSasToken(iothubHostName, DateTime.UtcNow.AddMinutes(10));
                var    identity = new DeviceIdentity(iothubHostName, deviceId);

                return(new TokenCredentials(identity, token, string.Empty, false));
            }

            ITokenProvider  tokenProvider  = null;
            IClientProvider clientProvider = GetMockDeviceClientProviderWithToken((s, a, t) => tokenProvider = a);

            var transportSettings = new ITransportSettings[] { new AmqpTransportSettings(TransportType.Amqp_Tcp_Only) };

            var receivedStatuses = new List <CloudConnectionStatus>();

            void ConnectionStatusHandler(string id, CloudConnectionStatus status) => receivedStatuses.Add(status);

            var messageConverterProvider = new MessageConverterProvider(new Dictionary <Type, IMessageConverter> {
                [typeof(TwinCollection)] = Mock.Of <IMessageConverter>()
            });

            ITokenCredentials          clientCredentialsWithExpiringToken1 = GetClientCredentialsWithExpiringToken();
            ClientTokenCloudConnection cloudConnection = await ClientTokenCloudConnection.Create(
                clientCredentialsWithExpiringToken1,
                ConnectionStatusHandler,
                transportSettings,
                messageConverterProvider,
                clientProvider,
                Mock.Of <ICloudListener>(),
                TimeSpan.FromMinutes(60),
                true,
                TimeSpan.FromSeconds(20));

            Option <ICloudProxy> cloudProxy1 = cloudConnection.CloudProxy;

            Assert.True(cloudProxy1.HasValue);
            Assert.True(cloudProxy1.OrDefault().IsActive);

            Assert.NotNull(tokenProvider);

            // Try to refresh token but get an expiring token
            Task <string> getTokenTask = tokenProvider.GetTokenAsync(Option.None <TimeSpan>());

            Assert.False(getTokenTask.IsCompleted);

            Assert.Equal(1, receivedStatuses.Count);
            Assert.Equal(receivedStatuses[0], CloudConnectionStatus.TokenNearExpiry);

            ICloudProxy cloudProxy2 = await cloudConnection.UpdateTokenAsync(clientCredentialsWithExpiringToken1);

            // Wait for the task to process
            await Task.Delay(TimeSpan.FromSeconds(5));

            Assert.False(getTokenTask.IsCompletedSuccessfully);
            Assert.Equal(cloudProxy2, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy2.IsActive);
            Assert.True(cloudProxy1.OrDefault().IsActive);
            Assert.Equal(cloudProxy1.OrDefault(), cloudProxy2);

            // Wait for 20 secs for retry to happen
            await Task.Delay(TimeSpan.FromSeconds(20));

            // Check if retry happened
            Assert.Equal(2, receivedStatuses.Count);
            Assert.Equal(receivedStatuses[1], CloudConnectionStatus.TokenNearExpiry);

            ITokenCredentials clientCredentialsWithNonExpiringToken = GetClientCredentialsWithNonExpiringToken();
            ICloudProxy       cloudProxy3 = await cloudConnection.UpdateTokenAsync(clientCredentialsWithNonExpiringToken);

            // Wait for the task to complete
            await Task.Delay(TimeSpan.FromSeconds(5));

            Assert.True(getTokenTask.IsCompletedSuccessfully);
            Assert.Equal(cloudProxy3, cloudConnection.CloudProxy.OrDefault());
            Assert.True(cloudProxy3.IsActive);
            Assert.True(cloudProxy1.OrDefault().IsActive);
            Assert.Equal(cloudProxy1.OrDefault(), cloudProxy3);
            Assert.Equal(getTokenTask.Result, clientCredentialsWithNonExpiringToken.Token);
        }
 public static void MaybeSetSecurityKeys(ITokenCredentials request)
 {
     request.SigningKey ??= request.SigningKey = BuildSigningCredentials(request);
     request.EncryptingKey ??= (request.EncryptingKey = BuildEncryptingCredentials(request));
 }