Closed leozzmc closed 8 months ago
Hi @leozzmc, I don't have experience with custom authentication demo so probably it will take some time to solve the problem with you. At the same time, I will also consult experienced member.
This first problem I saw from your log is that openSSL is not able to receive data. The reason is when CLIENT_USERNAME is defined, client cert and private key setup will be skipped in the demo. Client cert and private key are still required to connect to AWS IoT core. https://github.com/aws/aws-iot-device-sdk-embedded-C/blob/af6b6efc09d98dea8dadc3db1e2992b593abb104/demos/mqtt/mqtt_demo_mutual_auth/mqtt_demo_mutual_auth.c#L629-L632
Can you give the following fix a try and feedback the result?
// #ifndef CLIENT_USERNAME remove the preprocessor condition
opensslCredentials.pClientCertPath = CLIENT_CERT_PATH;
opensslCredentials.pPrivateKeyPath = CLIENT_PRIVATE_KEY_PATH;
// #endif
hi
I meet the same issue and same error msgs can't be resolved now.
And besides ,I configured demo-config.h ,I configure lambda function in my iot console also ,but it does't work yet, I can't figure the reasons out.
I want to use USERNAME/PASSWORD to log in mqtt server,so CLIENT_CERT_PATH and CLIENT_PRIVATE_KEY_PATH will not provide in my device.
@zhengasif Thank you for your feedback. We will look into this problem and reply in this thread again.
@zhengasif I am able to run the mqtt_demo_mutual_auth with custom authentication. Sorry for my previous post. The client cert and private key are not required for custom authentication.
The are couple of things we can check first:
After we create the lambda function and the authorizer, we can check the result with test-invoke-authorizer
aws iot test-invoke-authorizer --authorizer-name NAME_OF_AUTHORIZER ...
The json returned by the lambda function should be printed out in your console.
Ensure the json contains the required attribute and the policy document in json has the permission for the demo. iot:Connect
, iot:Publish
, iot:Subscribe
and iot:Receive
actions are required for this demo.
Configure the demo with the following in demo_config.h and run the demo.
#define AWS_IOT_ENDPOINT "YourAWSIoTEndpoint"
#define AWS_MQTT_PORT ( 443 )
#define CLIENT_USERNAME "The client username"
#define CLIENT_PASSWORD "The password"
Now you should be able to connect/subscribe/publish/receive to the AWS IoT Core with the demo.
More detail information can be found in Creating and managing custom authorizers document to run this demo with custom authentication.
Please feedback which steps you are having problem.
@leozzmc
It looks like you are able to invoke authorizer. Please check the followings and feedback more information:
iot:Connect
, iot:Publish
, iot:Subscribe
and iot:Receive
actions are required for this demo.Hi @chinglee-iot ,
I can pass the username/password authentication by using 3rd party mqtt client - MQTTX. I only specify
Then there are invocations in the Lambda log and AWS IoT Core metrics.
The message can also received by AWS IoT Core.
However, with the mqtt-demo-mutual-auth
file in the EC2, the connection still failed.
Here's the Lambda code
// A simple Lambda function for an authorizer. It demonstrates
// How to parse a CLI and Http password to generate a response.
exports.handler = async (event, context, callback) => {
//Http parameter to initiate allow/deny request
const HTTP_PARAM_NAME='actionToken';
const ALLOW_ACTION = 'Allow';
const DENY_ACTION = 'Deny';
//Event data passed to Lambda function
var event_str = JSON.stringify(event);
console.log('Complete event :'+ event_str);
//Read protocolData from the event json passed to Lambda function
var protocolData = event.protocolData;
console.log('protocolData value---> ' + protocolData);
//Get the dynamic account ID from function's ARN to be used
// as full resource for IAM policy
var ACCOUNT_ID = context.invokedFunctionArn.split(":")[4];
console.log("ACCOUNT_ID---"+ACCOUNT_ID);
//Get the dynamic region from function's ARN to be used
// as full resource for IAM policy
var REGION = context.invokedFunctionArn.split(":")[3];
console.log("REGION---"+REGION);
//protocolData data will be undefined if testing is done via CLI.
// This will help to test the set up.
if (protocolData === undefined) {
//If CLI testing, pass deny action as this is for testing purpose only.
console.log('Using the test-invoke-authorizer cli for testing only');
callback(null, generateAuthResponse(DENY_ACTION,ACCOUNT_ID,REGION));
} else{
var uname = event.protocolData.mqtt.username;
var pwd = event.protocolData.mqtt.password;
var buff = new Buffer(pwd, 'base64');
var passwd = buff.toString('ascii');
console.log("pwd: " +pwd);
switch (passwd) {
case 'test':
console.log("password: "+passwd);
callback(null, generateAuthResponse(ALLOW_ACTION, ACCOUNT_ID, REGION));
default:
console.log("password: "+passwd);
callback(null, generateAuthResponse(DENY_ACTION,ACCOUNT_ID,REGION));
}
}
};
// Helper function to generate the authorization IAM response.
var generateAuthResponse = function(effect,ACCOUNT_ID,REGION) {
var full_resource = "arn:aws:iot:"+ REGION + ":" + ACCOUNT_ID + ":*";
console.log("full_resource---"+full_resource);
var authResponse = {};
authResponse.isAuthenticated = true;
authResponse.principalId = 'principalId';
var policyDocument = {};
policyDocument.Version = '2012-10-17';
policyDocument.Statement = [];
var conncectstatement = {};
var subscribestatement = {};
var publishstatement = {};
var receivestatement = {};
//connect
conncectstatement.Action = 'iot:Connect';
conncectstatement.Effect = effect;
conncectstatement.Resource = full_resource;
//Subscribe
subscribestatement.Action = 'iot:Subscribe';
subscribestatement.Effect = effect;
subscribestatement.Resource = full_resource;
// Publish
publishstatement.Action = 'iot:Publish';
publishstatement.Effect = effect;
publishstatement.Resource = full_resource;
//Receive
receivestatement.Action = 'iot:Receive';
receivestatement.Effect = effect;
receivestatement.Resource = full_resource;
policyDocument.Statement[0] = conncectstatement;
policyDocument.Statement[1] = subscribestatement;
policyDocument.Statement[2] = publishstatement;
policyDocument.Statement[3] = receivestatement;
authResponse.policyDocuments = [policyDocument];
authResponse.disconnectAfterInSeconds = 3600;
authResponse.refreshAfterInSeconds = 600;
console.log('custom auth policy function called from http');
console.log('authResponse --> ' + JSON.stringify(authResponse));
console.log(authResponse.policyDocuments[0]);
return authResponse;
}
After executing these command, the policy document will returned, and this can also confirm by checking the Lambda log streams.
aws iot test-invoke-authorizer --authorizer-name TestAuth2 \
--mqtt-context '{"username":"kevin", "password": "dGVzdA==", "clientId":"testclient"}'
policy document
The point is, the same Lambda code and the same configuration in both MQTTX and demo-config.h
.
Why the script still failed with connection problems?
And I confirm that the EC2 that I use is in public subnet. It seems that the policy Lambda return may give my mqtt client enough permission to publish and receive mqtt messages.
@leozzmc
Can you help to check the followings in cloudwatch and feedback the result?
{
"timestamp": "2023-10-13 18:00:57.244",
"logLevel": "ERROR",
"traceId": "6475c73d-d3be-7d1a-b447-843c46917d88",
"accountId": "......",
"status": "Failure",
"eventType": "Connect",
"protocol": "MQTT",
"clientId": "testclient",
"principalId": "xxxxxxxx",
"sourceIp": ".....",
"sourcePort": 27487,
"reason": "AUTHORIZATION_FAILURE",
"details": "Authorization Failure"
}
I am able to run your lambda function with invalid password. The following is the cloudwatch log. I didn't try valid password with base64 encoding. I have not problem connect to the IoT core if I update your lambda to allow any password.
2023-10-16T10:51:20.841Z ..... INFO authResponse -->
{
"isAuthenticated": true,
"principalId": "principalId",
"policyDocuments": [
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "iot:Connect",
"Effect": "Deny",
"Resource": "arn:aws:iot:us-west-2:....:*"
},
{
"Action": "iot:Subscribe",
"Effect": "Deny",
"Resource": "arn:aws:iot:us-west-2:.....:*"
},
{
"Action": "iot:Publish",
"Effect": "Deny",
"Resource": "arn:aws:iot:us-west-2:.....:*"
},
{
"Action": "iot:Receive",
"Effect": "Deny",
"Resource": "arn:aws:iot:us-west-2:....:*"
}
]
}
],
"disconnectAfterInSeconds": 3600,
"refreshAfterInSeconds": 600
}
@leozzmc In my test, I use the default authorizer with set-default-authorizer.
We are also trying to set the custom authorizer in username and will reply the test result in this thread later.
#define CLIENT_USERNAME "Test?x-amz-customauthorizer-name=TestAuth2"
( edited for typo )
@leozzmc In the demo, the metrics parameter is already appended to the CLIENT_USERNAME_WITH_METRICS.
#define METRICS_STRING "?SDK=" OS_NAME "&Version=" OS_VERSION "&Platform=" HARDWARE_PLATFORM_NAME "&MQTTLib=" MQTT_LIB
#define CLIENT_USERNAME_WITH_METRICS CLIENT_USERNAME METRICS_STRING
Therefore, adding extra parameters in CLIENT_USERNAME would result in invalid format.
For example, with previous example
#define CLIENT_USERNAME "Test?x-amz-customauthorizer-name=TestAuth2"
The resulting string will have two question marks, which is invalid format.
Test?x-amz-customauthorizer-name=TestAuth2?SDK=" OS_NAME "&Version=" OS_VERSION "&Platform=" HARDWARE_PLATFORM_NAME "&MQTTLib=" MQTT_LIB
^ The extra question mark
We will bring back this problem for discussion and come out a solution to allow user to append parameters in CLIENT_USERNAME. To unblock your development, you may use default authorizer or update the METRICS_STRING
with the following code as a temporary workaround.
#define METRICS_STRING "&SDK=" OS_NAME "&Version=" OS_VERSION "&Platform=" HARDWARE_PLATFORM_NAME "&MQTTLib=" MQTT_LIB
^ Replace '?' with '&'
The PR #1893 to fix this issue is merged. We will close this issue. Thank you for creating this issue and feel free to reopen it if any new observation.
Hi experts!
I try to follow the AWS tutorial to implement the mqtt_mutal_tls and it works successfully.
Screenshot for successfully with mutual TLS![image](https://github.com/aws/aws-iot-device-sdk-embedded-C/assets/30616512/2a474b3b-7fa5-4e22-9060-266aef576d21)
However when i want to try custom authentication with username/password with this SDK, I was facing problems.
My Setting
~/aws-iot-device-sdk-embedded-c/demos/mqtt/mqtt_demo_mutual_auth/demo-config.h
Generate makefile with solely
cmake
command, and compile the files withmake
command.The I execute the excutable
The results shows that the MQTT connection failed
My HOST
It there any guidance?