Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…python-v2 into mqtt5_ga
  • Loading branch information
xiazhvera committed Dec 14, 2023
2 parents fd2cc25 + 1722914 commit 1eec185
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
- 'docs'

env:
BUILDER_VERSION: v0.9.21
BUILDER_VERSION: v0.9.53
BUILDER_SOURCE: releases
BUILDER_HOST: https://d19elf31gohf1l.cloudfront.net
PACKAGE_NAME: aws-iot-device-sdk-python-v2
Expand Down
20 changes: 14 additions & 6 deletions awsiot/mqtt5_client_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@
import awscrt.auth
import awscrt.io
import awscrt.mqtt5
import urllib.parse


DEFAULT_WEBSOCKET_MQTT_PORT = 443
DEFAULT_DIRECT_MQTT_PORT = 8883
Expand Down Expand Up @@ -629,8 +631,7 @@ def direct_with_custom_authorizer(
auth_authorizer_signature (`str`): The digital signature of the token value in the `auth_token_value`
parameter. The signature must be based on the private key associated with the custom authorizer. The
signature must be base64 encoded.
Required if the custom authorizer has signing enabled. It is strongly suggested to URL-encode this value;
the SDK will not do so for you.
Required if the custom authorizer has signing enabled.
auth_token_key_name (`str`): Key used to extract the custom authorizer token from MQTT username query-string
properties.
Expand All @@ -656,8 +657,12 @@ def direct_with_custom_authorizer(
username_string, auth_authorizer_name, "x-amz-customauthorizer-name=")

if auth_authorizer_signature is not None:
encoded_signature = auth_authorizer_signature
if "%" not in encoded_signature:
encoded_signature = urllib.parse.quote(encoded_signature)

username_string = _add_to_username_parameter(
username_string, auth_authorizer_signature, "x-amz-customauthorizer-signature=")
username_string, encoded_signature, "x-amz-customauthorizer-signature=")

if auth_token_key_name is not None and auth_token_value is not None:
username_string = _add_to_username_parameter(username_string, auth_token_value, auth_token_key_name + "=")
Expand Down Expand Up @@ -707,8 +712,7 @@ def websockets_with_custom_authorizer(
auth_authorizer_signature (`str`): The digital signature of the token value in the `auth_token_value`
parameter. The signature must be based on the private key associated with the custom authorizer. The
signature must be base64 encoded.
Required if the custom authorizer has signing enabled. It is strongly suggested to URL-encode this value;
the SDK will not do so for you.
Required if the custom authorizer has signing enabled.
auth_token_key_name (`str`): Key used to extract the custom authorizer token from MQTT username query-string
properties.
Expand Down Expand Up @@ -738,8 +742,12 @@ def websockets_with_custom_authorizer(
username_string, auth_authorizer_name, "x-amz-customauthorizer-name=")

if auth_authorizer_signature is not None:
encoded_signature = auth_authorizer_signature
if "%" not in encoded_signature:
encoded_signature = urllib.parse.quote(encoded_signature)

username_string = _add_to_username_parameter(
username_string, auth_authorizer_signature, "x-amz-customauthorizer-signature=")
username_string, encoded_signature, "x-amz-customauthorizer-signature=")

if auth_token_key_name is not None and auth_token_value is not None:
username_string = _add_to_username_parameter(username_string, auth_token_value, auth_token_key_name + "=")
Expand Down
13 changes: 8 additions & 5 deletions awsiot/mqtt_connection_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
import awscrt.auth
import awscrt.io
import awscrt.mqtt
import urllib.parse


def _check_required_kwargs(**kwargs):
Expand Down Expand Up @@ -529,8 +530,7 @@ def direct_with_custom_authorizer(
auth_authorizer_signature (`str`): The digital signature of the token value in the `auth_token_value`
parameter. The signature must be based on the private key associated with the custom authorizer. The
signature must be base64 encoded.
Required if the custom authorizer has signing enabled. It is strongly suggested to URL-encode this value;
the SDK will not do so for you.
Required if the custom authorizer has signing enabled.
auth_token_key_name (`str`): Key used to extract the custom authorizer token from MQTT username query-string
properties.
Expand Down Expand Up @@ -590,8 +590,7 @@ def websockets_with_custom_authorizer(
auth_authorizer_signature (`str`): The digital signature of the token value in the `auth_token_value`
parameter. The signature must be based on the private key associated with the custom authorizer. The
signature must be base64 encoded.
Required if the custom authorizer has signing enabled. It is strongly suggested to URL-encode this value;
the SDK will not do so for you.
Required if the custom authorizer has signing enabled.
auth_token_key_name (`str`): Key used to extract the custom authorizer token from MQTT username query-string
properties.
Expand Down Expand Up @@ -644,8 +643,12 @@ def _with_custom_authorizer(auth_username=None,
username_string, auth_authorizer_name, "x-amz-customauthorizer-name=")

if auth_authorizer_signature is not None:
encoded_signature = auth_authorizer_signature
if "%" not in encoded_signature:
encoded_signature = urllib.parse.quote(encoded_signature)

username_string = _add_to_username_parameter(
username_string, auth_authorizer_signature, "x-amz-customauthorizer-signature=")
username_string, encoded_signature, "x-amz-customauthorizer-signature=")

if auth_token_key_name is not None and auth_token_value is not None:
username_string = _add_to_username_parameter(username_string, auth_token_value, auth_token_key_name + "=")
Expand Down
41 changes: 40 additions & 1 deletion test/test_mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
CUSTOM_AUTHORIZER_NAME_UNSIGNED = os.environ.get("CUSTOM_AUTHORIZER_NAME_UNSIGNED")
CUSTOM_AUTHORIZER_PASSWORD = os.environ.get("CUSTOM_AUTHORIZER_PASSWORD")
CUSTOM_AUTHORIZER_SIGNATURE = os.environ.get("CUSTOM_AUTHORIZER_SIGNATURE")
CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED = os.environ.get("CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED")
CUSTOM_AUTHORIZER_TOKEN_KEY_NAME = os.environ.get("CUSTOM_AUTHORIZER_TOKEN_KEY_NAME")
CUSTOM_AUTHORIZER_TOKEN_VALUE = os.environ.get("CUSTOM_AUTHORIZER_TOKEN_VALUE")

Expand All @@ -27,7 +28,7 @@ def has_custom_auth_environment():
return (CUSTOM_AUTHORIZER_ENDPOINT is not None) and (CUSTOM_AUTHORIZER_NAME_SIGNED is not None) and \
(CUSTOM_AUTHORIZER_NAME_UNSIGNED is not None) and (CUSTOM_AUTHORIZER_PASSWORD is not None) and \
(CUSTOM_AUTHORIZER_SIGNATURE is not None) and (CUSTOM_AUTHORIZER_TOKEN_KEY_NAME is not None) and \
(CUSTOM_AUTHORIZER_TOKEN_VALUE is not None)
(CUSTOM_AUTHORIZER_TOKEN_VALUE is not None) and (CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED is not None)

class Config:
cache = None
Expand Down Expand Up @@ -193,6 +194,25 @@ def test_mqtt311_builder_direct_signed_custom_authorizer(self):

self._test_connection(connection)

@unittest.skipIf(not has_custom_auth_environment(), 'requires custom authentication env vars')
def test_mqtt311_builder_direct_signed_custom_authorizer_unencoded(self):
elg = EventLoopGroup()
resolver = DefaultHostResolver(elg)
bootstrap = ClientBootstrap(elg, resolver)

connection = mqtt_connection_builder.direct_with_custom_authorizer(
auth_username="",
auth_authorizer_name=CUSTOM_AUTHORIZER_NAME_SIGNED,
auth_authorizer_signature=CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED,
auth_password=CUSTOM_AUTHORIZER_PASSWORD,
auth_token_key_name=CUSTOM_AUTHORIZER_TOKEN_KEY_NAME,
auth_token_value=CUSTOM_AUTHORIZER_TOKEN_VALUE,
endpoint=CUSTOM_AUTHORIZER_ENDPOINT,
client_id=create_client_id(),
client_bootstrap=bootstrap)

self._test_connection(connection)

@unittest.skipIf(not has_custom_auth_environment(), 'requires custom authentication env vars')
def test_mqtt311_builder_direct_unsigned_custom_authorizer(self):
elg = EventLoopGroup()
Expand Down Expand Up @@ -244,3 +264,22 @@ def test_mqtt311_builder_websocket_signed_custom_authorizer(self):

self._test_connection(connection)

@unittest.skipIf(not has_custom_auth_environment(), 'requires custom authentication env vars')
def test_mqtt311_builder_websocket_signed_custom_authorizer_unencoded(self):
elg = EventLoopGroup()
resolver = DefaultHostResolver(elg)
bootstrap = ClientBootstrap(elg, resolver)

connection = mqtt_connection_builder.websockets_with_custom_authorizer(
auth_username="",
auth_authorizer_name=CUSTOM_AUTHORIZER_NAME_SIGNED,
auth_authorizer_signature=CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED,
auth_password=CUSTOM_AUTHORIZER_PASSWORD,
auth_token_key_name=CUSTOM_AUTHORIZER_TOKEN_KEY_NAME,
auth_token_value=CUSTOM_AUTHORIZER_TOKEN_VALUE,
endpoint=CUSTOM_AUTHORIZER_ENDPOINT,
client_id=create_client_id(),
client_bootstrap=bootstrap)

self._test_connection(connection)

47 changes: 46 additions & 1 deletion test/test_mqtt5.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
CUSTOM_AUTHORIZER_NAME_UNSIGNED = os.environ.get("CUSTOM_AUTHORIZER_NAME_UNSIGNED")
CUSTOM_AUTHORIZER_PASSWORD = os.environ.get("CUSTOM_AUTHORIZER_PASSWORD")
CUSTOM_AUTHORIZER_SIGNATURE = os.environ.get("CUSTOM_AUTHORIZER_SIGNATURE")
CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED = os.environ.get("CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED")
CUSTOM_AUTHORIZER_TOKEN_KEY_NAME = os.environ.get("CUSTOM_AUTHORIZER_TOKEN_KEY_NAME")
CUSTOM_AUTHORIZER_TOKEN_VALUE = os.environ.get("CUSTOM_AUTHORIZER_TOKEN_VALUE")

Expand All @@ -29,7 +30,7 @@ def has_custom_auth_environment():
return (CUSTOM_AUTHORIZER_ENDPOINT is not None) and (CUSTOM_AUTHORIZER_NAME_SIGNED is not None) and \
(CUSTOM_AUTHORIZER_NAME_UNSIGNED is not None) and (CUSTOM_AUTHORIZER_PASSWORD is not None) and \
(CUSTOM_AUTHORIZER_SIGNATURE is not None) and (CUSTOM_AUTHORIZER_TOKEN_KEY_NAME is not None) and \
(CUSTOM_AUTHORIZER_TOKEN_VALUE is not None)
(CUSTOM_AUTHORIZER_TOKEN_VALUE is not None) and (CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED is not None)

class Config:
cache = None
Expand Down Expand Up @@ -236,6 +237,28 @@ def test_mqtt5_builder_direct_signed_custom_authorizer(self):

self._test_connection(client, callbacks)

@unittest.skipIf(not has_custom_auth_environment(), 'requires custom authentication env vars')
def test_mqtt5_builder_direct_signed_custom_authorizer_unencoded(self):
elg = EventLoopGroup()
resolver = DefaultHostResolver(elg)
bootstrap = ClientBootstrap(elg, resolver)
callbacks = Mqtt5TestCallbacks()

client = mqtt5_client_builder.direct_with_custom_authorizer(
auth_username="",
auth_authorizer_name=CUSTOM_AUTHORIZER_NAME_SIGNED,
auth_authorizer_signature=CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED,
auth_password=CUSTOM_AUTHORIZER_PASSWORD,
auth_token_key_name=CUSTOM_AUTHORIZER_TOKEN_KEY_NAME,
auth_token_value=CUSTOM_AUTHORIZER_TOKEN_VALUE,
endpoint=CUSTOM_AUTHORIZER_ENDPOINT,
client_id=create_client_id(),
client_bootstrap=bootstrap,
on_lifecycle_connection_success=callbacks.on_lifecycle_connection_success,
on_lifecycle_stopped=callbacks.on_lifecycle_stopped)

self._test_connection(client, callbacks)

@unittest.skipIf(not has_custom_auth_environment(), 'requires custom authentication env vars')
def test_mqtt5_builder_direct_unsigned_custom_authorizer(self):
elg = EventLoopGroup()
Expand Down Expand Up @@ -277,6 +300,28 @@ def test_mqtt5_builder_websocket_signed_custom_authorizer(self):

self._test_connection(client, callbacks)

@unittest.skipIf(not has_custom_auth_environment(), 'requires custom authentication env vars')
def test_mqtt5_builder_websocket_signed_custom_authorizer_unencoded(self):
elg = EventLoopGroup()
resolver = DefaultHostResolver(elg)
bootstrap = ClientBootstrap(elg, resolver)
callbacks = Mqtt5TestCallbacks()

client = mqtt5_client_builder.websockets_with_custom_authorizer(
auth_username="",
auth_authorizer_name=CUSTOM_AUTHORIZER_NAME_SIGNED,
auth_authorizer_signature=CUSTOM_AUTHORIZER_SIGNATURE_UNENCODED,
auth_password=CUSTOM_AUTHORIZER_PASSWORD,
auth_token_key_name=CUSTOM_AUTHORIZER_TOKEN_KEY_NAME,
auth_token_value=CUSTOM_AUTHORIZER_TOKEN_VALUE,
endpoint=CUSTOM_AUTHORIZER_ENDPOINT,
client_id=create_client_id(),
client_bootstrap=bootstrap,
on_lifecycle_connection_success=callbacks.on_lifecycle_connection_success,
on_lifecycle_stopped=callbacks.on_lifecycle_stopped)

self._test_connection(client, callbacks)

@unittest.skipIf(not has_custom_auth_environment(), 'requires custom authentication env vars')
def test_mqtt5_builder_websocket_unsigned_custom_authorizer(self):
elg = EventLoopGroup()
Expand Down

0 comments on commit 1eec185

Please sign in to comment.