diff --git a/.builder/actions/build_samples.py b/.builder/actions/build_samples.py index 419eebd65..01e8baf14 100644 --- a/.builder/actions/build_samples.py +++ b/.builder/actions/build_samples.py @@ -20,6 +20,7 @@ def run(self, env): 'samples/mqtt/websocket_connect', 'samples/mqtt/x509_credentials_provider_connect', 'samples/mqtt/windows_cert_connect', + 'samples/mqtt/custom_authorizer_connect', 'samples/shadow/shadow_sync', 'samples/greengrass/basic_discovery', 'samples/identity/fleet_provisioning', @@ -52,7 +53,7 @@ def run(self, env): steps.append(['cmake', '--build', build_path, '--config', 'RelWithDebInfo']) - + for sample_path in da_samples: build_path = os.path.join('build', sample_path) steps.append(['cmake', diff --git a/codebuild/samples/connect-custom-authorizer-linux.sh b/codebuild/samples/connect-custom-authorizer-linux.sh new file mode 100755 index 000000000..d1c81c0b8 --- /dev/null +++ b/codebuild/samples/connect-custom-authorizer-linux.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +set -e + +env + +pushd $CODEBUILD_SRC_DIR/samples/mqtt/custom_authorizer_connect + +mkdir _build +cd _build +cmake -DCMAKE_PREFIX_PATH=/tmp/install .. +make -j + +ENDPOINT=$(aws secretsmanager get-secret-value --secret-id "unit-test/endpoint" --query "SecretString" | cut -f2 -d":" | sed -e 's/[\\\"\}]//g') +AUTH_NAME=$(aws secretsmanager get-secret-value --secret-id "unit-test/authorizer-name" --query "SecretString" | cut -f2 -d":" | sed -e 's/[\\\"\}]//g') +AUTH_PASSWORD=$(aws secretsmanager get-secret-value --secret-id "unit-test/authorizer-password" --query "SecretString" | cut -f2 -d":" | sed -e 's/[\\\"\}]//g') + +echo "Custom authorizer connect test" +./custom-authorizer-connect --endpoint $ENDPOINT --custom_auth_authorizer_name $AUTH_NAME --custom_auth_password $AUTH_PASSWORD + +popd diff --git a/codebuild/samples/linux-smoke-tests.yml b/codebuild/samples/linux-smoke-tests.yml index ac8ecb731..6a8fe3a67 100644 --- a/codebuild/samples/linux-smoke-tests.yml +++ b/codebuild/samples/linux-smoke-tests.yml @@ -19,6 +19,7 @@ phases: - $CODEBUILD_SRC_DIR/codebuild/samples/connect-websocket-linux.sh - $CODEBUILD_SRC_DIR/codebuild/samples/pkcs11-connect-linux.sh - $CODEBUILD_SRC_DIR/codebuild/samples/securetunnel-linux.sh + - $CODEBUILD_SRC_DIR/codebuild/samples/connect-custom-authorizer-linux.sh post_build: commands: - echo Build completed on `date` diff --git a/crt/aws-crt-cpp b/crt/aws-crt-cpp index 93d85d532..630aedb47 160000 --- a/crt/aws-crt-cpp +++ b/crt/aws-crt-cpp @@ -1 +1 @@ -Subproject commit 93d85d5329be1edff43da0a974d6e890c1e84ae0 +Subproject commit 630aedb47ff8892f8985c6c23aadc57c406e9941 diff --git a/samples/README.md b/samples/README.md index 604c9254a..c2e4a2c25 100644 --- a/samples/README.md +++ b/samples/README.md @@ -7,6 +7,7 @@ * [Raw Connect](#raw-connect) * [x509 Credentials Provider Connect](#x509-credentials-provider-connect) * [Windows Certificate MQTT Connect](#windows-certificate-mqtt-connect) +* [Custom Authorizer Connect](#custom-authorizer-connect) * [Fleet provisioning](#fleet-provisioning) * [Shadow](#shadow) * [Jobs](#jobs) @@ -387,6 +388,41 @@ Your Thing's [Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot- +## Custom Authorizer Connect + +This sample makes an MQTT connection and connects through a [Custom Authorizer](https://docs.aws.amazon.com/iot/latest/developerguide/custom-authentication.html). On startup, the device connects to the server and then disconnects. This sample is for reference on connecting using a custom authorizer. + +Your Thing's [Policy](https://docs.aws.amazon.com/iot/latest/developerguide/iot-policies.html) must provide privileges for this sample to connect. + +
+(see sample policy) +
+{
+  "Version": "2012-10-17",
+  "Statement": [
+    {
+      "Effect": "Allow",
+      "Action": [
+        "iot:Connect"
+      ],
+      "Resource": [
+        "arn:aws:iot:region:account:client/test-*"
+      ]
+    }
+  ]
+}
+
+
+ +To run the Custom Authorizer Connect sample use the following command: + +``` sh +./custom-authorizer-connect --endpoint --ca_file --custom_auth_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. + + ## Shadow This sample uses the AWS IoT diff --git a/samples/mqtt/custom_authorizer_connect/CMakeLists.txt b/samples/mqtt/custom_authorizer_connect/CMakeLists.txt new file mode 100644 index 000000000..4a758056b --- /dev/null +++ b/samples/mqtt/custom_authorizer_connect/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.1) +# note: cxx-17 requires cmake 3.8, cxx-20 requires cmake 3.12 +project(custom-authorizer-connect CXX) + +file(GLOB SRC_FILES + "*.cpp" + "../../utils/CommandLineUtils.cpp" + "../../utils/CommandLineUtils.h" +) + +add_executable(${PROJECT_NAME} ${SRC_FILES}) + +set_target_properties(${PROJECT_NAME} PROPERTIES + CXX_STANDARD 14) + +#set warnings +if (MSVC) + target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX /wd4068) +else () + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror) +endif () + +find_package(aws-crt-cpp REQUIRED) + +target_link_libraries(${PROJECT_NAME} AWS::aws-crt-cpp) diff --git a/samples/mqtt/custom_authorizer_connect/main.cpp b/samples/mqtt/custom_authorizer_connect/main.cpp new file mode 100644 index 000000000..f6b9e8214 --- /dev/null +++ b/samples/mqtt/custom_authorizer_connect/main.cpp @@ -0,0 +1,44 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ +#include +#include + +#include "../../utils/CommandLineUtils.h" + +using namespace Aws::Crt; + +int main(int argc, char *argv[]) +{ + + /************************ Setup the Lib ****************************/ + /* + * Do the global initialization for the API. + */ + ApiHandle apiHandle; + + /*********************** Parse Arguments ***************************/ + Utils::CommandLineUtils cmdUtils = Utils::CommandLineUtils(); + cmdUtils.RegisterProgramName("custom_authorizer_connect"); + cmdUtils.AddCommonMQTTCommands(); + cmdUtils.AddCommonCustomAuthorizerCommands(); + cmdUtils.RegisterCommand("client_id", "", "Client id to use (optional, default='test-*')"); + const char **const_argv = (const char **)argv; + cmdUtils.SendArguments(const_argv, const_argv + argc); + + // Make a MQTT client and create a connection through a custom authorizer + // Note: The data for the connection is gotten from cmdUtils + // (see BuildDirectMQTTConnectionWithCustomAuthorizer for implementation) + Aws::Iot::MqttClient client = Aws::Iot::MqttClient(); + std::shared_ptr connection = + cmdUtils.BuildDirectMQTTConnectionWithCustomAuthorizer(&client); + + // Get the client ID to send with the connection + String clientId = cmdUtils.GetCommandOrDefault("client_id", String("test-") + Aws::Crt::UUID().ToString()); + + // Connect and then disconnect using the connection we created + // (see SampleConnectAndDisconnect for implementation) + cmdUtils.SampleConnectAndDisconnect(connection, clientId); + return 0; +} diff --git a/samples/utils/CommandLineUtils.cpp b/samples/utils/CommandLineUtils.cpp index 0e2d42784..3c3a1262b 100644 --- a/samples/utils/CommandLineUtils.cpp +++ b/samples/utils/CommandLineUtils.cpp @@ -177,6 +177,27 @@ namespace Utils RegisterCommand(m_cmd_topic, "", "Topic to publish, subscribe to. (optional, default='test/topic')"); } + void CommandLineUtils::AddCommonCustomAuthorizerCommands() + { + RegisterCommand( + m_cmd_custom_auth_username, + "", + "The name to send when connecting through the custom authorizer (optional)"); + RegisterCommand( + m_cmd_custom_auth_authorizer_name, + "", + "The name of the custom authorizer to connect to (optional but required for everything but custom " + "domains)"); + RegisterCommand( + m_cmd_custom_auth_authorizer_signature, + "", + "The signature to send when connecting through a custom authorizer (optional)"); + RegisterCommand( + m_cmd_custom_auth_password, + "", + "The password to send when connecting through a custom authorizer (optional)"); + } + std::shared_ptr CommandLineUtils::BuildPKCS11MQTTConnection( Aws::Iot::MqttClient *client) { @@ -392,6 +413,24 @@ namespace Utils return GetClientConnectionForMQTTConnection(client, &clientConfigBuilder); } + std::shared_ptr CommandLineUtils::BuildDirectMQTTConnectionWithCustomAuthorizer( + Aws::Iot::MqttClient *client) + { + Aws::Crt::String auth_username = GetCommandOrDefault(m_cmd_custom_auth_username, ""); + Aws::Crt::String auth_authorizer_name = GetCommandOrDefault(m_cmd_custom_auth_authorizer_name, ""); + Aws::Crt::String auth_authorizer_signature = GetCommandOrDefault(m_cmd_custom_auth_authorizer_signature, ""); + Aws::Crt::String auth_password = GetCommandOrDefault(m_cmd_custom_auth_password, ""); + + Aws::Crt::String endpoint = GetCommandRequired(m_cmd_endpoint); + + auto clientConfigBuilder = Aws::Iot::MqttClientConnectionConfigBuilder::NewDefaultBuilder(); + clientConfigBuilder.WithEndpoint(endpoint); + clientConfigBuilder.WithCustomAuthorizer( + auth_username, auth_authorizer_name, auth_authorizer_signature, auth_password); + + return GetClientConnectionForMQTTConnection(client, &clientConfigBuilder); + } + std::shared_ptr CommandLineUtils::BuildMQTTConnection() { if (!m_internal_client) @@ -422,6 +461,10 @@ namespace Utils return BuildWebsocketMQTTConnection(&m_internal_client); } } + else if (HasCommand(m_cmd_custom_auth_authorizer_name)) + { + return BuildDirectMQTTConnectionWithCustomAuthorizer(&m_internal_client); + } else { return BuildDirectMQTTConnection(&m_internal_client); diff --git a/samples/utils/CommandLineUtils.h b/samples/utils/CommandLineUtils.h index b6b5aee04..d13766b27 100644 --- a/samples/utils/CommandLineUtils.h +++ b/samples/utils/CommandLineUtils.h @@ -153,6 +153,12 @@ namespace Utils */ void AddCommonTopicMessageCommands(); + /** + * A helper function taht adds custom_auth_username, custom_auth_authorizer_name, + * custom_auth_authorizer_signature and custom_auth_password commands + */ + void AddCommonCustomAuthorizerCommands(); + /** * A helper function that builds and returns a PKCS11 direct MQTT connection. * @@ -193,6 +199,18 @@ namespace Utils */ std::shared_ptr BuildDirectMQTTConnection(Aws::Iot::MqttClient *client); + /** + * A helper function that builds and returns a direct MQTT connection that will connect through a + * CustomAuthorizer. + * @param client The client to use to make the connection + * + * Will get the required data from the CommandLineUtils from arguments defined in the + * AddCommonCustomAuthorizerCommands. See mqtt/custom_authorizer_connect for example. + * @return The created direct MQTT connection + */ + std::shared_ptr BuildDirectMQTTConnectionWithCustomAuthorizer( + Aws::Iot::MqttClient *client); + /** * A helper function that builds and returns a MQTT connection automatically based * on the commands passed into CommandLineUtils. Will make a direct MQTT connection, PKCS11 MQTT connection, @@ -247,5 +265,9 @@ namespace Utils const Aws::Crt::String m_cmd_topic = "topic"; const Aws::Crt::String m_cmd_port_override = "port_override"; const Aws::Crt::String m_cmd_help = "help"; + const Aws::Crt::String m_cmd_custom_auth_username = "custom_auth_username"; + const Aws::Crt::String m_cmd_custom_auth_authorizer_name = "custom_auth_authorizer_name"; + const Aws::Crt::String m_cmd_custom_auth_authorizer_signature = "custom_auth_authorizer_signature"; + const Aws::Crt::String m_cmd_custom_auth_password = "custom_auth_password"; }; } // namespace Utils