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

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

Open
TCROC opened this issue May 8, 2023 · 2 comments
Open

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

TCROC opened this issue May 8, 2023 · 2 comments
Labels
feature-request New feature or request

Comments

@TCROC
Copy link

TCROC commented May 8, 2023

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.

@TCROC TCROC added the feature-request New feature or request label May 8, 2023
@chkr1011
Copy link
Collaborator

chkr1011 commented May 9, 2023

You can already remove the TCP and Websocket4net combinations because it only covers Web socket connections. For TCP it will fallback to .net/mono sockets.

@TCROC
Copy link
Author

TCROC commented May 9, 2023

I updated it on the PR over here as well: #1732

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants