Skip to content

AWS IoT dotnet standard 2.1 and Unity Game Engine ALPN support #1731

Open
@TCROC

Description

Unity currently supports dotnet standard 2.1. Dotnet standard 2.1 added ALPN support as can be seen here: https://learn.microsoft.com/en-us/dotnet/api/system.net.security.sslapplicationprotocol?view=netstandard-2.1

Here is a Unity project demo of what should be working: https://github.com/TCROC/mqttnet-unity-alpn

And here is the README with additional details (also included in that project).

README

mqttnet-unity-alpn

NOTE:

The MQTTnet submodule in this repo is forked from the main repo. NETCOREAPP3_1_OR_GREATER define symbol has manually been set to true and CipherSuitesPolicy has been commented out. This is to demonstrate that ALPN support should be working in netstandard2.1 as seen here: https://learn.microsoft.com/en-us/dotnet/api/system.net.security.sslapplicationprotocol?view=netstandard-2.1

Currently only websockets works in both dotnet and websocket4net.

You can view the git history of the MQTTnet submodule to see the changed files.

Dependencies

Tested on Ubuntu 22.04 and Windows 10.

Windows 10 requires WSL Ubuntu 22.04 for cross compiling to ARM64 processors.

  1. Install git: https://git-scm.com/downloads
    • NOTE: Reproduced with version: git version 2.40.1
  2. Install the rust toolset: https://www.rust-lang.org/tools/install
    • NOTE: Reproduced with version: rustup 1.26.0 (5af9b9484 2023-04-05), cargo 1.69.0 (6e9a83356 2023-04-12), rustc 1.69.0 (84c898d65 2023-04-16)
  3. Install cargo lambda: https://github.com/awslabs/aws-lambda-rust-runtime
    • NOTE: Reproduced with version: cargo-lambda 0.19.0 (e7a2b99 2023-04-07Z)
  4. Install aws cli v2: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
    • NOTE: Reproduced with version: aws-cli/2.11.15 Python/3.11.3 Linux/6.2.6-76060206-generic exe/x86_64.pop.22 prompt/off
  5. Install dotnet 7.0: https://dotnet.microsoft.com/en-us/download/dotnet/7.0
    • NOTE: Reproduced with version: 7.0.203
  6. Install Unity 2021.3.24f1: https://unity.com/download
  7. Clone:
    git clone https://github.com/TCROC/mqttnet-unity-alpn.git --recurse-submodules
    

NOTE: When running the scripts, you can ignore the aws cli errors that are logged. The scripts do things such as check if the lambda function is deployed by calling aws lambda get-function . If the command errors, the script assumes it doesn't exist in the cloud and attempts to create one.

Create Lambda Authorizer

Run in a bash shell:

./create-lambda.sh

Test Lambda Authorizer

  1. Run in a bash shell:
    ./init.sh
  2. Get the iot endpoint by running the following command:
    aws iot describe-endpoint --endpoint-type iot:Data-ATS --output text
    
  3. Open the project in Unity
  4. Open the SampleScene
  5. Select the MqttClient in the Hierarchy pane
  6. Edit the Endpoint property in the Inspector pane
  7. Change between the Transport Implementation and Transport values to test different combinations
  8. Hit "Play" to test a combination
  9. Select the "console" tab to see the output

Expected results: The mqtt client sends keep alive packets for 24 hours as specified in the policy returned from the lambda function in any transport.

Actual result: The mqtt client forms a connection over TCP, but times out when attempting to authenticate.

Example test event for aws console:

NOTE: The password is testpassword base64 encoded

{
    "token": "aToken",
    "signatureVerified": false,
    "protocols": [
        "tls",
        "http",
        "mqtt"
    ],
    "protocolData": {
        "tls": {
            "serverName": "serverName"
        },
        "http": {
            "headers": {
                "#{name}": "#{value}"
            },
            "queryString": "?#{name}=#{value}"
        },
        "mqtt": {
            "username": "test",
            "password": "dGVzdHBhc3N3b3Jk",
            "clientId": "testid"
        }
    },
    "connectionMetadata": {
        "id": "UUID"
    }
}

Example result:

{
  "isAuthenticated": true,
  "principalId": "testid",
  "disconnectAfterInSeconds": 86400,
  "refreshAfterInSeconds": 86400,
  "policyDocuments": [
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "iot:Connect"
          ],
          "Condition": {
            "ArnEquals": {
              "iot:LastWillTopic": [
                "arn:aws:iot:us-east-1:144868213084:topic/open/s/${iot:ClientId}"
              ]
            }
          }
        },
        {
          "Effect": "Allow",
          "Action": [
            "iot:Receive"
          ],
          "Resource": [
            "arn:aws:iot:us-east-1:144868213084:topic/open/*"
          ],
          "Condition": {}
        },
        {
          "Effect": "Allow",
          "Action": [
            "iot:Publish"
          ],
          "Resource": [
            "arn:aws:iot:us-east-1:144868213084:topic/open/d/*/${iot:ClientId}",
            "arn:aws:iot:us-east-1:144868213084:topic/open/p/*/${iot:ClientId}",
            "arn:aws:iot:us-east-1:144868213084:topic/open/s/${iot:ClientId}"
          ],
          "Condition": {}
        },
        {
          "Effect": "Allow",
          "Action": [
            "iot:Subscribe"
          ],
          "Resource": [
            "arn:aws:iot:us-east-1:144868213084:topicfilter/open/d/${iot:ClientId}/*",
            "arn:aws:iot:us-east-1:144868213084:topicfilter/open/p/*/*",
            "arn:aws:iot:us-east-1:144868213084:topicfilter/open/s/*",
            "arn:aws:iot:us-east-1:144868213084:topicfilter/open/f/*"
          ],
          "Condition": {}
        }
      ]
    }
  ]
}

Cleanup

The lambda functions, authorizers, and certificates in aws will be deleted.

Run in a bash shell:

./clean-aws.sh

It has a forked version of MQTTnet as a submodule with ApplicationProtocols enabled. You can see the file changes here: TCROC@306952c

I simply forcefully enabled NETCOREAPP3_1_OR_GREATER define symbol in the Unity settings. I then commented out the CipherSuitesPolicy as that is not supported in netstandard 2.1.

Websockets from dotnet and websocket4net work in both my fork and the main upstream repo. TCP does not work in either. I expected it to work in my fork, but it just hangs until it times out.

Good news:

The AWS documentation can be updated to look like this:

dotnet 7:

Provider Transport Status
dotnet tcp
dotnet websocket
websocket4net websocket

Mono (specifically tested with Unity Game Engine 2021.3.24f1)

Provider Transport Status
mono tcp
mono websocket
websocket4net websocket

Now we just need to see if we can make those red X's green for TCP! :)

NOTE:

I had to remove the logs. The ones Unity generates are too long to include in this issue. They are included in the README in the linked Unity project above.

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions