Closed RoustamManookian closed 2 years ago
Hi @diegocstn ,
I have encountered a similar problem. I replaced the function attachPolicy
with attachprincipalPolicy
then I got an another error:
connecting ... (status code 1)
connecting error (status code 5)
connecting ... (status code 1)
connecting error (status code 5)
The issue is similar to this . So far , any idea?
Hello, Could you please check out our IoT Sample App [https://github.com/awslabs/aws-sdk-ios-samples/tree/main/IoT-Sample/Swift] to refer to how to AWS IoT APIs in your applications? Please also refer to : https://docs.amplify.aws/sdk/pubsub/getting-started/q/platform/ios/#aws-iot on how to attach IoT policy to your Cognito Identity.
Hi in your sample you use attachPrincipalPolicy() function but in documentation, it's written that this function is deprecated and suggested to use attachPolicy() function instead.
Hi @RoustamManookian @thisisabhash , Thank you for your help! I have replaced the function attachPolicy() with attachPrinciplePolicy(). However, the issue still exists. I try another way to workaround. The following code shows the snippets.
if let certificateId = defaults.string(forKey: "certificateId") {
print("cerid == \(certificateId)")
self.attachIdPolicy()
self.connectDataManager(cerid: certificateId)
} else {
self.createCertificateIdAndStoreinNSUserDefaults { cerid in
print("cerid \(cerid)")
defaults.setValue(cerid, forKey: "certificateId")
self.connectDataManager(cerid: cerid)
} onFailure: { error in
print("is error")
}
}
func attachIdPolicy() {
let id = AWSMobileClient.default().getIdentityId()
let attachPrincipalPolicyRequest = AWSIoTAttachPrincipalPolicyRequest()
attachPrincipalPolicyRequest?.policyName = POLICY_NAME
attachPrincipalPolicyRequest?.principal = id.result as String?
IotManager.shared.iot.attachPrincipalPolicy(attachPrincipalPolicyRequest!).continueWith { task in
print("attach id policy finish, erro ->>>> \(task.error)")
}
}
private func createCertificateIdAndStoreinNSUserDefaults(onSuccess: @escaping (String)->Void, onFailure: @escaping (Error) -> Void) {
let defaults = UserDefaults.standard
let csrDictionary = [ "commonName": CertificateSigningRequestCommonName,
"countryName": CertificateSigningRequestCountryName,
"organizationName": CertificateSigningRequestOrganizationName,
"organizationalUnitName": CertificateSigningRequestOrganizationalUnitName]
IotManager.shared.iotManager.createKeysAndCertificate(fromCsr: csrDictionary) { (response) -> Void in
guard let response = response else {
onFailure(NSError(domain: "No response on iotManager.createKeysAndCertificate", code: -2, userInfo: nil))
return
}
defaults.set(response.certificateId, forKey:"certificateId")
let certificateId = response.certificateId
let attachPrincipalPolicyRequest = AWSIoTAttachPrincipalPolicyRequest()
attachPrincipalPolicyRequest?.policyName = POLICY_NAME
attachPrincipalPolicyRequest?.principal = response.certificateArn
IotManager.shared.iot.attachPrincipalPolicy(attachPrincipalPolicyRequest!).continueWith { task in
if let certificateId = certificateId {
onSuccess(certificateId)
} else {
onFailure(NSError(domain: "Unable to generate certificate id", code: -1, userInfo: nil))
}
return nil
}
I also attached the following policy to authenticated users in Cognito Identity Pool.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"mobileanalytics:PutEvents",
"cognito-sync:*",
"cognito-identity:*"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "iot:Connect",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"iot:Subscribe",
"iot:Receive",
"iot:Publish"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"iot:AttachPrincipalPolicy",
"iot:CreateKeysAndCertificate",
"iot:CreateCertificateFromCsr"
],
"Resource": "*",
"Effect": "Allow"
}
]
}
Please let me know, If you have better solutions .
Hi, Why do I need to use "createKeysAndCertificate" if I authenticate with Amplify ??
and by the way, I granted iotFullAccess to authenticated users in Cognito Identity Pool.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:*" ], "Resource": "*" } ] }
hi @RoustamManookian
I find that the function iotDataManager.connect
always need an argument called certificateId
.
As you can see the following snippets.
private func connectDataManager(cerid:String) {
let uuid = UUID().uuidString
IotManager.shared.iotDataManager.connect( withClientId: uuid,
cleanSession:true,
certificateId:cerid,
statusCallback: self.mqttEventCallback)
delegate?.loginFinish()
}
So I think I should give a temporary certificate for the function berfore connect to iot core.
I have tried another example. Maybe you can take a look at this example
Then you can use connectUsingWebSocket
to connect aws iot core.
private func mqttConnect() {
print("Connecting to MQTT ...")
self.iotDataManager.connectUsingWebSocket(withClientId: self.clientId, cleanSession: true, statusCallback: mqttEventCallback(_:))
}
But I don't have any problem with iotDataManager connection. I use "guard let userName = Amplify.Auth.getCurrentUser()?.username" and try to connect with current User userName which is the userId.
func connectToMQTT(connectionCallBack: @escaping (MQTT_Status)->Void){
Amplify.Auth.fetchAuthSession { [weak self] result in
switch result {
case .success:
guard let userName = Amplify.Auth.getCurrentUser()?.username
else{
print("OnSuccess: Problem getting userID")
return
}
guard let dataManager = self?.iotDataManager,
let status = self?.connectionStatus
else{
print("OnSuccess: Problem getting dataManager")
return
}
if status.status == .disconnected || status.status == .unknown{
if(!dataManager.connectUsingWebSocket(withClientId: userName,cleanSession: true,
statusCallback: {status in
self?.mqttEventCallback(status, connectionCallBack: connectionCallBack)
}))
{
print("ERROR Trying to connect. Connection Status: \(status)")
}
}
else{
print("Connection Status: \(status)")
}
case .failure(let error):
print(error)
}
}
}
Hi @RoustamManookian ,
I think the argument withClientId
should be given as a user's identity
from credentialProvider rather than a user's name.
An identity is something like
ap-southeast-1:d4512355-814d-4349-aa83-xxxxxxxxxxxx
.
I just created an API that triggers a lambda function which makes the attachPolicy() in JavaScript
var AWS = require('aws-sdk');
var iot = new AWS.Iot({apiVersion: '2015-05-28'});
exports.handler = async(event,context)=>{
var identity_id = "";
var userName = "";
if(event.queryStringParameters != null){
if (event.queryStringParameters.hasOwnProperty("identity_id")){
identity_id = event.queryStringParameters.identity_id;
}
else{
console.log("*** My Logs: line 32 -> identityId is empty");
}
if (event.queryStringParameters.hasOwnProperty("userName")){
userName = event.queryStringParameters.userName;
}
else{
console.log("*** My Logs: line 38 -> userName is empty");
}
}
console.log("userName: -> *" + userName + "*");
console.log("identityId: -> *" + identity_id + "*");
if(identity_id != "" && userName != ""){
//**************************************************************************
// Attach Policy
//**************************************************************************
const attachPolicyResult = new Promise(function(resolve, reject){
let params = {
policyName: 'iot_full_access_policy',
target: identity_id
};
iot.attachPolicy(params, function(err, data) {
if (err){
console.log("*** ERROR: line 54 -> " + err, err.stack);
reject('ERROR: ', err);
}
resolve(JSON.stringify(data));
});
});
var str_result = (await attachPolicyResult);
@RoustamManookian Can you check if you have set your endpoint in awsconfiguration.json
? It should have the details below with your unique endpoint for IoT.
"IoT": {
"Default": {
"Region": "us-east-1",
"Endpoint": "https://change_me-ats.iot.us-east-1.amazonaws.com/"
}
},
"IoTManager": {
"Default": {
"Region": "us-east-1",
"Endpoint": "https://change_me-ats.iot.us-east-1.amazonaws.com/"
}
},
When you get the "Resource Not Found" exception it could be due to using the wrong endpoint.
I would also change your policy so that it is more restrictive.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:*" ], "Resource": "*" } ] }
The policy you shared earlier allows for any IoT action when you could limit it to just what you really need for this client. You can see the list of actions below.
Describe the bug
I use AWS Amplify for signUp and sign In When the user signs up for the first time the AWS console creates an identity provider for the new user. Then I get the identity Id and try to attach it to IOT Core policy in order to be able to use IOT Core.
The IOT.attachPolicy() function is working perfectly on ANDROID and in CLI but in IOS I get ResourceNotFoundException !!!
and this is the output error
Failed to attach Policy. Error Domain=com.amazonaws.AWSIoTErrorDomain Code=20 "Not Found" UserInfo={NSLocalizedDescription=Not Found, NSLocalizedFailureReason=ResourceNotFoundException:}
Steps To Reproduce
Expected behavior
After the user has signed up for the first time iot.attachPolicy function has to attach the newly created identity id to iot.policy
I have to mention that this action is working perfectly on ANDROID and in CLI
Amplify Framework Version
1.21.1
Amplify Categories
Auth
Dependency manager
Swift PM
Swift version
5
CLI version
7.6.12
Xcode version
13.2.1
Relevant log output
No response
Is this a regression?
No
Regression additional context
No response
Device
iPhoneX
iOS Version
14
Specific to simulators
No response
Additional context
No response