Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use gateway hostname from options for connection string flow #3326

Merged
merged 4 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions iothub/device/src/Authentication/IotHubConnectionCredentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,23 @@ internal IotHubConnectionCredentials()
/// The authentication method that is used. It includes <see cref="ClientAuthenticationWithSharedAccessKeyRefresh"/>, <see cref="ClientAuthenticationWithSharedAccessSignature"/>,
/// <see cref="ClientAuthenticationWithX509Certificate"/> or <see cref="EdgeModuleAuthenticationWithHsm"/>.
/// </param>
/// <param name="hostName">The fully-qualified DNS host name of IoT hub.</param>
/// <param name="iotHubHostName">The fully-qualified DNS host name of IoT hub.</param>
/// <param name="gatewayHostName">The fully-qualified DNS host name of the gateway (optional).</param>
/// <returns>A new instance of the <c>IotHubConnectionCredentials</c> class with a populated connection string.</returns>
/// <exception cref="ArgumentNullException"><paramref name="hostName"/>, device Id or <paramref name="authenticationMethod"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="hostName"/> or device Id are an empty string or consist only of white-space characters.</exception>
/// <exception cref="ArgumentNullException"><paramref name="iotHubHostName"/>, device Id or <paramref name="authenticationMethod"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="iotHubHostName"/> or device Id are an empty string or consist only of white-space characters.</exception>
/// <exception cref="ArgumentException"><see cref="ClientAuthenticationWithX509Certificate.CertificateChain"/> is used over a protocol other than MQTT over TCP or AMQP over TCP.</exception>
/// <exception cref="FormatException">Neither shared access key, shared access signature or X509 certificates were presented for authentication.</exception>
/// <exception cref="FormatException">Either shared access key or shared access signature where presented together with X509 certificates for authentication.</exception>
/// <exception cref="IotHubClientException"><see cref="ClientAuthenticationWithX509Certificate.CertificateChain"/> could not be installed.</exception>
public IotHubConnectionCredentials(IAuthenticationMethod authenticationMethod, string hostName, string gatewayHostName = null)
public IotHubConnectionCredentials(IAuthenticationMethod authenticationMethod, string iotHubHostName, string gatewayHostName = default)
{
Argument.AssertNotNull(authenticationMethod, nameof(authenticationMethod));
Argument.AssertNotNullOrWhiteSpace(hostName, nameof(hostName));
Argument.AssertNotNullOrWhiteSpace(iotHubHostName, nameof(iotHubHostName));

IotHubHostName = hostName;
IotHubHostName = iotHubHostName;
GatewayHostName = gatewayHostName;
HostName = gatewayHostName ?? hostName;
HostName = gatewayHostName ?? iotHubHostName;

AuthenticationMethod = authenticationMethod;
IotHubConnectionCredentials iotHubConnectionCredentials = this;
Expand All @@ -58,20 +58,21 @@ public IotHubConnectionCredentials(IAuthenticationMethod authenticationMethod, s
/// Creates an instance of this class using a connection string.
/// </summary>
/// <param name="iotHubConnectionString">The IoT hub device connection string.</param>
/// <param name="gatewayHostName">The fully-qualified DNS host name of the gateway (optional).</param>
/// <returns>A new instance of this class.</returns>
/// <exception cref="ArgumentNullException"><paramref name="iotHubConnectionString"/>, IoT hub host name or device Id is null.</exception>
/// <exception cref="ArgumentException"><paramref name="iotHubConnectionString"/>, IoT hub host name or device Id are an empty string or consist only of white-space characters.</exception>
/// <exception cref="FormatException">Neither shared access key nor shared access signature were presented for authentication.</exception>
/// <exception cref="FormatException">Either shared access key or shared access signature where presented together with X509 certificates for authentication.</exception>
public IotHubConnectionCredentials(string iotHubConnectionString)
public IotHubConnectionCredentials(string iotHubConnectionString, string gatewayHostName = default)
{
Argument.AssertNotNullOrWhiteSpace(iotHubConnectionString, nameof(iotHubConnectionString));

// We'll parse the connection string and use that to build an auth method
IotHubConnectionString parsedConnectionString = IotHubConnectionStringParser.Parse(iotHubConnectionString);
AuthenticationMethod = GetAuthenticationMethodFromConnectionString(parsedConnectionString);

PopulatePropertiesFromConnectionString(parsedConnectionString);
PopulatePropertiesFromConnectionString(parsedConnectionString, gatewayHostName);
SetAuthenticationModel();
SetTokenRefresherIfApplicable();

Expand Down Expand Up @@ -249,10 +250,10 @@ private static int UpdateHashCode(int hashCode, object field)
: hashCode * -1521134295 + field.GetHashCode();
}

private void PopulatePropertiesFromConnectionString(IotHubConnectionString iotHubConnectionString)
private void PopulatePropertiesFromConnectionString(IotHubConnectionString iotHubConnectionString, string gatewayHostName)
{
IotHubHostName = iotHubConnectionString.IotHubHostName;
GatewayHostName = iotHubConnectionString.GatewayHostName;
GatewayHostName = iotHubConnectionString.GatewayHostName ?? gatewayHostName;
HostName = GatewayHostName ?? IotHubHostName;
DeviceId = iotHubConnectionString.DeviceId;
ModuleId = iotHubConnectionString.ModuleId;
Expand Down
4 changes: 4 additions & 0 deletions iothub/device/src/IotHubClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ public IotHubClientOptions(IotHubClientTransportSettings transportSettings)
/// <para>
/// It can also be used for other, custom transparent or protocol gateways.
/// </para>
/// <para>
/// If the client uses a connection string-based authentication mechanism, and has a gateway hostname specified in the connection string
/// then the value set in options will be ignored.
/// </para>
/// </remarks>
public string GatewayHostName { get; set; }

Expand Down
2 changes: 1 addition & 1 deletion iothub/device/src/IotHubDeviceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class IotHubDeviceClient : IotHubBaseClient
/// </code>
/// </example>
public IotHubDeviceClient(string connectionString, IotHubClientOptions options = default)
: this(new IotHubConnectionCredentials(connectionString), options)
: this(new IotHubConnectionCredentials(connectionString, options?.GatewayHostName), options)
{
}

Expand Down
2 changes: 1 addition & 1 deletion iothub/device/src/IotHubModuleClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class IotHubModuleClient : IotHubBaseClient
/// </code>
/// </example>
public IotHubModuleClient(string connectionString, IotHubClientOptions options = default)
: this(new IotHubConnectionCredentials(connectionString), options, null)
: this(new IotHubConnectionCredentials(connectionString, options?.GatewayHostName), options, null)
{
}

Expand Down
39 changes: 39 additions & 0 deletions iothub/device/tests/IotHubDeviceClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ public sealed class IotHubDeviceClientTests
private const string FakeDeviceId = "fake";
private const string FakeSharedAccessKey = "dGVzdFN0cmluZzE=";
private const string FakeSharedAccessKeyName = "AllAccessKey";
private const string FakeGatewayHostNameOptions = "my-custom-gateway-options";
private const string FakeGatewayHostNameCs = "my-custom-gateway-cs";
private static readonly string s_fakeConnectionString = $"HostName={FakeHostName};SharedAccessKeyName={FakeSharedAccessKeyName};DeviceId={FakeDeviceId};SharedAccessKey={FakeSharedAccessKey}";
private static readonly string s_fakeConnectionStringWithGatewayHostName = $"GatewayHostName={FakeGatewayHostNameCs};HostName={FakeHostName};SharedAccessKeyName={FakeSharedAccessKeyName};DeviceId={FakeDeviceId};SharedAccessKey={FakeSharedAccessKey}";

private static readonly IotHubConnectionCredentials s_iotHubConnectionCredentials = new(s_fakeConnectionString);

Expand Down Expand Up @@ -1630,6 +1633,42 @@ private static void IotHubDeviceClient_InitWithNonHttpTransportAndModelId_DoesNo
act.Should().NotThrowAsync();
}

[TestMethod]
public async Task IotHubDeviceClient_CreateFromConnectionString_WithoutWithGatewayHostname_UseIotHubClientOptionsGatewayHostName()
{
// arrange
var clientOptions = new IotHubClientOptions
{
GatewayHostName = FakeGatewayHostNameOptions,
};

// act
await using var deviceClient = new IotHubDeviceClient(s_fakeConnectionString, clientOptions);

// assert
deviceClient.IotHubConnectionCredentials.IotHubHostName.Should().Be(FakeHostName);
deviceClient.IotHubConnectionCredentials.GatewayHostName.Should().Be(FakeGatewayHostNameOptions);
deviceClient.IotHubConnectionCredentials.HostName.Should().Be(FakeGatewayHostNameOptions);
}

[TestMethod]
public async Task IotHubDeviceClient_CreateFromConnectionString_WithGatewayHostname_OverrideIotHubClientOptionsGatewayHostName()
{
// arrange
var clientOptions = new IotHubClientOptions
{
GatewayHostName = FakeGatewayHostNameOptions,
};

// act
await using var deviceClient = new IotHubDeviceClient(s_fakeConnectionStringWithGatewayHostName, clientOptions);

// assert
deviceClient.IotHubConnectionCredentials.IotHubHostName.Should().Be(FakeHostName);
deviceClient.IotHubConnectionCredentials.GatewayHostName.Should().Be(FakeGatewayHostNameCs);
deviceClient.IotHubConnectionCredentials.HostName.Should().Be(FakeGatewayHostNameCs);
}

private class TestDeviceAuthenticationWithTokenRefresh : ClientAuthenticationWithTokenRefresh
{
// This authentication method relies on the default sas token time to live and renewal buffer set by the SDK.
Expand Down