diff --git a/e2e/test/iothub/service/IoTHubCertificateValidationE2ETest.cs b/e2e/test/iothub/service/IoTHubCertificateValidationE2ETest.cs index 9be17041bb..f8c74fe8ec 100644 --- a/e2e/test/iothub/service/IoTHubCertificateValidationE2ETest.cs +++ b/e2e/test/iothub/service/IoTHubCertificateValidationE2ETest.cs @@ -2,9 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Net.WebSockets; +using System.Net; using System.Security.Authentication; using System.Threading.Tasks; +using FluentAssertions; using Microsoft.Azure.Devices.Client; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -18,14 +19,21 @@ public class IotHubCertificateValidationE2ETest : E2EMsTestBase [Timeout(TestTimeoutMilliseconds)] public async Task ServiceClient_QueryDevicesInvalidServiceCertificateHttp_Fails() { + // arrange using var sc = new IotHubServiceClient(TestConfiguration.IotHub.ConnectionStringInvalidServiceCertificate); - var exception = await Assert.ThrowsExceptionAsync( - () => sc.Query.CreateAsync("select * from devices")).ConfigureAwait(false); + // act + Func act = async () => await sc.Query.CreateAsync("select * from devices").ConfigureAwait(false); + + // assert + var error = await act.Should().ThrowAsync(); + error.And.StatusCode.Should().Be(HttpStatusCode.Unauthorized); + error.And.ErrorCode.Should().Be(IotHubServiceErrorCode.IotHubUnauthorizedAccess); + error.And.IsTransient.Should().BeFalse(); #if NET472 - Assert.IsInstanceOfType(exception.InnerException.InnerException.InnerException, typeof(AuthenticationException)); + error.And.InnerException.InnerException.InnerException.Should().BeOfType(); #else - Assert.IsInstanceOfType(exception.InnerException.InnerException, typeof(AuthenticationException)); + error.And.InnerException.InnerException.Should().BeOfType(); #endif } @@ -33,27 +41,43 @@ public async Task ServiceClient_QueryDevicesInvalidServiceCertificateHttp_Fails( [Timeout(TestTimeoutMilliseconds)] public async Task ServiceClient_SendMessageToDeviceInvalidServiceCertificateAmqpTcp_Fails() { + // arrange IotHubTransportProtocol protocol = IotHubTransportProtocol.Tcp; - await Assert.ThrowsExceptionAsync( - () => TestServiceClientInvalidServiceCertificate(protocol)).ConfigureAwait(false); + + // act + Func act = async () => await TestServiceClientInvalidServiceCertificateAsync(protocol).ConfigureAwait(false); + + // assert + var error = await act.Should().ThrowAsync(); + error.And.StatusCode.Should().Be(HttpStatusCode.Unauthorized); + error.And.ErrorCode.Should().Be(IotHubServiceErrorCode.IotHubUnauthorizedAccess); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.Should().BeOfType(); } [TestMethod] [Timeout(TestTimeoutMilliseconds)] public async Task ServiceClient_SendMessageToDeviceInvalidServiceCertificateAmqpWs_Fails() { + // arrange IotHubTransportProtocol protocol = IotHubTransportProtocol.WebSocket; - WebSocketException exception = await Assert.ThrowsExceptionAsync( - () => TestServiceClientInvalidServiceCertificate(protocol)).ConfigureAwait(false); - - Assert.IsInstanceOfType(exception.InnerException.InnerException, typeof(AuthenticationException)); + + // act + Func act = async () => await TestServiceClientInvalidServiceCertificateAsync(protocol).ConfigureAwait(false); + + //assert + var error = await act.Should().ThrowAsync(); + error.And.StatusCode.Should().Be(HttpStatusCode.Unauthorized); + error.And.ErrorCode.Should().Be(IotHubServiceErrorCode.IotHubUnauthorizedAccess); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.InnerException.InnerException.Should().BeOfType(); } - private static async Task TestServiceClientInvalidServiceCertificate(IotHubTransportProtocol protocol) + private static async Task TestServiceClientInvalidServiceCertificateAsync(IotHubTransportProtocol protocol) { - IotHubServiceClientOptions options = new IotHubServiceClientOptions + var options = new IotHubServiceClientOptions { - Protocol = protocol + Protocol = protocol, }; using var service = new IotHubServiceClient(TestConfiguration.IotHub.ConnectionStringInvalidServiceCertificate, options); var testMessage = new Message(); @@ -66,24 +90,32 @@ private static async Task TestServiceClientInvalidServiceCertificate(IotHubTrans [Timeout(TestTimeoutMilliseconds)] public async Task JobClient_ScheduleTwinUpdateInvalidServiceCertificateHttp_Fails() { + // arrange using var sc = new IotHubServiceClient(TestConfiguration.IotHub.ConnectionStringInvalidServiceCertificate); var ScheduledTwinUpdateOptions = new ScheduledJobsOptions { JobId = "testDevice", MaxExecutionTime = TimeSpan.FromSeconds(60) }; - var exception = await Assert.ThrowsExceptionAsync( - () => sc.ScheduledJobs.ScheduleTwinUpdateAsync( + + // act + Func act = async () => + await sc.ScheduledJobs.ScheduleTwinUpdateAsync( "DeviceId IN ['testDevice']", new ClientTwin(), DateTimeOffset.UtcNow, - ScheduledTwinUpdateOptions)) + ScheduledTwinUpdateOptions) .ConfigureAwait(false); + // assert + var error = await act.Should().ThrowAsync(); + error.And.StatusCode.Should().Be(HttpStatusCode.Unauthorized); + error.And.ErrorCode.Should().Be(IotHubServiceErrorCode.IotHubUnauthorizedAccess); + error.And.IsTransient.Should().BeFalse(); #if NET472 - Assert.IsInstanceOfType(exception.InnerException.InnerException.InnerException, typeof(AuthenticationException)); + error.And.InnerException.InnerException.InnerException.Should().BeOfType(); #else - Assert.IsInstanceOfType(exception.InnerException.InnerException, typeof(AuthenticationException)); + error.And.InnerException.InnerException.Should().BeOfType(); #endif } @@ -91,43 +123,66 @@ public async Task JobClient_ScheduleTwinUpdateInvalidServiceCertificateHttp_Fail [Timeout(TestTimeoutMilliseconds)] public async Task IotHubDeviceClient_SendAsyncInvalidServiceCertificateAmqpTcp_Fails() { - await Assert.ThrowsExceptionAsync( - () => TestDeviceClientInvalidServiceCertificate(new IotHubClientAmqpSettings())).ConfigureAwait(false); + // act + Func act = async () => await TestDeviceClientInvalidServiceCertificateAsync(new IotHubClientAmqpSettings()).ConfigureAwait(false); + + // assert + var error = await act.Should().ThrowAsync(); + error.And.ErrorCode.Should().Be(IotHubClientErrorCode.TlsAuthenticationError); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.Should().BeOfType(); } [TestMethod] [Timeout(TestTimeoutMilliseconds)] public async Task IotHubDeviceClient_SendAsyncInvalidServiceCertificateMqttTcp_Fails() { - await Assert.ThrowsExceptionAsync( - () => TestDeviceClientInvalidServiceCertificate(new IotHubClientMqttSettings())).ConfigureAwait(false); + // act + Func act = async () => await TestDeviceClientInvalidServiceCertificateAsync(new IotHubClientMqttSettings()).ConfigureAwait(false); + + // assert + var error = await act.Should().ThrowAsync(); + error.And.ErrorCode.Should().Be(IotHubClientErrorCode.TlsAuthenticationError); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.InnerException.Should().BeOfType(); } [TestMethod] [Timeout(TestTimeoutMilliseconds)] public async Task IotHubDeviceClient_SendAsyncInvalidServiceCertificateAmqpWs_Fails() { - AuthenticationException exception = await Assert.ThrowsExceptionAsync( - () => TestDeviceClientInvalidServiceCertificate(new IotHubClientAmqpSettings(IotHubClientTransportProtocol.WebSocket))).ConfigureAwait(false); - - Assert.IsInstanceOfType(exception.InnerException.InnerException, typeof(AuthenticationException)); + // act + Func act = async () => + await TestDeviceClientInvalidServiceCertificateAsync(new IotHubClientAmqpSettings(IotHubClientTransportProtocol.WebSocket)).ConfigureAwait(false); + + // assert + var error = await act.Should().ThrowAsync(); + error.And.ErrorCode.Should().Be(IotHubClientErrorCode.TlsAuthenticationError); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.InnerException.InnerException.Should().BeOfType(); } [TestMethod] [Timeout(TestTimeoutMilliseconds)] public async Task IotHubDeviceClient_SendAsyncInvalidServiceCertificateMqttWs_Fails() { - AuthenticationException exception = await Assert.ThrowsExceptionAsync( - () => TestDeviceClientInvalidServiceCertificate(new IotHubClientMqttSettings(IotHubClientTransportProtocol.WebSocket))).ConfigureAwait(false); - - Assert.IsInstanceOfType(exception.InnerException.InnerException.InnerException, typeof(AuthenticationException)); + // act + Func act = async () => + await TestDeviceClientInvalidServiceCertificateAsync(new IotHubClientMqttSettings(IotHubClientTransportProtocol.WebSocket)).ConfigureAwait(false); + + // assert + var error = await act.Should().ThrowAsync(); + error.And.ErrorCode.Should().Be(IotHubClientErrorCode.TlsAuthenticationError); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.InnerException.InnerException.InnerException.Should().BeOfType(); } - private static async Task TestDeviceClientInvalidServiceCertificate(IotHubClientTransportSettings transportSettings) + private static async Task TestDeviceClientInvalidServiceCertificateAsync(IotHubClientTransportSettings transportSettings) { - await using var deviceClient = new IotHubDeviceClient( - TestConfiguration.IotHub.DeviceConnectionStringInvalidServiceCertificate, - new IotHubClientOptions(transportSettings)); + await using var deviceClient = + new IotHubDeviceClient( + TestConfiguration.IotHub.DeviceConnectionStringInvalidServiceCertificate, + new IotHubClientOptions(transportSettings)); var testMessage = new TelemetryMessage(); await deviceClient.OpenAsync().ConfigureAwait(false); await deviceClient.SendTelemetryAsync(testMessage).ConfigureAwait(false); diff --git a/e2e/test/provisioning/ProvisioningCertificateValidationE2ETest.cs b/e2e/test/provisioning/ProvisioningCertificateValidationE2ETest.cs index f513363b15..8cbe003904 100644 --- a/e2e/test/provisioning/ProvisioningCertificateValidationE2ETest.cs +++ b/e2e/test/provisioning/ProvisioningCertificateValidationE2ETest.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Linq; +using System.Net; using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; @@ -34,18 +35,22 @@ public static void TestClassSetup(TestContext _) [Timeout(TestTimeoutMilliseconds)] public async Task ProvisioningServiceClient_QueryInvalidServiceCertificateHttp_Fails() { - using var provisioningServiceClient = new ProvisioningServiceClient( - TestConfiguration.Provisioning.ConnectionStringInvalidServiceCertificate); - Query q = provisioningServiceClient.EnrollmentGroups.CreateQuery( - "SELECT * FROM enrollmentGroups"); + // arrange + using var provisioningServiceClient = new ProvisioningServiceClient(TestConfiguration.Provisioning.ConnectionStringInvalidServiceCertificate); + Query q = provisioningServiceClient.EnrollmentGroups.CreateQuery("SELECT * FROM enrollmentGroups"); + // act Func act = async () => await q.NextAsync(); + // assert var error = await act.Should().ThrowAsync().ConfigureAwait(false); + error.And.StatusCode.Should().Be(HttpStatusCode.Unauthorized); + error.And.ErrorCode.Should().Be(0); + error.And.IsTransient.Should().BeFalse(); #if NET472 - Assert.IsInstanceOfType(error.And.InnerException.InnerException.InnerException, typeof(AuthenticationException)); + error.And.InnerException.InnerException.InnerException.Should().BeOfType(); #else - Assert.IsInstanceOfType(error.And.InnerException.InnerException, typeof(AuthenticationException)); + error.And.InnerException.InnerException.Should().BeOfType(); #endif } @@ -53,54 +58,71 @@ public async Task ProvisioningServiceClient_QueryInvalidServiceCertificateHttp_F [Timeout(TestTimeoutMilliseconds)] public async Task ProvisioningDeviceClient_RegisterAsyncInvalidServiceCertificateAmqpTcp_Fails() { + // arrange var clientOptions = new ProvisioningClientOptions(new ProvisioningClientAmqpSettings(ProvisioningClientTransportProtocol.Tcp)); - Func act = async () => await TestInvalidServiceCertificate(clientOptions); + // act + Func act = async () => await TestInvalidServiceCertificateAsync(clientOptions); + + //assert var error = await act.Should().ThrowAsync().ConfigureAwait(false); - Assert.IsInstanceOfType(error.And.InnerException, typeof(AuthenticationException)); + error.And.ErrorCode.Should().Be(0); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.Should().BeOfType(); } [TestMethod] [Timeout(TestTimeoutMilliseconds)] public async Task ProvisioningDeviceClient_RegisterAsyncInvalidServiceCertificateMqttTcp_Fails() { + // arrange var clientOptions = new ProvisioningClientOptions(new ProvisioningClientMqttSettings(ProvisioningClientTransportProtocol.Tcp)); - Func act = async () => await TestInvalidServiceCertificate(clientOptions); + // act + Func act = async () => await TestInvalidServiceCertificateAsync(clientOptions); + + // assert var error = await act.Should().ThrowAsync().ConfigureAwait(false); - if (error.And.InnerException == null) - { - Assert.AreEqual("MQTT Protocol Exception: Channel closed.", error.And.Message); - } - else - { - Assert.IsInstanceOfType(error.And.InnerException, typeof(AuthenticationException)); - } + error.And.ErrorCode.Should().Be(0); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.InnerException.Should().BeOfType(); } [TestMethod] [Timeout(TestTimeoutMilliseconds)] public async Task ProvisioningDeviceClient_RegisterAsyncInvalidServiceCertificateAmqpWs_Fails() { + // arrange var clientOptions = new ProvisioningClientOptions(new ProvisioningClientAmqpSettings(ProvisioningClientTransportProtocol.WebSocket)); - Func act = async () => await TestInvalidServiceCertificate(clientOptions); + // act + Func act = async () => await TestInvalidServiceCertificateAsync(clientOptions); + + // assert var error = await act.Should().ThrowAsync().ConfigureAwait(false); - Assert.IsInstanceOfType(error.And.InnerException.InnerException.InnerException, typeof(AuthenticationException)); + error.And.ErrorCode.Should().Be(0); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.InnerException.InnerException.Should().BeOfType(); } [TestMethod] [Timeout(TestTimeoutMilliseconds)] public async Task ProvisioningDeviceClient_RegisterAsyncInvalidServiceCertificateMqttWs_Fails() { + // arrange var clientOptions = new ProvisioningClientOptions(new ProvisioningClientMqttSettings(ProvisioningClientTransportProtocol.WebSocket)); - Func act = async () => await TestInvalidServiceCertificate(clientOptions); + // act + Func act = async () => await TestInvalidServiceCertificateAsync(clientOptions); + + // assert var error = await act.Should().ThrowAsync().ConfigureAwait(false); - Assert.IsInstanceOfType(error.And.InnerException.InnerException.InnerException, typeof(AuthenticationException)); + error.And.ErrorCode.Should().Be(0); + error.And.IsTransient.Should().BeFalse(); + error.And.InnerException.InnerException.InnerException.InnerException.Should().BeOfType(); } - private async Task TestInvalidServiceCertificate(ProvisioningClientOptions clientOptions) + private static async Task TestInvalidServiceCertificateAsync(ProvisioningClientOptions clientOptions) { // Shorten the file name to avoid overall file path become too long and cause error in the test string certificateSubject = "cert-" + Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace('+', '-').Replace('/', '.').Trim('='); diff --git a/iothub/device/src/Fx/Fx.cs b/iothub/device/src/Fx/Fx.cs index fdfae14898..c3ea5dcf24 100644 --- a/iothub/device/src/Fx/Fx.cs +++ b/iothub/device/src/Fx/Fx.cs @@ -10,7 +10,7 @@ namespace Microsoft.Azure.Devices.Client { internal static class Fx { - public static bool IsFatal(Exception ex) + internal static bool IsFatal(Exception ex) { while (ex != null) { diff --git a/iothub/device/src/IotHubClientOptions.cs b/iothub/device/src/IotHubClientOptions.cs index 2da84ff096..be41b27d07 100644 --- a/iothub/device/src/IotHubClientOptions.cs +++ b/iothub/device/src/IotHubClientOptions.cs @@ -112,6 +112,7 @@ internal IotHubClientOptions Clone() ModelId = ModelId, SdkAssignsMessageId = SdkAssignsMessageId, AdditionalUserAgentInfo = AdditionalUserAgentInfo, + RetryPolicy = RetryPolicy, }; } } diff --git a/iothub/device/src/Pipeline/ClientPipelineBuilder.cs b/iothub/device/src/Pipeline/ClientPipelineBuilder.cs index eb230edbfe..351645cb8c 100644 --- a/iothub/device/src/Pipeline/ClientPipelineBuilder.cs +++ b/iothub/device/src/Pipeline/ClientPipelineBuilder.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using Azure.Core; using Microsoft.Azure.Devices.Client.Transport; namespace Microsoft.Azure.Devices.Client diff --git a/iothub/device/src/Transport/Mqtt/MqttTransportHandler.cs b/iothub/device/src/Transport/Mqtt/MqttTransportHandler.cs index f613ff4e42..2ae6091796 100644 --- a/iothub/device/src/Transport/Mqtt/MqttTransportHandler.cs +++ b/iothub/device/src/Transport/Mqtt/MqttTransportHandler.cs @@ -310,33 +310,33 @@ public override async Task OpenAsync(CancellationToken cancellationToken) // The timer would invoke callback after every hour. _twinTimeoutTimer.Change(s_twinResponseTimeout, s_twinResponseTimeout); } - catch (MqttConnectingFailedException cfe) + catch (MqttConnectingFailedException ex) { - MqttClientConnectResultCode connectCode = cfe.ResultCode; + MqttClientConnectResultCode connectCode = ex.ResultCode; switch (connectCode) { case MqttClientConnectResultCode.BadUserNameOrPassword: case MqttClientConnectResultCode.NotAuthorized: case MqttClientConnectResultCode.ClientIdentifierNotValid: - throw new IotHubClientException("Failed to open the MQTT connection due to incorrect or unauthorized credentials", IotHubClientErrorCode.Unauthorized, cfe); + throw new IotHubClientException("Failed to open the MQTT connection due to incorrect or unauthorized credentials", IotHubClientErrorCode.Unauthorized, ex); case MqttClientConnectResultCode.UnsupportedProtocolVersion: // Should never happen since the protocol version (3.1.1) is hardcoded - throw new IotHubClientException("Failed to open the MQTT connection due to an unsupported MQTT version", cfe); + throw new IotHubClientException("Failed to open the MQTT connection due to an unsupported MQTT version", ex); case MqttClientConnectResultCode.ServerUnavailable: - throw new IotHubClientException("MQTT connection rejected because the server was unavailable", IotHubClientErrorCode.ServerBusy, cfe); + throw new IotHubClientException("MQTT connection rejected because the server was unavailable", IotHubClientErrorCode.ServerBusy, ex); default: - if (cfe.InnerException is MqttCommunicationTimedOutException) + if (ex.InnerException is MqttCommunicationTimedOutException) { if (cancellationToken.IsCancellationRequested) { // MQTTNet throws MqttCommunicationTimedOutException instead of OperationCanceledException // when the cancellation token requests cancellation. - throw new OperationCanceledException(ConnectTimedOutErrorMessage, cfe); + throw new OperationCanceledException(ConnectTimedOutErrorMessage, ex); } // This execption may be thrown even if cancellation has not been requested yet. // This case is treated as a timeout error rather than an OperationCanceledException - throw new IotHubClientException(ConnectTimedOutErrorMessage, IotHubClientErrorCode.Timeout, cfe); + throw new IotHubClientException(ConnectTimedOutErrorMessage, IotHubClientErrorCode.Timeout, ex); } // MQTT 3.1.1 only supports the above connect return codes, so this default case @@ -344,9 +344,13 @@ public override async Task OpenAsync(CancellationToken cancellationToken) // https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html // MQTT 5 supports a larger set of connect codes. See the MQTT 5.0 specification section "3.2.2.2 Connect Reason Code" // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901074 - throw new IotHubClientException("Failed to open the MQTT connection", cfe); + throw new IotHubClientException("Failed to open the MQTT connection", ex); } } + catch (MqttCommunicationTimedOutException ex) + { + throw new IotHubClientException(ConnectTimedOutErrorMessage, IotHubClientErrorCode.Timeout, ex); + } } public override async Task SendTelemetryAsync(TelemetryMessage message, CancellationToken cancellationToken) diff --git a/iothub/device/tests/IotHubDeviceClientOptionsCloneTest.cs b/iothub/device/tests/IotHubDeviceClientOptionsCloneTest.cs index 0a9ac72be3..4cb1cc3b69 100644 --- a/iothub/device/tests/IotHubDeviceClientOptionsCloneTest.cs +++ b/iothub/device/tests/IotHubDeviceClientOptionsCloneTest.cs @@ -91,5 +91,87 @@ public void IotHubClientAmqpSettings() settings.ClientWebSocket.Dispose(); } + + [TestMethod] + public void IotHubClientNoRetry() + { + // arrange + var options = new IotHubClientOptions(new IotHubClientAmqpSettings()); + + // act + var clone = options.Clone(); + + // assert + options.RetryPolicy.Should().BeOfType(); + clone.RetryPolicy.Should().BeOfType(); + + options.RetryPolicy = new IotHubClientNoRetry(); + options.RetryPolicy.Should().BeOfType(); + clone.RetryPolicy.Should().BeOfType(); + } + + [TestMethod] + public void IotHubClientIncrementalDelayRetryPolicy() + { + // arrange + var options = new IotHubClientOptions(new IotHubClientAmqpSettings()); + + // act + var clone = options.Clone(); + + // assert + options.RetryPolicy.Should().BeOfType(); + clone.RetryPolicy.Should().BeOfType(); + + options.RetryPolicy = new IotHubClientIncrementalDelayRetryPolicy(0, TimeSpan.FromSeconds(1), TimeSpan.FromMinutes(100), false); + options.RetryPolicy.Should().BeOfType(); + clone.RetryPolicy.Should().BeOfType(); + } + + [TestMethod] + public void IotHubClientFixedDelayRetryPolicy() + { + // arrange + var options = new IotHubClientOptions(new IotHubClientAmqpSettings()); + + // act + var clone = options.Clone(); + + // assert + options.RetryPolicy.Should().BeOfType(); + clone.RetryPolicy.Should().BeOfType(); + + options.RetryPolicy = new IotHubClientFixedDelayRetryPolicy(0, TimeSpan.FromSeconds(1), false); + options.RetryPolicy.Should().BeOfType(); + clone.RetryPolicy.Should().BeOfType(); + } + + [TestMethod] + public void IotHubClientCustomRetryPolicy() + { + // arrange + var options = new IotHubClientOptions(new IotHubClientAmqpSettings()); + + // act + var clone = options.Clone(); + + // assert + options.RetryPolicy.Should().BeOfType(); + clone.RetryPolicy.Should().BeOfType(); + + options.RetryPolicy = new CustomRetryPolicy(); + options.RetryPolicy.Should().BeOfType(); + clone.RetryPolicy.Should().BeOfType(); + } + + internal class CustomRetryPolicy : IIotHubClientRetryPolicy + { + public CustomRetryPolicy() { } + + public bool ShouldRetry(uint currentRetryCount, Exception lastException, out TimeSpan retryDelay) + { + throw new NotImplementedException(); + } + } } } diff --git a/iothub/service/src/Amqp/AmqpConnectionHandler.cs b/iothub/service/src/Amqp/AmqpConnectionHandler.cs index 44f78e16bc..c7ba3092ee 100644 --- a/iothub/service/src/Amqp/AmqpConnectionHandler.cs +++ b/iothub/service/src/Amqp/AmqpConnectionHandler.cs @@ -159,12 +159,20 @@ internal async Task OpenAsync(CancellationToken cancellationToken) await _cbsSession.OpenAsync(_connection, cancellationToken).ConfigureAwait(false); await _workerSession.OpenAsync(_connection, cancellationToken).ConfigureAwait(false); } + catch (AuthenticationException authException) + { + throw new IotHubServiceException(authException.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, authException); + } catch (SocketException socketException) { throw new IotHubServiceException(socketException.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, socketException); } catch (WebSocketException webSocketException) { + if (Fx.ContainsAuthenticationException(webSocketException)) + { + throw new IotHubServiceException(webSocketException.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, webSocketException); + } throw new IotHubServiceException(webSocketException.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, webSocketException); } finally @@ -206,6 +214,10 @@ internal async Task CloseAsync(CancellationToken cancellationToken) } catch (WebSocketException webSocketException) { + if (Fx.ContainsAuthenticationException(webSocketException)) + { + throw new IotHubServiceException(webSocketException.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, webSocketException); + } throw new IotHubServiceException(webSocketException.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, webSocketException); } finally diff --git a/iothub/service/src/Configurations/ConfigurationsClient.cs b/iothub/service/src/Configurations/ConfigurationsClient.cs index ce3e3bbcf5..da2882ab30 100644 --- a/iothub/service/src/Configurations/ConfigurationsClient.cs +++ b/iothub/service/src/Configurations/ConfigurationsClient.cs @@ -92,6 +92,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -149,6 +153,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -212,6 +220,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -275,6 +287,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -360,6 +376,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -424,6 +444,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) diff --git a/iothub/service/src/DigitalTwin/DigitalTwinsClient.cs b/iothub/service/src/DigitalTwin/DigitalTwinsClient.cs index ca1ad355d7..5529a10884 100644 --- a/iothub/service/src/DigitalTwin/DigitalTwinsClient.cs +++ b/iothub/service/src/DigitalTwin/DigitalTwinsClient.cs @@ -100,6 +100,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -196,6 +200,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -278,6 +286,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -363,6 +375,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) diff --git a/iothub/service/src/DirectMethod/DirectMethodsClient.cs b/iothub/service/src/DirectMethod/DirectMethodsClient.cs index f6386c1dba..1821b4f309 100644 --- a/iothub/service/src/DirectMethod/DirectMethodsClient.cs +++ b/iothub/service/src/DirectMethod/DirectMethodsClient.cs @@ -90,6 +90,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -151,6 +155,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) diff --git a/iothub/service/src/Jobs/ScheduledJobsClient.cs b/iothub/service/src/Jobs/ScheduledJobsClient.cs index d7a78231c1..019065a145 100644 --- a/iothub/service/src/Jobs/ScheduledJobsClient.cs +++ b/iothub/service/src/Jobs/ScheduledJobsClient.cs @@ -92,6 +92,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -173,6 +177,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -251,6 +259,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -337,6 +349,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) diff --git a/iothub/service/src/Messaging/MessagesClient.cs b/iothub/service/src/Messaging/MessagesClient.cs index aa4b0f028f..d3277cdae1 100644 --- a/iothub/service/src/Messaging/MessagesClient.cs +++ b/iothub/service/src/Messaging/MessagesClient.cs @@ -340,6 +340,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) diff --git a/iothub/service/src/Query/QueryClient.cs b/iothub/service/src/Query/QueryClient.cs index 9fdfe129cb..f1414be8f8 100644 --- a/iothub/service/src/Query/QueryClient.cs +++ b/iothub/service/src/Query/QueryClient.cs @@ -139,6 +139,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -220,6 +224,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) diff --git a/iothub/service/src/Registry/DevicesClient.cs b/iothub/service/src/Registry/DevicesClient.cs index 33031b651e..428653d213 100644 --- a/iothub/service/src/Registry/DevicesClient.cs +++ b/iothub/service/src/Registry/DevicesClient.cs @@ -97,6 +97,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -154,6 +158,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -218,6 +226,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -306,6 +318,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -368,6 +384,10 @@ public virtual async Task CreateWithTwinAsync(Devic } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -425,6 +445,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -474,6 +498,10 @@ public virtual async Task CreateAsync(IEnumerable SetAsync(IEnumerable DeleteAsync(IEnumerable ImportAsync(ImportJobProperties j } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -665,6 +705,10 @@ public virtual async Task ExportAsync(ExportJobProperties j } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -722,6 +766,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -774,6 +822,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -830,6 +882,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -882,6 +938,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -934,6 +994,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) diff --git a/iothub/service/src/Registry/ModulesClient.cs b/iothub/service/src/Registry/ModulesClient.cs index cfa445f010..b66fcfd460 100644 --- a/iothub/service/src/Registry/ModulesClient.cs +++ b/iothub/service/src/Registry/ModulesClient.cs @@ -89,6 +89,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -148,6 +152,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -211,6 +219,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -300,6 +312,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) diff --git a/iothub/service/src/Twin/TwinsClient.cs b/iothub/service/src/Twin/TwinsClient.cs index c09ac150ec..effe0bb695 100644 --- a/iothub/service/src/Twin/TwinsClient.cs +++ b/iothub/service/src/Twin/TwinsClient.cs @@ -99,6 +99,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -161,6 +165,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -304,6 +312,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -419,6 +431,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) @@ -475,6 +491,10 @@ await _internalRetryHandler } catch (HttpRequestException ex) { + if (Fx.ContainsAuthenticationException(ex)) + { + throw new IotHubServiceException(ex.Message, HttpStatusCode.Unauthorized, IotHubServiceErrorCode.IotHubUnauthorizedAccess, null, ex); + } throw new IotHubServiceException(ex.Message, HttpStatusCode.RequestTimeout, IotHubServiceErrorCode.Unknown, null, ex); } catch (Exception ex) diff --git a/iothub/service/src/Utilities/Fx.cs b/iothub/service/src/Utilities/Fx.cs index a0719362ae..4bb5c89411 100644 --- a/iothub/service/src/Utilities/Fx.cs +++ b/iothub/service/src/Utilities/Fx.cs @@ -5,12 +5,13 @@ using System.Collections.ObjectModel; using System.Reflection; using System.Runtime.InteropServices; +using System.Security.Authentication; -namespace Microsoft.Azure.Devices.Common +namespace Microsoft.Azure.Devices { internal static class Fx { - public static bool IsFatal(Exception ex) + internal static bool IsFatal(Exception ex) { while (ex != null) { @@ -53,5 +54,15 @@ public static bool IsFatal(Exception ex) return false; } + + internal static bool ContainsAuthenticationException(Exception ex) + { + while (ex != null) + { + return ex is AuthenticationException || ContainsAuthenticationException(ex.InnerException); + } + + return false; + } } } diff --git a/provisioning/device/src/TransportSettings/ProvisioningClientMqttSettings.cs b/provisioning/device/src/TransportSettings/ProvisioningClientMqttSettings.cs index 67b5d1a7a7..8f4272ef87 100644 --- a/provisioning/device/src/TransportSettings/ProvisioningClientMqttSettings.cs +++ b/provisioning/device/src/TransportSettings/ProvisioningClientMqttSettings.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Net.Security; namespace Microsoft.Azure.Devices.Provisioning.Client { diff --git a/provisioning/device/src/Transports/Amqp/ProvisioningTransportHandlerAmqp.cs b/provisioning/device/src/Transports/Amqp/ProvisioningTransportHandlerAmqp.cs index be3ebb79fd..506263d758 100644 --- a/provisioning/device/src/Transports/Amqp/ProvisioningTransportHandlerAmqp.cs +++ b/provisioning/device/src/Transports/Amqp/ProvisioningTransportHandlerAmqp.cs @@ -3,6 +3,8 @@ using System; using System.IO; +using System.Net.WebSockets; +using System.Security.Authentication; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -197,6 +199,18 @@ await Task.Delay( // If it was the user's cancellation token that requested cancellation, then this catch block // won't execute and the OperationCanceledException will be thrown as expected. } + catch (AuthenticationException authEx) + { + throw new ProvisioningClientException(authEx.Message, authEx, false); + } + catch (WebSocketException webEx) + { + if (ContainsAuthenticationException(webEx)) + { + throw new ProvisioningClientException(webEx.Message, webEx, false); + } + throw new ProvisioningClientException($"AMQP transport exception", webEx, true); + } catch (Exception ex) when (ex is not ProvisioningClientException) { if (Logging.IsEnabled) @@ -355,5 +369,15 @@ private void ValidateOutcome(Outcome outcome) } } } + + private static bool ContainsAuthenticationException(Exception ex) + { + while (ex != null) + { + return ex is AuthenticationException || ContainsAuthenticationException(ex.InnerException); + } + + return false; + } } } diff --git a/provisioning/device/src/Transports/Mqtt/ProvisioningTransportHandlerMqtt.cs b/provisioning/device/src/Transports/Mqtt/ProvisioningTransportHandlerMqtt.cs index 6b49f44b81..fc1fd12b81 100644 --- a/provisioning/device/src/Transports/Mqtt/ProvisioningTransportHandlerMqtt.cs +++ b/provisioning/device/src/Transports/Mqtt/ProvisioningTransportHandlerMqtt.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Linq; using System.Net; +using System.Security.Authentication; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; @@ -119,6 +120,14 @@ Task HandleDisconnectionAsync(MqttClientDisconnectedEventArgs disconnectedEventA Logging.Info(this, $"MQTT connect responded with status code '{connectResult.ResultCode}'"); mqttClient.DisconnectedAsync += HandleDisconnectionAsync; } + catch (MqttCommunicationException ex) + { + if (ContainsAuthenticationException(ex)) + { + throw new ProvisioningClientException(ex.Message, ex, false); + } + throw new ProvisioningClientException(ex.Message, ex, true); + } catch (Exception ex) when (ex is not OperationCanceledException) { throw new ProvisioningClientException("Failed to open the MQTT connection.", ex, true); @@ -465,5 +474,15 @@ private static async Task GetTaskCompletionSourceResultAsync( // Otherwise throw operation cancelled exception since the cancellation token was cancelled before the task finished. throw new OperationCanceledException(timeoutErrorMessage); } + + private static bool ContainsAuthenticationException(Exception ex) + { + while (ex != null) + { + return ex is AuthenticationException || ContainsAuthenticationException(ex.InnerException); + } + + return false; + } } } diff --git a/provisioning/service/src/Http/ContractApiHttp.cs b/provisioning/service/src/Http/ContractApiHttp.cs index cd2aa44fe5..f53f7f291b 100644 --- a/provisioning/service/src/Http/ContractApiHttp.cs +++ b/provisioning/service/src/Http/ContractApiHttp.cs @@ -9,6 +9,7 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Security.Authentication; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -170,6 +171,10 @@ await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false), } catch (HttpRequestException ex) { + if (ContainsAuthenticationException(ex)) + { + throw new ProvisioningServiceException(ex.Message, HttpStatusCode.Unauthorized, ex); + } throw new ProvisioningServiceException(ex.Message, ex, true); } catch (TaskCanceledException ex) @@ -189,6 +194,16 @@ await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false), return response; } + private static bool ContainsAuthenticationException(Exception ex) + { + while (ex != null) + { + return ex is AuthenticationException || ContainsAuthenticationException(ex.InnerException); + } + + return false; + } + private static void ValidateHttpResponse(ContractApiResponse response) { if (response.Body == null)