public async Task DigitalTwinClient_Http_TokenCredentialAuth_Success()
        {
            // arrange
            TestDevice testDevice = await TestDevice.GetTestDeviceAsync(Logger, _devicePrefix).ConfigureAwait(false);

            string thermostatModelId = "dtmi:com:example:TemperatureController;1";

            // Create a device client instance initializing it with the "Thermostat" model.
            var options = new ClientOptions
            {
                ModelId = thermostatModelId,
            };

            using DeviceClient deviceClient = testDevice.CreateDeviceClient(Client.TransportType.Mqtt, options);

            // Call openAsync() to open the device's connection, so that the ModelId is sent over Mqtt CONNECT packet.
            await deviceClient.OpenAsync().ConfigureAwait(false);

            using var digitalTwinClient = DigitalTwinClient.Create(
                      Configuration.IoTHub.GetIotHubHostName(),
                      Configuration.IoTHub.GetClientSecretCredential());

            // act
            HttpOperationResponse <ThermostatTwin, DigitalTwinGetHeaders> response = await digitalTwinClient
                                                                                     .GetDigitalTwinAsync <ThermostatTwin>(testDevice.Id)
                                                                                     .ConfigureAwait(false);

            ThermostatTwin twin = response.Body;

            // assert
            twin.Metadata.ModelId.Should().Be(thermostatModelId);

            // cleanup
            await testDevice.RemoveDeviceAsync().ConfigureAwait(false);
        }
Exemplo n.º 2
0
 /// <summary>
 /// Create a InternalClient using Amqp transport from the specified connection string
 /// </summary>
 /// <param name="connectionString">Connection string for the IoT hub (including DeviceId)</param>
 /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
 /// <returns>InternalClient</returns>
 internal static InternalClient CreateFromConnectionString(string connectionString, ClientOptions options = default)
 {
     return(CreateFromConnectionString(connectionString, TransportType.Amqp, options));
 }
Exemplo n.º 3
0
 /// <summary>
 /// Creates a disposable DeviceClient from the specified parameters
 /// </summary>
 /// <param name="hostname">The fully-qualified DNS hostname of IoT Hub</param>
 /// <param name="authenticationMethod">The authentication method that is used</param>
 /// <param name="transportSettings">Prioritized list of transportTypes and their settings</param>
 /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
 /// <returns>A disposable DeviceClient instance</returns>
 public static DeviceClient Create(string hostname, IAuthenticationMethod authenticationMethod,
                                   ITransportSettings[] transportSettings, ClientOptions options = default)
 {
     return(Create(() => ClientFactory.Create(hostname, authenticationMethod, transportSettings, options)));
 }
Exemplo n.º 4
0
 /// <summary>
 /// Create a disposable DeviceClient from the specified parameters
 /// </summary>
 /// <param name="hostname">The fully-qualified DNS hostname of IoT Hub</param>
 /// <param name="gatewayHostname">The fully-qualified DNS hostname of Gateway</param>
 /// <param name="authenticationMethod">The authentication method that is used</param>
 /// <param name="transportType">The transportType used (Http1, Amqp or Mqtt), <see cref="TransportType"/></param>
 /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
 /// <returns>A disposable DeviceClient instance</returns>
 public static DeviceClient Create(string hostname, string gatewayHostname, IAuthenticationMethod authenticationMethod, TransportType transportType, ClientOptions options = default)
 {
     return(Create(() => ClientFactory.Create(hostname, gatewayHostname, authenticationMethod, transportType, options)));
 }
Exemplo n.º 5
0
 /// <summary>
 /// Creates a disposable DeviceClient from the specified connection string using the prioritized list of transports
 /// </summary>
 /// <param name="connectionString">Connection string for the IoT hub (without DeviceId)</param>
 /// <param name="deviceId">Id of the device</param>
 /// <param name="transportSettings">Prioritized list of transportTypes and their settings</param>
 /// <returns>A disposable DeviceClient instance</returns>
 public static DeviceClient CreateFromConnectionString(string connectionString, string deviceId,
                                                       ITransportSettings[] transportSettings, ClientOptions options = default)
 {
     return(Create(() => ClientFactory.CreateFromConnectionString(connectionString, deviceId, transportSettings, options)));
 }
Exemplo n.º 6
0
 /// <summary>
 /// Creates a disposable DeviceClient from the specified connection string using the specified transport type
 /// </summary>
 /// <param name="connectionString">Connection string for the IoT hub (including DeviceId)</param>
 /// <param name="transportType">Specifies whether Http1, Amqp or Mqtt transport is used, <see cref="TransportType"/></param>
 /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
 /// <returns>A disposable DeviceClient instance</returns>
 public static DeviceClient CreateFromConnectionString(string connectionString, TransportType transportType, ClientOptions options = default)
 {
     return(Create(() => ClientFactory.CreateFromConnectionString(connectionString, transportType, options)));
 }
Exemplo n.º 7
0
 /// <summary>
 /// Create a InternalClient from individual parameters
 /// </summary>
 /// <param name="hostname">The fully-qualified DNS hostname of IoT Hub</param>
 /// <param name="authenticationMethod">The authentication method that is used</param>
 /// <param name="transportType">The transportType used (Http1, Amqp or Mqtt), <see cref="TransportType"/></param>
 /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
 /// <returns>InternalClient</returns>
 public static InternalClient Create(string hostname, IAuthenticationMethod authenticationMethod, TransportType transportType, ClientOptions options = default)
 {
     return(Create(hostname, null, authenticationMethod, transportType, options));
 }
Exemplo n.º 8
0
        /// <summary>
        /// Create a InternalClient from individual parameters
        /// </summary>
        /// <param name="hostname">The fully-qualified DNS hostname of IoT hub</param>
        /// <param name="gatewayHostname">The fully-qualified DNS hostname of Gateway</param>
        /// <param name="authenticationMethod">The authentication method that is used</param>
        /// <param name="transportType">The transportType used (Http1, Amqp or Mqtt), <see cref="TransportType"/></param>
        /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
        /// <returns>InternalClient</returns>
        internal static InternalClient Create(
            string hostname,
            string gatewayHostname,
            IAuthenticationMethod authenticationMethod,
            TransportType transportType,
            ClientOptions options = default)
        {
            if (hostname == null)
            {
                throw new ArgumentNullException(nameof(hostname));
            }

            if (authenticationMethod == null)
            {
                throw new ArgumentNullException(nameof(authenticationMethod));
            }

            if (transportType != TransportType.Amqp_Tcp_Only &&
                transportType != TransportType.Mqtt_Tcp_Only &&
                authenticationMethod is DeviceAuthenticationWithX509Certificate certificate &&
                certificate.ChainCertificates != null)
            {
                throw new ArgumentException("Certificate chains are only supported on Amqp_Tcp_Only and Mqtt_Tcp_Only");
            }

            if (!string.IsNullOrWhiteSpace(options?.ModelId) &&
                transportType == TransportType.Http1)
            {
                throw new InvalidOperationException("Plug and Play is not supported over the HTTP transport.");
            }

            var connectionStringBuilder = IotHubConnectionStringBuilder.Create(hostname, gatewayHostname, authenticationMethod);

            // Make sure client options is initialized with the correct transport setting.
            EnsureOptionsIsSetup(connectionStringBuilder.Certificate, ref options);

            if (authenticationMethod is DeviceAuthenticationWithX509Certificate)
            {
                if (connectionStringBuilder.Certificate == null)
                {
                    throw new ArgumentException("No certificate was found. To use certificate authentication certificate must be present.");
                }

                InternalClient internalClient = CreateFromConnectionString(
                    connectionStringBuilder.ToString(),
                    authenticationMethod,
                    PopulateCertificateInTransportSettings(connectionStringBuilder, transportType),
                    null,
                    options);

                internalClient.Certificate = connectionStringBuilder.Certificate;

                // Install all the intermediate certificates in the chain if specified.
                if (connectionStringBuilder.ChainCertificates != null)
                {
                    try
                    {
                        CertificateInstaller.EnsureChainIsInstalled(connectionStringBuilder.ChainCertificates);
                    }
                    catch (Exception ex)
                    {
                        if (Logging.IsEnabled)
                        {
                            Logging.Error(null, $"{nameof(CertificateInstaller)} failed to read or write to cert store due to: {ex}");
                        }

                        throw new UnauthorizedException($"Failed to provide certificates in the chain - {ex.Message}", ex);
                    }
                }

                return(internalClient);
            }

            return(CreateFromConnectionString(connectionStringBuilder.ToString(), authenticationMethod, transportType, null, options));
        }
Exemplo n.º 9
0
 /// <summary>
 /// Creates a ModuleClient instance in an IoT Edge deployment
 /// based on environment variables.
 /// </summary>
 /// <param name="transportType">Specifies whether Amqp or Http transport is used</param>
 /// <param name="options">The options that allow configuration of the module client instance during initialization.</param>
 /// <returns>ModuleClient instance</returns>
 public static Task <ModuleClient> CreateFromEnvironmentAsync(TransportType transportType, ClientOptions options = default)
 {
     return(CreateFromEnvironmentAsync(ClientFactory.GetTransportSettings(transportType), options));
 }
Exemplo n.º 10
0
 /// <summary>
 /// Creates a ModuleClient instance in an IoT Edge deployment
 /// based on environment variables.
 /// </summary>
 /// <param name="options">The options that allow configuration of the module client instance during initialization.</param>
 /// <returns>ModuleClient instance</returns>
 public static Task <ModuleClient> CreateFromEnvironmentAsync(ClientOptions options = default)
 {
     return(CreateFromEnvironmentAsync(TransportType.Amqp, options));
 }
Exemplo n.º 11
0
 /// <summary>
 /// Create a ModuleClient using Amqp transport from the specified connection string
 /// </summary>
 /// <param name="connectionString">Connection string for the IoT hub (including DeviceId)</param>
 /// <param name="options">The options that allow configuration of the module client instance during initialization.</param>
 /// <returns>ModuleClient</returns>
 public static ModuleClient CreateFromConnectionString(string connectionString, ClientOptions options = default)
 {
     return(Create(() => ClientFactory.CreateFromConnectionString(connectionString, options)));
 }
Exemplo n.º 12
0
        /// <summary>
        /// Create InternalClient from the specified connection string using the prioritized list of transports
        /// </summary>
        /// <param name="connectionString">Connection string for the IoT hub (without DeviceId)</param>
        /// <param name="deviceId">Id of the device</param>
        /// <param name="transportSettings">Prioritized list of transportTypes and their settings</param>
        /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
        /// <returns>InternalClient</returns>
        internal static InternalClient CreateFromConnectionString(string connectionString, string deviceId, ITransportSettings[] transportSettings, ClientOptions options = default)
        {
            if (connectionString == null)
            {
                throw new ArgumentNullException(nameof(connectionString));
            }

            if (deviceId == null)
            {
                throw new ArgumentNullException(nameof(deviceId));
            }

            if (s_deviceIdParameterRegex.IsMatch(connectionString))
            {
                throw new ArgumentException("Connection string must not contain DeviceId keyvalue parameter", nameof(connectionString));
            }

            return(CreateFromConnectionString(connectionString + ";" + DeviceId + "=" + deviceId, transportSettings, options));
        }
Exemplo n.º 13
0
 /// <summary>
 /// Create InternalClient from the specified connection string using a prioritized list of transports
 /// </summary>
 /// <param name="connectionString">Connection string for the IoT hub (with DeviceId)</param>
 /// <param name="transportSettings">Prioritized list of transports and their settings</param>
 /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
 /// <returns>InternalClient</returns>
 internal static InternalClient CreateFromConnectionString(string connectionString,
                                                           ITransportSettings[] transportSettings, ClientOptions options = default)
 {
     return(CreateFromConnectionString(connectionString, null, transportSettings, null, options));
 }
Exemplo n.º 14
0
        /// <summary>
        /// Create a InternalClient from individual parameters
        /// </summary>
        /// <param name="hostname">The fully-qualified DNS hostname of IoT Hub</param>
        /// <param name="gatewayHostname">The fully-qualified DNS hostname of Gateway</param>
        /// <param name="authenticationMethod">The authentication method that is used</param>
        /// <param name="transportType">The transportType used (Http1, Amqp or Mqtt), <see cref="TransportType"/></param>
        /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
        /// <returns>InternalClient</returns>
        public static InternalClient Create(string hostname, string gatewayHostname, IAuthenticationMethod authenticationMethod, TransportType transportType, ClientOptions options = default)
        {
            if (hostname == null)
            {
                throw new ArgumentNullException(nameof(hostname));
            }

            if (authenticationMethod == null)
            {
                throw new ArgumentNullException(nameof(authenticationMethod));
            }

            if (transportType != TransportType.Amqp_Tcp_Only &&
                transportType != TransportType.Mqtt_Tcp_Only &&
                authenticationMethod is DeviceAuthenticationWithX509Certificate &&
                ((DeviceAuthenticationWithX509Certificate)authenticationMethod).ChainCertificates != null)
            {
                throw new ArgumentException("Certificate chains are only supported on Amqp_Tcp_Only and Mqtt_Tcp_Only");
            }

            IotHubConnectionStringBuilder connectionStringBuilder = IotHubConnectionStringBuilder.Create(hostname, gatewayHostname, authenticationMethod);

            // Make sure client options is initialized with the correct transport setting.
            EnsureOptionsIsSetup(connectionStringBuilder.Certificate, ref options);

            if (authenticationMethod is DeviceAuthenticationWithX509Certificate)
            {
                if (connectionStringBuilder.Certificate == null)
                {
                    throw new ArgumentException("No certificate was found. To use certificate authentication certificate must be present.");
                }

#pragma warning disable CA2000 // This is returned to client so cannot be disposed here.
                InternalClient dc = CreateFromConnectionString(connectionStringBuilder.ToString(), PopulateCertificateInTransportSettings(connectionStringBuilder, transportType), options);
#pragma warning restore CA2000
                dc.Certificate = connectionStringBuilder.Certificate;

                // Install all the intermediate certificates in the chain if specified.
                if (connectionStringBuilder.ChainCertificates != null)
                {
                    try
                    {
                        CertificateInstaller.EnsureChainIsInstalled(connectionStringBuilder.ChainCertificates);
                    }
                    catch (Exception ex)
                    {
                        if (Logging.IsEnabled)
                        {
                            Logging.Error(null, $"{nameof(CertificateInstaller)} failed to read or write to cert store due to: {ex}");
                        }
                        throw new UnauthorizedException($"Failed to provide certificates in the chain - {ex.Message}", ex);
                    }
                }

                return(dc);
            }

            return(CreateFromConnectionString(connectionStringBuilder.ToString(), authenticationMethod, transportType, null, options));
        }
Exemplo n.º 15
0
 /// <summary>
 /// Create an Amqp InternalClient from individual parameters
 /// </summary>
 /// <param name="hostname">The fully-qualified DNS hostname of IoT hub</param>
 /// <param name="authenticationMethod">The authentication method that is used</param>
 /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
 /// <returns>InternalClient</returns>
 internal static InternalClient Create(string hostname, IAuthenticationMethod authenticationMethod, ClientOptions options = default)
 {
     return(Create(hostname, authenticationMethod, TransportType.Amqp, options));
 }
Exemplo n.º 16
0
        internal static InternalClient CreateFromConnectionString(
            string connectionString,
            IAuthenticationMethod authenticationMethod,
            ITransportSettings[] transportSettings,
            IDeviceClientPipelineBuilder pipelineBuilder,
            ClientOptions options = default)
        {
            if (connectionString == null)
            {
                throw new ArgumentNullException(nameof(connectionString));
            }

            if (transportSettings == null)
            {
                throw new ArgumentNullException(nameof(transportSettings));
            }

            if (transportSettings.Length == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(connectionString), "Must specify at least one TransportSettings instance");
            }

            if (!string.IsNullOrWhiteSpace(options?.ModelId) &&
                transportSettings.Any(x => x.GetTransportType() == TransportType.Http1))
            {
                throw new InvalidOperationException("Plug and Play is not supported over the HTTP transport.");
            }

            var builder = IotHubConnectionStringBuilder.CreateWithIAuthenticationOverride(
                connectionString,
                authenticationMethod);

            // Clients that derive their authentication method from AuthenticationWithTokenRefresh will need to specify
            // the token time to live and renewal buffer values through the corresponding AuthenticationWithTokenRefresh
            // implementation constructors instead, and these values are irrelevant for cert-based auth.
            if (!(builder.AuthenticationMethod is AuthenticationWithTokenRefresh) &&
                !(builder.AuthenticationMethod is DeviceAuthenticationWithX509Certificate))
            {
                builder.SasTokenTimeToLive    = options?.SasTokenTimeToLive ?? default;
                builder.SasTokenRenewalBuffer = options?.SasTokenRenewalBuffer ?? default;
            }

            var iotHubConnectionString = builder.ToIotHubConnectionString();

            foreach (ITransportSettings transportSetting in transportSettings)
            {
                switch (transportSetting.GetTransportType())
                {
                case TransportType.Amqp_WebSocket_Only:
                case TransportType.Amqp_Tcp_Only:
                    if (!(transportSetting is AmqpTransportSettings))
                    {
                        throw new InvalidOperationException("Unknown implementation of ITransportSettings type");
                    }
                    break;

                case TransportType.Http1:
                    if (!(transportSetting is Http1TransportSettings))
                    {
                        throw new InvalidOperationException("Unknown implementation of ITransportSettings type");
                    }
                    break;

                case TransportType.Mqtt_WebSocket_Only:
                case TransportType.Mqtt_Tcp_Only:
                    if (!(transportSetting is MqttTransportSettings))
                    {
                        throw new InvalidOperationException("Unknown implementation of ITransportSettings type");
                    }
                    break;

                default:
                    throw new InvalidOperationException(
                              $"Unsupported Transport Type {transportSetting.GetTransportType()}");
                }
            }

            if (authenticationMethod is DeviceAuthenticationWithX509Certificate &&
                builder.Certificate == null)
            {
                throw new ArgumentException("No certificate was found. To use certificate authentication certificate must be present.");
            }

            // Make sure client options is initialized with the correct transport setting.
            EnsureOptionsIsSetup(builder.Certificate, ref options);

            pipelineBuilder ??= BuildPipeline();

            // Defer concrete InternalClient creation to OpenAsync
            var client = new InternalClient(iotHubConnectionString, transportSettings, pipelineBuilder, options);

            if (Logging.IsEnabled)
            {
                Logging.CreateFromConnectionString(
                    client,
                    $"HostName={iotHubConnectionString.HostName};DeviceId={iotHubConnectionString.DeviceId};ModuleId={iotHubConnectionString.ModuleId}",
                    transportSettings,
                    options);
            }

            return(client);
        }
Exemplo n.º 17
0
 /// <summary>
 /// Creates a ModuleClient instance in an IoT Edge deployment
 /// based on environment variables.
 /// </summary>
 /// <param name="transportSettings">Prioritized list of transports and their settings</param>
 /// <param name="options">The options that allow configuration of the module client instance during initialization.</param>
 /// <returns>ModuleClient instance</returns>
 public static Task <ModuleClient> CreateFromEnvironmentAsync(ITransportSettings[] transportSettings, ClientOptions options = default)
 {
     return(new EdgeModuleClientFactory(transportSettings, new TrustBundleProvider(), options).CreateAsync());
 }
Exemplo n.º 18
0
 /// <summary>
 /// Create an Amqp ModuleClient from individual parameters
 /// </summary>
 /// <param name="hostname">The fully-qualified DNS hostname of IoT Hub</param>
 /// <param name="authenticationMethod">The authentication method that is used</param>
 /// <param name="gatewayHostname">The fully-qualified DNS hostname of Gateway</param>
 /// <param name="options">The options that allow configuration of the module client instance during initialization.</param>
 /// <returns>ModuleClient</returns>
 public static ModuleClient Create(string hostname, string gatewayHostname, IAuthenticationMethod authenticationMethod, ClientOptions options = default)
 {
     return(Create(() => ClientFactory.Create(hostname, gatewayHostname, authenticationMethod, options)));
 }
Exemplo n.º 19
0
        /// <summary>
        /// Create InternalClient from the specified connection string using the specified transport type
        /// </summary>
        /// <param name="connectionString">Connection string for the IoT hub (including DeviceId)</param>
        /// <param name="transportType">Specifies whether Http1, Amqp or Mqtt transport is used, <see cref="TransportType"/></param>
        /// <param name="options">The options that allow configuration of the device client instance during initialization.</param>
        /// <returns>InternalClient</returns>
        public static InternalClient CreateFromConnectionString(string connectionString, TransportType transportType, ClientOptions options = default)
        {
            if (string.IsNullOrEmpty(connectionString))
            {
                throw new ArgumentNullException(nameof(connectionString));
            }

            return(CreateFromConnectionString(connectionString, null, transportType, null, options));
        }