Skip to content

Add Cognito connect sample #407

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

Merged
merged 2 commits into from
Feb 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ env:
CI_SAMPLES_FOLDER: "./aws-iot-device-sdk-python-v2/samples"
CI_IOT_CONTAINERS_ROLE: ${{ secrets.AWS_CI_IOT_CONTAINERS }}
CI_PUBSUB_ROLE: ${{ secrets.AWS_CI_PUBSUB_ROLE }}
CI_COGNITO_ROLE: ${{ secrets.AWS_CI_COGNITO_ROLE }}
CI_CUSTOM_AUTHORIZER_ROLE: ${{ secrets.AWS_CI_CUSTOM_AUTHORIZER_ROLE }}
CI_SHADOW_ROLE: ${{ secrets.AWS_CI_SHADOW_ROLE }}
CI_JOBS_ROLE: ${{ secrets.AWS_CI_JOBS_ROLE }}
Expand Down Expand Up @@ -244,6 +245,14 @@ jobs:
export SOFTHSM2_CONF=/tmp/softhsm2.conf
echo "directories.tokendir = /tmp/tokens" > /tmp/softhsm2.conf
python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_pkcs11_connect_cfg.json
- name: configure AWS credentials (Cognito)
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.CI_COGNITO_ROLE }}
aws-region: ${{ env.AWS_DEFAULT_REGION }}
- name: run Cognito Connect sample
run: |
python3 ${{ env.CI_UTILS_FOLDER }}/run_sample_ci.py --file ${{ env.CI_SAMPLES_CFG_FOLDER }}/ci_run_cognito_connect_cfg.json
- name: configure AWS credentials (MQTT5 samples)
uses: aws-actions/configure-aws-credentials@v1
with:
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/ci_run_cognito_connect_cfg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"language": "Python",
"sample_file": "./aws-iot-device-sdk-python-v2/samples/cognito_connect.py",
"sample_region": "us-east-1",
"sample_main_class": "",
"arguments": [
{
"name": "--endpoint",
"secret": "ci/endpoint"
},
{
"name": "--signing_region",
"data": "us-east-1"
},
{
"name": "--cognito_identity",
"secret": "ci/Cognito/identity_id"
}
]
}
50 changes: 49 additions & 1 deletion samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* [PKCS#11 Connect](#pkcs11-connect)
* [Windows Certificate Connect](#windows-certificate-connect)
* [Custom Authorizer Connect](#custom-authorizer-connect)
* [Cognito Connect](#cognito-connect)
* [Shadow](#shadow)
* [Jobs](#jobs)
* [Fleet Provisioning](#fleet-provisioning)
Expand Down Expand Up @@ -411,11 +412,58 @@ Your Thing's [Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot-
Run the sample like this:
``` sh
# For Windows: replace 'python3' with 'python'
python3 custom_authorizer_connect.py --endpoint <endpoint> --ca_file <path to root CA> --custom_auth_authorizer_name <authorizer name>
python3 custom_authorizer_connect.py --endpoint <endpoint> --custom_auth_authorizer_name <authorizer name>
```

You will need to setup your Custom Authorizer so that the lambda function returns a policy document. See [this page on the documentation](https://docs.aws.amazon.com/iot/latest/developerguide/config-custom-auth.html) for more details and example return result.

## Cognito Connect

This sample makes an MQTT websocket connection and connects through a [Cognito](https://aws.amazon.com/cognito/) identity. On startup, the device connects to the server and then disconnects. This sample is for reference on connecting using Cognito.

To run this sample, you need to have a Cognito identifier ID. You can get a Cognito identifier ID by creating a Cognito identity pool. For creating Cognito identity pools, please see the following page on the AWS documentation: [Tutorial: Creating an identity pool](https://docs.aws.amazon.com/cognito/latest/developerguide/tutorial-create-identity-pool.html)

**Note:** This sample assumes using an identity pool with unauthenticated identity access for the sake of convenience. Please follow best practices in a real world application based on the needs of your application and the intended use case.

Once you have a Cognito identity pool, you can run the following CLI command to get the Cognito identity pool ID:
```sh
aws cognito-identity get-id --identity-pool-id <cognito identity pool id>
# result from above command
{
"IdentityId": "<cognito identity ID>"
}
```

You can then use the returned ID in the `IdentityId` result as the input for the `--cognito_identity` argument. Please note that the Cognito identity pool ID is **not** the same as a Cognito identity ID and the sample will not work if you pass a Cognito pool id.

Your IoT Thing's [Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot-policies.html) must provide privileges for this sample to connect. Make sure your policy allows a client ID of `test-*` to connect or use `--client_id <client ID here>` to send the client ID your policy supports.

<details>
<summary>(see sample policy)</summary>
<pre>
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Connect"
],
"Resource": [
"arn:aws:iot:<b>region</b>:<b>account</b>:client/test-*"
]
}
]
}
</pre>
</details>

Run the sample like this:
``` sh
# For Windows: replace 'python3' with 'python'
python3 cognito_connect.py --endpoint <endpoint> --signing_region <signing region> --cognito_identity <cognito identity ID>
```

## Shadow

This sample uses the AWS IoT
Expand Down
66 changes: 66 additions & 0 deletions samples/cognito_connect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0.

from uuid import uuid4

# This sample shows how to create a MQTT connection using Cognito.
# This sample is intended to be used as a reference for making MQTT connections.

# Parse arguments
import command_line_utils
cmdUtils = command_line_utils.CommandLineUtils("Cognito Connect - Make a Cognito MQTT connection.")
cmdUtils.add_common_mqtt_commands()
cmdUtils.add_common_proxy_commands()
cmdUtils.add_common_logging_commands()
cmdUtils.register_command("signing_region", "<str>",
"The signing region used for the websocket signer",
True, str)
cmdUtils.register_command("client_id", "<str>",
"Client ID to use for MQTT connection (optional, default='test-*').",
default="test-" + str(uuid4()))
cmdUtils.register_command("cognito_identity", "<str>",
"The Cognito identity ID to use to connect via Cognito",
True, str)
cmdUtils.register_command("is_ci", "<str>", "If present the sample will run in CI mode (optional, default='None')")
# Needs to be called so the command utils parse the commands
cmdUtils.get_args()
is_ci = cmdUtils.get_command("is_ci", None) is not None

# Callback when connection is accidentally lost.
def on_connection_interrupted(connection, error, **kwargs):
print("Connection interrupted. error: {}".format(error))

# Callback when an interrupted connection is re-established.
def on_connection_resumed(connection, return_code, session_present, **kwargs):
print("Connection resumed. return_code: {} session_present: {}".format(return_code, session_present))


if __name__ == '__main__':
# Create a connection using Cognito.
# Note: The data for the connection is gotten from cmdUtils.
# (see build_cognito_mqtt_connection for implementation)
#
# Note: This sample and code assumes that you are using a Cognito identity
# in the same region as you pass to "--signing_region".
# If not, you may need to adjust the Cognito endpoint in the cmdUtils.
# See https://docs.aws.amazon.com/general/latest/gr/cognito_identity.html
# for all Cognito endpoints.
mqtt_connection = cmdUtils.build_cognito_mqtt_connection(on_connection_interrupted, on_connection_resumed)

if not is_ci:
print("Connecting to {} with client ID '{}'...".format(
cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id")))
else:
print("Connecting to endpoint with client ID...")

connect_future = mqtt_connection.connect()

# Future.result() waits until a result is available
connect_future.result()
print("Connected!")

# Disconnect
print("Disconnecting...")
disconnect_future = mqtt_connection.disconnect()
disconnect_future.result()
print("Disconnected!")
23 changes: 23 additions & 0 deletions samples/command_line_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,28 @@ def build_websocket_mqtt_connection(self, on_connection_interrupted, on_connecti
keep_alive_secs=30)
return mqtt_connection

def build_cognito_mqtt_connection(self, on_connection_interrupted, on_connection_resumed):
proxy_options = self.get_proxy_options_for_mqtt_connection()

cognito_endpoint = "cognito-identity." + self.get_command_required(self.m_cmd_signing_region) + ".amazonaws.com"
credentials_provider = auth.AwsCredentialsProvider.new_cognito(
endpoint=cognito_endpoint,
identity=self.get_command_required(self.m_cmd_cognito_identity),
tls_ctx=io.ClientTlsContext(io.TlsContextOptions()))

mqtt_connection = mqtt_connection_builder.websockets_with_default_aws_signing(
endpoint=self.get_command_required(self.m_cmd_endpoint),
region=self.get_command_required(self.m_cmd_signing_region),
credentials_provider=credentials_provider,
http_proxy_options=proxy_options,
ca_filepath=self.get_command(self.m_cmd_ca_file),
on_connection_interrupted=on_connection_interrupted,
on_connection_resumed=on_connection_resumed,
client_id=self.get_command_required("client_id"),
clean_session=False,
keep_alive_secs=30)
return mqtt_connection

def build_direct_mqtt_connection(self, on_connection_interrupted, on_connection_resumed):
proxy_options = self.get_proxy_options_for_mqtt_connection()
mqtt_connection = mqtt_connection_builder.mtls_from_path(
Expand Down Expand Up @@ -378,3 +400,4 @@ def build_mqtt5_client(self,
m_cmd_custom_auth_authorizer_name = "custom_auth_authorizer_name"
m_cmd_custom_auth_authorizer_signature = "custom_auth_authorizer_signature"
m_cmd_custom_auth_password = "custom_auth_password"
m_cmd_cognito_identity = "cognito_identity"