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

Feat/gateway #80

Merged
merged 6 commits into from
Nov 4, 2022
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
2 changes: 1 addition & 1 deletion .github/workflows/samples2docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand Down
2 changes: 1 addition & 1 deletion samples/iothub-sample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
}
},
"ConnectionStrings": {
"cs": "HostName=rido-freetier.azure-devices.net;DeviceId=device23;SharedAccessKey=MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA="
"cs": "HostName=ridofree.azure-devices.net;DeviceId=leaf02;SharedAccessKey=+icdXc8+XlxlggkOXdpaK7lacuJHOKqdwok8ClkFWFY=;GatewayHostName=localhost;CaFile=c:/certs/localhost/ca.pem"
}
}
2 changes: 1 addition & 1 deletion samples/memmon/Device.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ string RenderData()
StringBuilder sb = new();
AppendLineWithPadRight(sb, " ");
AppendLineWithPadRight(sb, $"{connectionSettings?.HostName}:{connectionSettings?.TcpPort}");
AppendLineWithPadRight(sb, $"{connectionSettings.ClientId} (Auth:{connectionSettings.Auth}/ TLS:{connectionSettings.UseTls})");
AppendLineWithPadRight(sb, $"{connectionSettings.ClientId} (Auth:{connectionSettings.Auth}/ TLS:{connectionSettings.UseTls}) GW: {connectionSettings.GatewayHostName}");
AppendLineWithPadRight(sb, " ");
AppendLineWithPadRight(sb, string.Format("{0:8} | {1:15} | {2}", "Property", "Value".PadRight(15), "Version"));
AppendLineWithPadRight(sb, string.Format("{0:8} | {1:15} | {2}", "--------", "-----".PadLeft(15, '-'), "------"));
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ public static T FromString<T>(string s) => JsonSerializer.Deserialize<T>(s,
})!;
}

#pragma warning disable CA1822 // Mark members as static
public byte[] ToBytes<T>(T payload, string name = "", int? version = null)
#pragma warning restore CA1822 // Mark members as static
{
if (string.IsNullOrEmpty(name))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public CloudToDeviceBinder(IMqttClient connection, string name, IMessageSerializ
if (resp != null)
{
byte[] responseBytes = serializer.ToBytes(resp, WrapResponse ? _name : string.Empty);
string? resTopic = responseTopicPattern?.Replace("{rid}", tp.Rid.ToString()).Replace("{version}", tp.Version.ToString());
string? resTopic = responseTopicPattern?.Replace("{rid}", tp.Rid!).Replace("{version}", tp.Version.ToString());
_ = connection.PublishAsync(
new MqttApplicationMessageBuilder()
.WithTopic(resTopic)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public class TopicParameters
{
public int Rid { get; set; }
public string? Rid { get; set; }
public int Version { get; set; }
}
8 changes: 2 additions & 6 deletions src/MQTTnet.Extensions.MultiCloud/Binders/TopicParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,15 @@ public static TopicParameters ParseTopic(string topic)
{
var segments = topic.Split('/');
int twinVersion = -1;
int rid = -1;
string rid = string.Empty;
if (topic.Contains('?'))
{
var qs = HttpUtility.ParseQueryString(segments[^1]);
if (int.TryParse(qs["$version"], out int v))
{
twinVersion = v;
}

if (int.TryParse(qs["$rid"], out int r))
{
rid = r;
}
rid = Convert.ToString(qs["$rid"])!;
}
return new TopicParameters() { Rid = rid, Version = twinVersion };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public AuthType Auth
public string? CaFile { get; set; }
public bool DisableCrl { get; set; }

public string? GatewayHostName { get; set; }

public ConnectionSettings()
{
SasMinutes = Default_SasMinutes;
Expand All @@ -50,6 +52,7 @@ public ConnectionSettings()
UseTls = Default_UseTls == "true";
DisableCrl = Default_DisableCrl == "true";
CleanSession = Default_CleanSession == "true";
GatewayHostName = string.Empty;
}

public static ConnectionSettings FromConnectionString(string cs) => new(cs);
Expand Down Expand Up @@ -98,6 +101,7 @@ private void ParseConnectionString(string cs)
UseTls = GetStringValue(map, nameof(UseTls), Default_UseTls) == "true";
CaFile = GetStringValue(map, nameof(CaFile));
DisableCrl = GetStringValue(map, nameof(DisableCrl), Default_DisableCrl) == "true";
GatewayHostName = GetStringValue(map, nameof(GatewayHostName));
}

private static void AppendIfNotEmpty(StringBuilder sb, string name, string val)
Expand Down Expand Up @@ -129,6 +133,7 @@ public override string ToString()
AppendIfNotEmpty(result, nameof(ModelId), ModelId!);
AppendIfNotEmpty(result, nameof(ClientId), ClientId!);
AppendIfNotEmpty(result, nameof(Auth), Auth!.ToString());
AppendIfNotEmpty(result, nameof(GatewayHostName), GatewayHostName!.ToString());
result.Remove(result.Length - 1, 1);
return result.ToString();
}
Expand Down
10 changes: 7 additions & 3 deletions src/MQTTnet.Extensions.MultiCloud/Connections/SasAuth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ internal static string Sign(string requestString, string key)

internal static string CreateSasToken(string resource, string sasKey, int minutes)
{

var expiry = DateTimeOffset.UtcNow.AddMinutes(minutes).ToUnixTimeSeconds().ToString();
var sig = System.Net.WebUtility.UrlEncode(Sign($"{resource}\n{expiry}", sasKey));
return $"SharedAccessSignature sr={resource}&sig={sig}&se={expiry}";
}

internal static (string username, string password) GenerateHubSasCredentials(string hostName, string deviceId, string sasKey, string modelId, int minutes = 60) =>
(GetUserName(hostName, deviceId, modelId), CreateSasToken($"{hostName}/devices/{deviceId}", sasKey, minutes));
internal static (string username, string password) GenerateHubSasCredentials(string hostName, string deviceId, string sasKey, string audience, string modelId, int minutes = 60)
{
string user = GetUserName(hostName, deviceId, modelId);
string pwd = CreateSasToken($"{audience}/devices/{deviceId}", sasKey, minutes);
return (user, pwd);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ public static partial class MqttNetExtensions
{
internal static MqttClientOptionsBuilder WithAzureIoTHubCredentials(this MqttClientOptionsBuilder builder, ConnectionSettings? cs)
{
string? hostName = cs!.HostName!;
if (!string.IsNullOrEmpty(cs.GatewayHostName))
{
hostName = cs.GatewayHostName;
}
if (cs?.Auth == AuthType.Sas)
{
if (string.IsNullOrEmpty(cs.ModuleId))
Expand All @@ -17,7 +22,8 @@ internal static MqttClientOptionsBuilder WithAzureIoTHubCredentials(this MqttCli
{
cs.ClientId = $"{cs.DeviceId}/{cs.ModuleId}";
}
return builder.WithAzureIoTHubCredentialsSas(cs.HostName!, cs.DeviceId!, cs.ModuleId!, cs.SharedAccessKey!, cs.ModelId!, cs.SasMinutes, cs.TcpPort);
builder.WithTlsSettings(cs);
return builder.WithAzureIoTHubCredentialsSas(hostName, cs.DeviceId!, cs.ModuleId!, cs.HostName!, cs.SharedAccessKey!, cs.ModelId!, cs.SasMinutes, cs.TcpPort);
}
else if (cs?.Auth == AuthType.X509)
{
Expand All @@ -34,31 +40,29 @@ internal static MqttClientOptionsBuilder WithAzureIoTHubCredentials(this MqttCli
{
cs.DeviceId = clientId;
}

return builder.WithAzureIoTHubCredentialsX509(cs.HostName!, cert, cs.ModelId!, cs.TcpPort);
builder.WithTlsSettings(cs);
return builder.WithAzureIoTHubCredentialsX509(hostName, cert, cs.ModelId!, cs.TcpPort);
}
else
{
throw new ApplicationException("Auth not supported: " + cs?.Auth);
}
}

public static MqttClientOptionsBuilder WithAzureIoTHubCredentialsSas(this MqttClientOptionsBuilder builder, string hostName, string deviceId, string moduleId, string sasKey, string modelId, int sasMinutes, int tcpPort)
public static MqttClientOptionsBuilder WithAzureIoTHubCredentialsSas(this MqttClientOptionsBuilder builder, string hostName, string deviceId, string moduleId, string audience, string sasKey, string modelId, int sasMinutes, int tcpPort)
{
if (string.IsNullOrEmpty(moduleId))
{
(string username, string password) = SasAuth.GenerateHubSasCredentials(hostName, deviceId, sasKey, modelId, sasMinutes);
(string username, string password) = SasAuth.GenerateHubSasCredentials(hostName, deviceId, sasKey, audience, modelId, sasMinutes);
builder
.WithTcpServer(hostName, tcpPort)
.WithTls()
.WithCredentials(username, password);
}
else
{
(string username, string password) = SasAuth.GenerateHubSasCredentials(hostName, $"{deviceId}/{moduleId}", sasKey, modelId, sasMinutes);
(string username, string password) = SasAuth.GenerateHubSasCredentials(hostName, $"{deviceId}/{moduleId}", sasKey, modelId, audience, sasMinutes);
builder
.WithTcpServer(hostName, tcpPort)
.WithTls()
.WithCredentials(username, password);
}
return builder;
Expand All @@ -70,13 +74,7 @@ public static MqttClientOptionsBuilder WithAzureIoTHubCredentialsX509(this MqttC

builder
.WithTcpServer(hostName, tcpPort)
.WithCredentials(new MqttClientCredentials(SasAuth.GetUserName(hostName, clientId, modelId)))
.WithTls(new MqttClientOptionsBuilderTlsParameters
{
UseTls = true,
SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
Certificates = new List<X509Certificate> { cert }
});
.WithCredentials(new MqttClientCredentials(SasAuth.GetUserName(hostName, clientId, modelId)));
return builder;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace MQTTnet.Extensions.MultiCloud.UnitTests

internal class MockMqttClient : IMqttClient
{
string _clientId = "";
readonly string _clientId = "";


#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
Expand Down