1

I have the the authenticated user with federated ID. But when I try to access the AWS IOT stuff I get this error which is driving me crazy.

I am following the iot sample code. All the relevant credentials are correct too.

    `MQTTHelper`
    ....
        credentialsProvider = new CognitoCachingCredentialsProvider(
                        mContext.getApplicationContext(), // context
                        BuildConfig.COGNITO_POOL_ID, // Identity Pool ID
                        MY_REGION // Region
                );

                Region region = Region.getRegion(MY_REGION);

                mqttManager = new AWSIotMqttManager(clientId, BuildConfig.CUSTOMER_SPECIFIC_ENDPOINT);
                mqttManager.setKeepAlive(10);
mAwsIotDataClient = new AWSIotDataClient(credentialsProvider);
        String iotDataEndpoint = BuildConfig.CUSTOMER_SPECIFIC_ENDPOINT;
        mAwsIotDataClient.setEndpoint(iotDataEndpoint);
        mAwsIotDataClient.setRegion(region);

        // mqttManager.setMqttLastWillAndTestament(lwt);

        mIotAndroidClient = new AWSIotClient(credentialsProvider);
        mIotAndroidClient.setRegion(region);

        keystorePath = mContext.getFilesDir().getPath();
        keystoreName = BuildConfig.KEYSTORE_NAME;
        keystorePassword = BuildConfig.KEYSTORE_PASSWORD;
        certificateId = BuildConfig.CERTIFICATE_ID;

        // To load cert/key from keystore on filesystem
        try {
            if (AWSIotKeystoreHelper.isKeystorePresent(keystorePath, keystoreName)) {
                if (AWSIotKeystoreHelper.keystoreContainsAlias(certificateId, keystorePath,
                        keystoreName, keystorePassword)) {
                    Log.d(LOG_TAG, "Certificate " + certificateId
                            + " found in keystore - using for MQTT.");
                    // load keystore from file into memory to pass on connection
                    clientKeyStore = AWSIotKeystoreHelper.getIotKeystore(certificateId,
                            keystorePath, keystoreName, keystorePassword);
                    //btnConnect.setEnabled(true);
                    Log.i(LOG_TAG, "Connected....");
                    //CONNECTED_TO_DEVICE = true;
                } else {
                    Log.i(LOG_TAG, "Key/cert " + certificateId + " not found in keystore.");
                }
            } else {
                Log.i(LOG_TAG, "Keystore " + keystorePath + "/" + keystoreName + " not found.");
            }
        } catch (Exception e) {
            Log.e(LOG_TAG, "An error occurred retrieving cert/key from keystore.", e);
        }


        if (clientKeyStore == null) {

            IS_CERTIFICATE_GENERATED = false;

            Log.i(LOG_TAG, "Cert/key was not found in keystore - creating new key and certificate.");

            doGenerateNewCertificate();

        } else {

            IS_CERTIFICATE_GENERATED = true;
            doMqttConnect();
        }




    }

    private static void doMqttConnect() {

        Log.d(LOG_TAG, "clientId = " + clientId);

        try {
            mqttManager.connect(clientKeyStore, new AWSIotMqttClientStatusCallback() {
                @Override
                public void onStatusChanged(final AWSIotMqttClientStatus status,
                                            final Throwable throwable) {
                    Log.d(LOG_TAG, "Status = " + String.valueOf(status));

                    if (mqttManagerConnStatus != null) {
                        //Send Mqtt Manager Status Back
                        mqttManagerConnStatus.onStatusChanged(status, throwable);
                    }


                }

            });
        } catch (final Exception e) {
            Log.e(LOG_TAG, "Connection error.", e);

        }

and similarly as mentioned in the sample code I am calling GetShadow() in another class

 GetThingShadowRequest getThingShadowRequest = new GetThingShadowRequest() .withThingName(thingName);

                GetThingShadowResult result = mDashboard.mqttHelper.doGetAwsIotDataClient()
                        .getThingShadow(getThingShadowRequest);

                byte[] bytes = new byte[result.getPayload().remaining()];
                result.getPayload().get(bytes);

                String resultString = new String(bytes);
                return new AsyncTaskResult<String>(resultString);

I am able to get the KMS working so there is no problem with the authenticated (federated Id). The only source of information I get on AWS IOT is just this which is not helpful from client perspective. Is it the issue with the AWS IOT configuration or code issue? I have to subscribe to the Thing Group, is there anything else I need to do to subscribe to the group? This is the Thing Group ARN that I needs to subscribe to arn:aws:iot:us-east-1:XXXXXXXXXX:thinggroup/A_GROUP

Stack Trace

getShadowTask
    com.amazonaws.AmazonServiceException: null (Service: AWSIotData; Status Code: 403; Error Code: ForbiddenException; Request ID: f78eea4d-9053-4b19-1840-297dd67c2667)
        at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:730)
        at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:405)
        at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:212)
        at com.amazonaws.services.iotdata.AWSIotDataClient.invoke(AWSIotDataClient.java:571)
        at com.amazonaws.services.iotdata.AWSIotDataClient.getThingShadow(AWSIotDataClient.java:406)
        at com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter$GetShadowTask.doInBackground(MyDevicesFragment_RV_Adapter.java:519)
        at com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter$GetShadowTask.doInBackground(MyDevicesFragment_RV_Adapter.java:497)
        at android.os.AsyncTask$2.call(AsyncTask.java:295)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
        at java.lang.Thread.run(Thread.java:818)
06-18 06:00:54.029 7489-7489/com.lyrebird.abc E/com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter.GetShadowTask: getShadowTask
    com.amazonaws.AmazonServiceException: null (Service: AWSIotData; Status Code: 403; Error Code: ForbiddenException; Request ID: f78eea4d-9053-4b19-1840-297dd67c2667)
        at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:730)
        at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:405)
        at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:212)
        at com.amazonaws.services.iotdata.AWSIotDataClient.invoke(AWSIotDataClient.java:571)
        at com.amazonaws.services.iotdata.AWSIotDataClient.getThingShadow(AWSIotDataClient.java:406)
        at com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter$GetShadowTask.doInBackground(MyDevicesFragment_RV_Adapter.java:519)
        at com.lyrebird.abc.device.MyDevicesFragment_RV_Adapter$GetShadowTask.doInBackground(MyDevicesFragment_RV_Adapter.java:497)
        at android.os.AsyncTask$2.call(AsyncTask.java:295)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
        at java.lang.Thread.run(Thread.java:818)

Policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:*",
        "lambda:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
Ahmed S. Durrani
  • 1,535
  • 2
  • 17
  • 41
  • Can you post a stack trace? Also, can you share the details of the policy you have configured for the Cognito unAuth role? One other question: the AWS sample demonstrates unauthenticated access (i.e., customer doesn't have to login on the app). If you have moved away from that and require that the customer logs-in in your scenario, share the policy for the Cognito Auth role as well. – Bommas Jun 14 '18 at 15:56
  • @Bommas Please see the updated question. – Ahmed S. Durrani Jun 18 '18 at 01:04
  • Are you using social logins in federated ID? Is there a proper connection established between thing in AWS? – Aarth Tandel Jun 18 '18 at 18:48
  • @AarthTandel Socials are not in federated ID but the simple login is. The iot devices are working fine but at the same time getting this error. Perhaps the application could be added as a thing? If yes how? – Ahmed S. Durrani Jun 20 '18 at 09:54
  • @AhmedS.Durrani Thanks for sharing the policy. Is this policy setup on the the Cognito auth role? – Bommas Jun 25 '18 at 04:58
  • @Bommas not sure. – Ahmed S. Durrani Jun 25 '18 at 05:01

1 Answers1

2

Here are the few reasons why you might be getting error 403

  1. In Cognito, there are no appropriate permissions for Update/Get Shadow both for authenticated and unauthenticated pool
  2. The ARN of the Cognito Pool id as well as the IoT are incorrect
  3. Check the IAM policy and the following policy to the Cognito users, Also for the Cognito user, you have to attach AttachPrincipalPolicy policy to give them appropriate permissions for Get/update the shadow. The policy below should be in the Cognito Auth and UnAuth roles.

    {

    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iot:AttachPrincipalPolicy"
            ],
            "Resource": [
                "*"
            ]
        }
    ] }
    
Aarth Tandel
  • 1,001
  • 12
  • 32
  • Could you explain your first point in a little more detail? Are you saying that with Cognito, the policy in the original question (that allowed `iot:*`) wouldn't let you update a shadow? If so, could you point to any documentation of that? – Rapunzel Van Winkle Jun 30 '18 at 06:47
  • 1
    There are two policies needed for Cognito IoTFullAccess the one that your mentioned (You can custom make this policy) and the policy which is written in 3rd point both the policies are necessary for Authenticated users. link https://stackoverflow.com/questions/40301345/connect-to-aws-iot-using-web-socket-with-cognito-authenticated-users – Aarth Tandel Jun 30 '18 at 07:06
  • Aha! But why do we then need that second policy allowing `iot:AttachPrincipalPolicy`? I would think that should be included under `iot:*`. How is the second policy different? – Rapunzel Van Winkle Jun 30 '18 at 10:40
  • 1
    Yes, it is different that is iot:AttachPrincipalPolicy. That policy has to attach to each and every Cognito user for Authenticated user. Please see the link I have attached in the first comment. – Aarth Tandel Jun 30 '18 at 11:01