2017-02-28 77 views
0

簡而言之:我有一個聯合身份驗證池,其中包含未經身份驗證和驗證身份驗證的角色。我對未經身份驗證的訪問沒有任何問題。但是,當涉及到驗證訪問時,用戶登錄很好,但我的身份驗證用戶角色並未實際應用。用於通過Cognito身份池進行身份驗證的用戶的MQTT連接


我有一個s3桶與簡單的index.html和index.js文件通過MQTT進行通信。

對於經過身份驗證和未經身份驗證的用戶而言,兩種策略看起來完全一樣,並且相當寬容(當然,這不是生產的方式,但我只是試圖以任何方式使其工作到目前爲止) 。所以,這兩個策略如下所示:

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
     { 
      "Effect": "Allow", 
      "Action": "*", 
      "Resource": "*" 
     } 
    ] 
} 

而在index.js我可以建立連接MQTT作爲未認證的用戶,如下所示:

var region = 'eu-west-1'; 
AWS.config.credentials = new AWS.CognitoIdentityCredentials({ 
    IdentityPoolId: 'my-identity-pool-id', 
}); 
AWS.config.credentials.clearCachedId(); 
AWS.config.credentials.get(function(err) { 
    console.log('accessKeyId:', AWS.config.credentials.accessKeyId); 
    if(err) { 
    console.log(err); 
    return; 
    } 
    var requestUrl = SigV4Utils.getSignedUrl(
    'wss', 
    'data.iot.' + region + '.amazonaws.com', 
    '/mqtt', 
    'iotdevicegateway', 
    region, 
    AWS.config.credentials.accessKeyId, 
    AWS.config.credentials.secretAccessKey, 
    AWS.config.credentials.sessionToken 
); 

    initClient(requestUrl); 
}); 

initClient()只是建立由Paho手段MQTT連接:

function initClient(requestUrl) { 
    var clientId = String(Math.random()).replace('.', ''); 
    var rpcId = "smart_heater_" + String(Math.random()).replace('.', ''); 
    var client = new Paho.MQTT.Client(requestUrl, clientId); 
    var connectOptions = { 
    onSuccess: function() { 
     console.log('connected'); 
     // Now I can call client.subscribe(...) or client.send(...) 
    }, 
    useSSL: true, 
    timeout: 3, 
    mqttVersion: 4, 
    onFailure: function (err) { 
     console.error('connect failed', err); 
    } 
    }; 
    client.connect(connectOptions); 

    client.onMessageArrived = function (message) { 
    console.log("msg arrived: " + message); 
    }; 
} 

而且它工作得很好:connected被打印到控制檯,我可以實際發送/訂閱。

現在,我正在嘗試爲經過身份驗證的用戶執行相同的操作。爲此,我添加了Cognito用戶池,在那裏創建了一個用戶,創建了一個「應用程序」,將身份驗證提供程序「Cognito」添加到我的身份池(具有適當的用戶池ID和應用程序客戶端ID),身份驗證本身也正常工作:用戶獲取登錄代碼如下:

var region = 'eu-west-1'; 
var poolData = { 
    UserPoolId: 'eu-west-1_XXXXXXXXX', 
    ClientId: 'ZZZZZZZZZZZZZZZZZZZZZZZZZ', 
}; 
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData); 

var authenticationData = { 
    Username: 'myusername', 
    Password: 'mypassword', 
}; 
var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData); 
var userData = { 
    Username: 'myusername', 
    Pool: userPool 
}; 
var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData); 
cognitoUser.authenticateUser(authenticationDetails, { 
    onSuccess: function (result) { 
    console.log('result:', result); 
    console.log('access token: ' + result.getAccessToken().getJwtToken()); 

    var myUserPoolId = 'eu-west-1_XXXXXXXXX'; 
    console.log('You are now logged in.'); 

    // Add the User's Id Token to the Cognito credentials login map. 
    var logins = {}; 
    logins['cognito-idp.' + region + '.amazonaws.com/' + myUserPoolId] = result.getIdToken().getJwtToken(); 

    AWS.config.credentials.params.Logins = logins; 
    // finally, expire the credentials so we refresh on the next request 
    AWS.config.credentials.expired = true; 

    //call refresh method in order to authenticate user and get new temp credentials 
    AWS.config.credentials.refresh((error) => { 
     if (error) { 
     console.error(error); 
     } else { 
     console.log('Successfully logged!'); 
     console.log('accessKeyId:', AWS.config.credentials.accessKeyId); 

     var requestUrl = SigV4Utils.getSignedUrl(
      'wss', 
      'data.iot.' + region + '.amazonaws.com', 
      '/mqtt', 
      'iotdevicegateway', 
      region, 
      AWS.config.credentials.accessKeyId, 
      AWS.config.credentials.secretAccessKey, 
      AWS.config.credentials.sessionToken 
     ); 

     initClient(requestUrl); 
     } 
    }); 
    }, 

    onFailure: function (err) { 
    alert(err); 
    }, 

    newPasswordRequired: function(userAttributes, requiredAttributes) { 
    // User was signed up by an admin and must provide new 
    // password and required attributes, if any, to complete 
    // authentication. 

    // the api doesn't accept this field back 
    delete userAttributes.email_verified; 

    var newPassword = prompt('Enter new password ', ''); 
    // Get these details and call 
    cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes, this); 
    }, 
}); 

到登錄部分是不平凡的獲得工作,但現在它工作正常:在控制檯中,我看到:

You are now logged in. 
Successfully logged! 
accessKeyId: ASIAIRV4HOMOH6DXFTWA 

然後,在連接時,我收到以下錯誤:

connect failed: {invocationContext: undefined, errorCode: 8, errorMessage: "AMQJS0008I Socket closed."} 

我認爲這是因爲實際應用於已驗證用戶的角色不允許採取動作iot:Connect;我相信,因爲我可以完全照搬了同樣的錯誤了未經驗證的用戶,如果我把用於未經授權的用戶策略中的以下內容:

{ 
    "Action": [ 
     "iot:Connect" 
    ], 
    "Resource": "*", 
    "Effect": "Deny" 
}, 

然後,當他們嘗試連接未授權的用戶將收到相同的錯誤AMQJS0008I Socket closed

因此,它看起來像我的身份驗證用戶的政策並沒有實際應用於已驗證的用戶。

在寫這個問題之前,我做了很多實驗。目前,我的身份池設置,在「身份驗證的角色選擇」我只是「使用默認的角色」,這的確應該選擇我的身份驗證的作用,這就是:

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
     { 
      "Effect": "Allow", 
      "Action": "*", 
      "Resource": "*" 
     } 
    ] 
} 

但我也試圖選擇「選擇角色與規則「,並寫出一個規則,將根據一些匹配條款來設置我的角色。

我也嘗試在我的用戶池中創建一個組,在那裏使用相同的角色,將我的用戶添加到此組,並在身份池設置中設置「從標記中選擇角色」。

沒有幫助。我一直收到經過身份驗證的用戶的這個errorMessage: "AMQJS0008I Socket closed."消息,而對於未經身份驗證的用戶,即使策略是相同的,一切都可以正常工作。

任何幫助表示讚賞。

回答

1

的問題是,經過身份驗證Cognito用戶,IAM策略附加到身份池是不夠的:除了是,一個必須重視的物聯網政策(不IAM策略),以每個標識(基本上,每一個用戶),就像這樣:

$ aws iot attach-principal-policy \ 
    --policy-name Some-Policy \ 
    --principal us-east-1:0390875e-98ef-420d-a52d-f4188ce3cf06 

檢查也是這個線程https://forums.aws.amazon.com/thread.jspa?messageID=726121

+0

所以沒有辦法從AWS控制檯做到這一點,是這樣嗎? –

相關問題