AWS DynamoDB access from Android, access denied to table - android

I'm trying to do CRUD operations on a NoSQL DynamoDB, I originally had not integrated a CognitoPool with my project on the AWS Mobile Hub but I have no done that and replaced my json file in the "raw" directory in my project. The DB is completely public both read and write but for some reason I keep getting this error:
com.amazonaws.AmazonServiceException: User: arn:aws:sts::1234567890:assumed-role/shoppinglist_unauth_MOBILEHUB_1234567890/CognitoIdentityCredentials is not authorized to perform: dynamodb:DescribeTable on resource: arn:aws:dynamodb:us-east-1:1234567890:table/ShoppingLists (Service: AmazonDynamoDB; Status Code: 400; Error Code: AccessDeniedException; Request ID: BQ0HAP7PUGO6AUC04LOHUND1V3VV4KQNSO5AEMVJF66Q9ASUAAJG)
I've changed all the identifying numbers to 1234567890 for security reasons.
This is my .json file:
{
"UserAgent": "MobileHub/1.0",
"Version": "1.0",
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "us-east-1******************,
"Region": "us-east-1"
}
}
},
"IdentityManager": {
"Default": {}
},
"CognitoUserPool": {
"Default": {
"PoolId": "us-east-1_*******",
"AppClientId": "5lg571jsd60ruvair8jiqpefbs",
"AppClientSecret": "bqn8edlp19gfgogfhf4j9qg1mq8u8ftpb328f652n0451gl2dnt",
"Region": "us-east-1"
}
},
"DynamoDBObjectMapper": {
"Default": {
"Region": "us-east-1"
}
},
"PinpointAnalytics": {
"Default": {
"AppId": "27e0f3ee2e63419c9dc8f18f23a294fe",
"Region": "us-east-1"
}
},
"PinpointTargeting": {
"Default": {
"Region": "us-east-1"
}
}
}
This is my onCreate() method in my main activity class
AWSMobileClient.getInstance().initialize(this, awsStartupResult ->
Log.d("YourMainActivity", "AWSMobileClient is instantiated and you are connected to AWS!"))
.execute();
// Instantiate a AmazonDynamoDBMapperClient
AmazonDynamoDBClient dynamoDBClient = new AmazonDynamoDBClient(AWSMobileClient.getInstance().getCredentialsProvider());
this.dynamoDBMapper = DynamoDBMapper.builder()
.dynamoDBClient(dynamoDBClient)
.awsConfiguration(AWSMobileClient.getInstance().getConfiguration())
.build();
Runnable runnable = () -> {
dbClient = new AmazonDynamoDBClient(AWSMobileClient.getInstance().getCredentialsProvider());
// Create a table reference
dbTable = Table.loadTable(dbClient, "ShoppingLists");
Document memo = new Document();
memo.put("Apple", "apple");
dbTable.putItem(memo);
};
Thread myThread = new Thread(runnable);
myThread.start();
My build.gradle should hold the correct dependencies, those are here, granted it may be a bit of a mess:
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation ('com.amazonaws:aws-android-sdk-mobile-client:2.6.+#aar') { transitive = true }
implementation 'com.amazonaws:aws-android-sdk-core:2.6.18'
implementation 'com.amazonaws:aws-android-sdk-s3:2.6.18'
implementation 'com.amazonaws:aws-android-sdk-ddb:2.6.18'
implementation 'com.amazonaws:aws-android-sdk-ddb-mapper:2.6.18'
compile 'com.amazonaws:aws-android-sdk-core:2.6.18'
compile 'com.amazonaws:aws-android-sdk-ddb:2.6.18'
compile 'com.amazonaws:aws-android-sdk-ddb-document:2.4.4'
// Mobile Client for initializing the SDK
implementation ('com.amazonaws:aws-android-sdk-mobile-client:2.6.+#aar') { transitive = true }
// Cognito UserPools for SignIn
implementation 'com.android.support:support-v4:27.1.1'
implementation ('com.amazonaws:aws-android-sdk-auth-userpools:2.6.+#aar') { transitive = true }
// Sign in UI Library
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation ('com.amazonaws:aws-android-sdk-auth-ui:2.6.+#aar') { transitive = true }
As far as I can tell this should work fine, I was helped by another helpful person here to get to the point where it would connect to AWS which it did do at one point but I just can't seem to access the table.
I guess I have two questions, is it possible to do this without a Cognito pool at all and just have it completely unsecure? And if not, how do I get this to work with the Cognito Pool? Should the cognito pool have user names associated with it?

Let me take a crack at answering your questions
1) Can you do this without a Cognito Identity pool? The answer is Yes. This doesn't automatically mean that it is insecure - you can use AWS credentials that you setup for an IAM user. The best practice, however, is to use Cognito Identity pool, which will give you temporary AWS credentials that are valid for a short amount of time.
2) When you create a Cognito Identity pool, two roles (named auth and unauth) are automatically created. The "auth" role is for the cases where you have a signed in user ( for example, signed in using a social login like Facebook and federated to AWS through the Identity pool) and the "unauth" role is for a user who hasn't yet signed in. You can fine-tune the access privileges for these roles using IAM policies to best suit your application's needs.
See this page (https://docs.aws.amazon.com/aws-mobile/latest/developerguide/how-to-nosql-integrate-an-existing-table.html) for specific instructions on how to get this working.

Related

signInAnonymously:FAILURE com.google.firebase.auth.FirebaseAuthException: despite Anonymous Sign in enabled

Despite I have enabled in my Firebase project anonymous sign in, my mobile (Android) app is not able to authenticate and I'm getting this error (on emulator and on physical device too).
signInAnonymously:FAILURE
com.google.firebase.auth.FirebaseAuthException: This operation is restricted to administrators only.
My Firebase config:
My code:
mAuth = FirebaseAuth.getInstance();
...
// Sign in anonymously. Authentication is required to read or write from Firebase Storage.
mAuth
.signInAnonymously()
.addOnSuccessListener(
mActivity,
authResult -> {
Log.d(TAG, "signInAnonymously:SUCCESS");
try {
upload();
} catch (Exception e) {
Log.e(TAG, "upload:FAILURE", e);
}
})
.addOnFailureListener(
mActivity,
exception -> {
Log.e(TAG, "signInAnonymously:FAILURE", exception);
});
}
Dependencies:
implementation 'com.google.firebase:firebase-auth:21.0.1'
implementation 'com.google.firebase:firebase-storage:20.0.0'
implementation "com.google.firebase:firebase-core:18.0.2"
Does anybody had the same problem?
Well, in the end, I updated packages to this:
+ implementation platform('com.google.firebase:firebase-bom:29.0.2')
+ implementation 'com.google.firebase:firebase-auth'
+ implementation 'com.google.firebase:firebase-storage'
... implementation "com.google.firebase:firebase-core:18.0.2" //not updated
Make the Firebase storage rules look like this(disclaimer: for my debug version, production I suppose will be more strict):
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
​
And it started to work. But honestly not sure why ¯\(ツ)/¯.

AWS Amplify. Use existing resources

I have followed the tutorial:
https://aws-amplify.github.io/docs/android/start?ref=amplify-android-btn
To integrate AWS S3 with my android application.
I'm able to download a file, and everything works fine.
I've notice that when i create a enviroment, it creates a new bucket, i don't want to create a new bucket, i want to use an existing one.
I've tried to change the bucket in the awsconfiguration.json. But it does not work.
"S3TransferUtility": {
"Default": {
"Bucket": "somebucket",
"Region": "us-east-1"
}
}
AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: <ID>)
I don't want to create a new bucket, i want to be able to access crated buckets that share objects across other apps.
I solved. For anyone who is interested in.
For using an existing bucket, without creating a environment with amplify. The only thing i done was to add manually the file awsconfiguration.json inside the raw folder. I do not use amplify.
So, my awsconfiguration.json looks like:
{
"Version": "1.0",
"IdentityManager": {
"Default": {}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "cognito-pool-id",
"Region": "region"
}
}
},
"S3TransferUtility": {
"Default": {
"Bucket": "somebucket",
"Region": "region"
}
}
}
And to download objects from S3 i make my TransferUtility like this:
val transferUtility = TransferUtility.builder()
.context(context)
.awsConfiguration(AWSMobileClient.getInstance().configuration)
.s3Client(getAmazonS3Client())
.build()
private fun getAmazonS3Client(): AmazonS3Client{
if (amazonS3Client == null) {
amazonS3Client = AmazonS3Client(
CognitoCachingCredentialsProvider(
context,
BuildConfig.S3_POOL_ID,
Regions.US_EAST_2
),
Region.getRegion(Regions.US_EAST_2)
)
}
return amazonS3Client!!
}

How to setup different configuration(awsconfiguration.json) with AWSMobileClient for debug and release build types

I want to have different configuration for debug and release builds. All the configuration is stored inside awsconfiguration.json, for example I have two different config files how can I set which file should be used.
When using AWSMobileClient.getInstance() it gets default configuration from file awsconfiguration.json
Configuration file example:
{
"Version": "1.0",
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "DIFFERENT_VALUES",
"Region": "DIFFERENT_VALUES"
}
}
},
"IdentityManager": {
"Default": {}
},
"CognitoUserPool": {
"Default": {
"AppClientSecret": "DIFFERENT_VALUES",
"AppClientId": "DIFFERENT_VALUES",
"PoolId": "DIFFERENT_VALUES",
"Region": "DIFFERENT_VALUES"
}
}
}
Update
There is option to use different awsconfiguration.json by puting different files in main\res\raw and release\res\raw, for example by following this answer and it works.
But I'm wondering whether there is an option to do it programmatically.
This can also be acheived by setting the configuration value in AWSConfiguration and then initializing the AWSMobileClient.
AWSConfiguration awsConfiguration = new AWSConfiguration(context);
awsConfiguration.setConfiguration("Stage"); // BuildConfig can be used here.
AWSMobileClient.getInstance().initialize(context, awsConfiguration, new Callback<UserStateDetails>() {
#Override
public void onResult(UserStateDetails userStateDetails) {
}
#Override
public void onError(Exception e) {
}
});
And the awsconfiguration.json file can be updated as below
{
"Version": "1.0",
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "DIFFERENT_VALUES",
"Region": "DIFFERENT_VALUES"
},
"Stage": {
"PoolId": "STAGE_VALUES",
"Region": "STAGE_VALUES"
}
}
},
"IdentityManager": {
"Default": {},
"Stage": {}
},
"CognitoUserPool": {
"Default": {
"AppClientSecret": "DIFFERENT_VALUES",
"AppClientId": "DIFFERENT_VALUES",
"PoolId": "DIFFERENT_VALUES",
"Region": "DIFFERENT_VALUES"
},
"Stage": {
"AppClientSecret": "STAGE_VALUES",
"AppClientId": "STAGE_VALUES",
"PoolId": "STAGE_VALUES",
"Region": "STAGE_VALUES"
}
}
}
I've been trying to achieve something similar; selecting an AWS configuration at runtime based on a selected profile. I got it partially working by hacking the AWS SDK but then stumbled across release notes for AWS SDK version 2.11.0. Quoting:
Added the option of passing the configuration as an in-memory object (i.e. [String: Any]/NSDictionary) instead of the default awsconfiguration.json through the new API
I've also found it documented(!) in the amplify getting started guide here.
So since 9th September 2019 it IS possible to select an AWS configuration at runtime.
Edit: Just noticed that this question is for Android rather than iOS. I'm not an Android developer but a quick searched revealed something similar in AWS Android SDK release 2.13.6 (7th June 2019). Quoting the release notes:
Add AWSConfiguration(JSONObject) constructor to construct a AWSConfiguration object from the configuration passed via a JSONObject
... which looks promising.
This can be done with source sets; eg. directories main & debug or directories debug & release, where res/raw or assets are not being processed by AAPT2. Adding credentials alike that is only suggested for internal use, because they can be easily extracted from the package.
Abhishek's answer is my favorite of these. But if you're using Amplify (as I am), while it's possible to put multiple configurations into a single file, I've not found a way of selecting between them.
So, although it's not an exact answer to the question, in Amplify you can select between multiple, self-contained configuration files like this:
When you set up Amplify:
Amplify.addPlugin(AWSCognitoAuthPlugin())
// and whatever other plugins you'll need...
Amplify.configure(AmplifyConfiguration.fromConfigFile(applicationContext, getConfigResourceId(applicationContext)), applicationContext)
And also add:
private fun getConfigResourceId(context: Context): Int = context.resources.getIdentifier("YourConfigFileName", "raw", context.packageName)

Firebase Authentication API Email/Password Android

I am attempting to write an app for android that uses Firebase Authentication via Email/Password. It is enabled. However the tutorial, and the code in Github for the examples are showing:
private FirebaseAuth mAuth;
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:cardview-v7:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.google.firebase:firebase-core:9.0.2'
}
apply plugin: 'com.google.gms.google-services'
However, I get an error as if the "FirebaseAuth" doesn't exist. However the latest documentation says otherwise.
Github sample code
Any help would be greatly appreciated.
Replace the com.google.firebase:firebase-core:9.0.2' dependency with the com.google.firebase:firebase-auth:9.0.2 dependency. So:
compile 'com.google.firebase:firebase-auth:9.0.2'
instead of
compile 'com.google.firebase:firebase-core:9.0.2' under your dependencies.
I did not find the FirebaseAuth class in the core dependency but I did find it in the auth dependency. Furthermore, if you checkout their dependencies list, they do not add the core dependency, they add the auth dependency instead.
According to documentation in the firebase web page you should create a Firebase object using the URL from your firebase and from there create usernames with passwords or log them in. The code you showed used this FirebaseAuth for that.
Here is the code to create a new user:
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.createUser("bobtony#firebase.com", "correcthorsebatterystaple", new Firebase.ValueResultHandler<Map<String, Object>>() {
#Override
public void onSuccess(Map<String, Object> result) {
System.out.println("Successfully created user account with uid: " + result.get("uid"));
}
#Override
public void onError(FirebaseError firebaseError) {
// there was an error
}
});
Here is the code to log him in:
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.authWithPassword("bobtony#firebase.com", "correcthorsebatterystaple", new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
System.out.println("User ID: " + authData.getUid() + ", Provider: " + authData.getProvider());
}
#Override
public void onAuthenticationError(FirebaseError firebaseError) {
// there was an error
}
});
Got all of this info from the quick start guide here: https://www.firebase.com/docs/android/guide/login/password.html#section-logging-in
Hope it helps.

How to get push interactive notification with Urban Airship in Android?

I've integrated Urban Airship SDK to my application on device with Android 4.2 (Jelly Bean). I've received general push-notifications. It's Ok. But I want to get interactive push-notification with button with "Save" label.
My dependencies from build.gradle:
dependencies {
compile 'com.google.code.gson:gson:2.2.4'
compile 'com.google.android.gms:play-services:+'
compile project (':urbanairship-lib-6.1.1')
compile 'com.android.support:support-v4:22.2.0'
// Recommended for in-app messaging
compile 'com.android.support:cardview-v7:22.2.0'
// Recommended for location services
compile 'com.google.android.gms:play-services-location:7.5.0'
// Required for Android (GCM) push notifications
compile 'com.google.android.gms:play-services-gcm:7.5.0'
compile files('libs/commons-io-2.4.jar')
compile files('libs/FlurryAnalytics-4.1.0.jar')
compile files('libs/nineoldandroids-2.4.0.jar')
}
According to official documentation, I've added the following code in the onCreate() method in MyApplication class:
#Override
public void onCreate() {
AirshipConfigOptions options = new AirshipConfigOptions();
options.developmentAppKey = "sdgsdgsdhsdh";
options.developmentAppSecret = "sdhsdhsdhsdhsh";
options.productionAppKey = "Your Production App Key";
options.productionAppSecret = "Your Production App Secret";
options.inProduction = false;
options.gcmSender = "11111111";
UAirship.takeOff(this, options);
NotificationActionButton hiButtonAction = new NotificationActionButton.Builder("btnSave")
.setLabel(R.string.save)
.setPerformsInForeground(true)
.build();
// Define the group
NotificationActionButtonGroup buttonGroup = new NotificationActionButtonGroup.Builder()
.addNotificationActionButton(hiButtonAction)
.build();
// Add the custom group
UAirship.shared().getPushManager().addNotificationActionButtonGroup("save", buttonGroup);
UAirship.shared().getPushManager().setUserNotificationsEnabled(true);
UAirship.shared().getPushManager().setPushEnabled(true);
}
After that I've tried test push from my Urban Airship account:
EDIT:
I've used Urban Airship API v3. According to official documentation I've sent push with json:
{
"audience": {
"named_user": "2971"
},
"device_types":["android"],
"notification": {
"android": {
"alert": "Hello",
"extra": {
"EEID": "2971",
"DATE": "20150601"
},
"interactive": {
"type": "save"
}
}
}
}
But I've received general push-notification with "Hello" text and without any buttons.
What could be the problem and how to open some activity by click on the button in notification?
Thanks in advance.
The key "category" is not the correct on Android. Its actually looking for "com.urbanairship.interactive_type". However you should be either using the main composer or the push API directly.
curl -v -X POST -u <APP_KEY>:<MASTER_SECRET> -H "Content-type: application/json" -H "Accept: application/vnd.urbanairship+json; version=3;" --data '{
"audience":"ALL",
"device_types":["android"],
"notification": {
"android": {
"alert": "Hello",
"interactive": {
"type": "save"
}
}
}
}' https://go.urbanairship.com/api/push/
But with your apps credentials for <APP_KEY>:<MASTER_SECRET>
See http://docs.urbanairship.com/api/ua.html#interactive-api for more details.

Categories

Resources