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)); }
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); }
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); }
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); }
/// <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))); }
/// <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))); }
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); }
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); }
/// <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; } } }
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); }
/// <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();
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)); }