I am creating an android application which connects to AWS IoT using Amazon Cognito authentication. I am able to authenticate user successfully and I am able get the credentials.
While updating the thing shadow using these credentials always return 403 Forbidden Exception. I have tried all my ways to troubleshoot the issue but I found no solutions.
My IAM Policy is:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:GetThingShadow",
"iot:UpdateThingShadow",
],
"Resource": [
"arn:aws:iot:us-west-2:<my_account>:thing/mythingname"
]
}
]
}
Android code for connecting endpoint:
userSession= AppHelper.getCurrSession();
credentialsProvider=new CognitoCachingCredentialsProvider(getApplicationContext(),POOL_ID,REGIONS);
Map<String,String> logins=new HashMap<String, String>();
logins.put("cognito-idp.us-west-2.amazonaws.com/user_pool_id",userSession.getIdToken().getJWTToken());
credentialsProvider.setLogins(logins);
iotDataClient=new AWSIotDataClient(credentialsProvider);
iotDataClient.setEndpoint(ENDPOINT);
Updating thing shadow:
UpdateThingShadowRequest request=new UpdateThingShadowRequest();
request.setThingName(thingName);
ByteBuffer payloadBuffer=ByteBuffer.wrap(updateState.getBytes());
request.setPayload(payloadBuffer);
UpdateThingShadowResult result=iotDataClient.updateThingShadow(request);
Any help with this regard would be appreciated.
I had the same issue as you. I've found a solution.
That 403 status code mean that you need authorization.
If you read this documentation (near the end) : Publish/Subscribe Policy Exemple it's stated that you need 2 policies to make it work with Authenticated Cognito User. One for the Cognito Identity Pool and another for the Cognito User.
It's not possible to attach a policy to a cognito user with the UI, but you can do it through the CLI.
The command to attach a policy to a cognito user is :
aws iot attach-principal-policy --principal "cognito user id" --policy-Name "policy name"
You can find your cognito user id in :
Cognito > Manager Federated Identities > choose your identity pool > identity browser > and find your identity ID
I use this policy for testing purpose.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:*"
],
"Resource": [
"*"
]
}
]
}
To make it reusable, you need to use a lambda function (here in JavaScript).
var AWS = require('aws-sdk');
var iot = new AWS.Iot();
exports.handler = function(event, context, cb) {
var params = {
policyName: 'your policy',
principal: 'your cognito id'
};
var out = iot.attachPrincipalPolicy(params, function(err, data) {
if (err) cb(err);
else cb(null, data);
});
};
I am able to identify the issue. In my case, I was missing to set region for AWS iot client.
Region region = Region.getRegion(MY_REGION);
mIotAndroidClient.setRegion(region); // I was missing this piece of code
Related
I'm trying to implement AWS sign in with web UI on my app, followed the documentation and it's working fine but I can't redirect back to my app after sign in.
In my amplifyconfiguration.json :
"Auth": {
"Default": {
"OAuth": {
"WebDomain": "xxxxxxxxxxxx",
"AppClientId": "xxxxxxxxxxxxx",
"SignInRedirectURI": "http://localhost:3000/",
"SignOutRedirectURI": "http://localhost:3000/",
"responseType": "code",
"Scopes": [
"phone",
"email",
"openid",
"profile",
"aws.cognito.signin.user.admin"
]
},
"authenticationFlowType": "USER_SRP_AUTH"
}
}
When I change "SignInRedirectURI": "http://localhost:3000/" to "SignInRedirectURI": "myapp//" instead of the login page it shows this error:
Am I missing something?
You have to pull the amplify auth again or make changes in your awsconfiguration.json and amplifyconfiguration.json file to change the redirect URL.
I'm using following flutter library for Okta integration
https://github.com/sonikro/flutter-okta-sdk
Code is of course, same for Android and iOS App but the JWT token generated for Android and iOS app is having different information when decoded.
Because of this difference token generated by iOS App is getting authenticated by backend server but token generated by Android app is getting rejected as invalid token. This is probably because backend code is configured for "aud" as api://default
Token generated by iOS looks like below. It contains "iss" ending with oauth2/default and aud as api://default.
{
"ver": 1,
"jti": "AT.Mbk7V5Sp1hNRzpHA4JKBoF9dniS4AO_WBPSUgNqJ4Pk",
"iss": "https://org-dev.oktapreview.com/oauth2/default",
"aud": "api://default",
"iat": 1650342083,
"exp": 1650345683,
"cid": "0otyt767ytytE41d7",
"uid": "00iuererere77def1d7",
"scp": [
"email",
"openid",
"profile"
],
"auth_time": 1650342081,
"sub": "abhishek.lastname#org.com"
}
But in case of Android, "iss" is just "https://org-dev.oktapreview.com" and aud is also "https://org-dev.oktapreview.com"
{
"ver": 1,
"jti": "AT.VMgUDc-wJnEXTx4n5I-QyKTI0yMGTqBWw8HA9FE6EPY",
"iss": "https://org-dev.oktapreview.com",
"aud": "https://org-dev.oktapreview.com",
"sub": "abhishek.lastname#org.com",
"iat": 1649419357,
"exp": 1649422957,
"cid": "0otyt767ytytE41d7",
"uid": "00iuererere77def1d7",
"scp": [
"openid",
"profile",
"email"
],
"auth_time": 1649419354
}
Please suggest if something we should do on our code or in flutter okta sdk or backend code
I am using CognitoCachingCredentialsProvider to initialise an AWSKMSClient in my android application to get the temporary credentials for authorizing encrypt() operation and ListKeys() of the AWS KMS service. In my IAM role policy, I have specified the authorization to encrypt operation on a specific KeyID and ListKeys operation on all resources. Still I am getting an Access Denied Exception with the error that
assumed-role/Cognito_usernameUnauth_Role/CognitoIdentityCredentials is not authorized
to perform the operation ListKeys on resource *.
(Service: AWSKMS; Status Code: 400; Error Code: AccessDeniedException; Request ID 123456788)
I have run simulation on IAM role Cognito_usernameUnAuthRole and that says that ListKeys operation is allowed.
I am unable to understand why is this happening ? Here is the IAM Policy attached to my role.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"kms:ListKeys",
"kms:ListAliases",
"mobileanalytics:PutEvents",
"apigateway:POST",
"cognito-sync:*"
],
"Resource": "*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "kms:Encrypt",
"Resource": "arn:aws:kms:region:1234:key/123456789”
}
]
}
I'm developing an Android app and keep having issues accessing S3 bucket "through" Cognito.
I'm managing to connect to my cognito pool, with a username and a password of a specific user from my pool:
AWSMobileClient auth = AWSMobileClient.getInstance();
auth.signIn("username", "password", new HashMap<String, String>());
if (auth.isSignedIn()) {
ActivityUtils.startActivity(this, MyActivity.class);
}
My user in the pool is assigned to a group with attach S3 role:
Role ARN arn:aws:iam::<my account number>:role/Cognito_S3_Full_Access
Which contains those permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
]
}
When I'm trying to use the "AmazonS3Client" I created using the credentials from the "AWSMobileClient" I keep getting errors. I create it in this way:
AWSMobileClient awsMobileClient =AWSMobileClient.getInstance();
AmazonS3Client s3Client = new AmazonS3Client(awsMobileClient);
And the error that I got is:
2019-05-20 17:56:21.645 27019-27019/com.mycomp.mypackage E/S3Uploader: Error upload file to S3 bucket : Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: 375C07384A904483)
When I'm creating the "AmazonS3Client" using HARD-CODED accessKey and secretKey of a new "IAM" user that I created and attach the same policy as above it working as expected.
I'm using it this way:
BasicAWSCredentials credentials = new BasicAWSCredentials("myAccessKey_hsjgfhjsdg", "mySecretKey_asdhasjkdha");
AmazonS3Client s3Client = new AmazonS3Client(credentials);
But I don't want to fill up my app with hard coded password, especially that I already manage to connect using the user input of his username and password
Some notes: when I trying to get the secret key and access key after login with Cognito I can see that I get different token every login, so I guess this part is working.
So my question is what am I doing wrong?
How can I make the "AmazonS3Client" to use the session and role permission of the log-in user and his assigned group?
I had everything set up properly and was getting the same Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: 8D650E2CCCD58E34)
What I missed was the condition in the S3 template:
"Condition": {
"StringLike": {
"s3:prefix": [
"public/",
"public/*",
"protected/",
"protected/*",
"private/${cognito-identity.amazonaws.com:sub}/",
"private/${cognito-identity.amazonaws.com:sub}/*"
]
}
}
Basically your keys have to start with these prefixes, depending on the policy. I didn't think much of the public/s3Key.txt example key in the Amplify docs.
private val transferUtility = TransferUtility.builder()
.context(context)
.s3Client(AmazonS3Client(AWSMobileClient.getInstance(), Region.getRegion(Regions.EU_WEST_1)))
.awsConfiguration(AWSMobileClient.getInstance().configuration) // use the generated s3 template
.build()
transferUtility.upload("public/$key/${file.name}", file)
I am using Slim framework to return JSON to my Android device. I am currently working on login on my device. I am using 3 different ways to login: Facebook, Google and account login. When he takes account login he can register a new account or login with an existing one.
For security on my web service I thought to use JWT security. So I am reading and watching video's about how it works. I think I understand how it works, but I cannot find anything about how to implement it correctly.
The middleware I use for slim v3 is called: Slim-JWT-Auth.
I found the following link to implement this in my slim framework, and it works correctly I think.
Now my questions:
How do I generate my Token?
When do I generate my Token?
Do I also need a Token when using Google or Facebook sign-in? because they already use a Auth2.0 token?
I understand how it works but nobody is talking about when and how to implement it. So when do I need to generate the token (on login on the webservice?), and do I need to generate a token after every start of the app, or do I just need to wait until the token expires?
How do I generate my Token?
Since the middleware already includes firebase/php-jwt library you can use it to generate the token.
$now = new DateTime();
$future = new DateTime("now +2 hours");
$server = $request->getServerParams();
$payload = [
"iat" => $now->getTimeStamp(),
"exp" => $future->getTimeStamp(),
"sub" => $server["PHP_AUTH_USER"]
];
$secret = "supersecretkeyyoushouldnotcommittogithub";
$token = JWT::encode($payload, $secret, "HS256");
When do I generate my Token?
In your api you can for example include a password protected route which returns the token. All other routes except /token are JWT authenticated. Client can request token with every request or just always bit before the old one expires.
$app->add(new \Slim\Middleware\HttpBasicAuthentication([
"path" => "/token",
"users" => [
"test" => "test"
]
]);
$app->add(new \Slim\Middleware\JwtAuthentication([
"secret" => "supersecretkeyyoushouldnotcommittogithub"
"rules" => [
new RequestPathRule([
"path" => "/",
"passthrough" => ["/token"]
])
]
]);
$app->post("/token", function ($request, $response, $arguments) {
$now = new DateTime();
$future = new DateTime("now +2 hours");
$server = $request->getServerParams();
$payload = [
"iat" => $now->getTimeStamp(),
"exp" => $future->getTimeStamp(),
"sub" => $server["PHP_AUTH_USER"],
];
$secret = "supersecretkeyyoushouldnotcommittogithub";
$token = JWT::encode($payload, $secret, "HS256");
$data["status"] = "ok";
$data["token"] = $token;
return $response->withStatus(201)
->withHeader("Content-Type", "application/json")
->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
});
Do I also need a Token when using Google or Facebook sign-in? because they already use a Auth2.0 token?
There is no clear answer to this. It "depends". You could for example authenticate your /token route with Facebook or Google and return your own JWT token from there.
There is an work in progress more detailed example implementation of everything above you might want to check.