Skip to content

Commit

Permalink
Fix a bug where migrating expirationDate in CognitoCachingCredentials…
Browse files Browse the repository at this point in the history
…Provider crashes (#781)

* Secure information stored in SharedPreferences

* Lower aws-android-sdk-core-test compile and target sdk version to 27

* Add a symlink to android-23.jar for core

* Add a gradle task that creates a symlink to android-23.jar for AWS Core

* Fix the gradle task that creates symbolic link to android-23.jar

* Change config.yml to setup android-23

* Enable core, cognitoidentityprovider and cognitoauth integration tests on CircleCI

* Enable core, cognitoidentityprovider and cognitoauth integration tests on CircleCI

* Fix pom.xml

* Improve exception handling in AWSKeyValueStore

* [2.12.3] Bump the patch version of 2.12.z

* Update 2.12.3 CHANGELOG

* Add the missing bucket prefixes to CleanupBucketIntegrationTests

* Fix a bug where migrating expirationDate in CognitoCachingCredentialsProvider crashes
  • Loading branch information
Karthikeyan authored Mar 11, 2019
1 parent 2cbdaf0 commit 6af4dec
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ __pycache__/
# Credentials
**/testconfiguration.json
**/awsconfiguration.json
aws-android-sdk-testutils/src/main/res/raw/testconfiguration.json

# AWSCoreRuntime libs
aws-android-sdk-core/libs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
* Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package com.amazonaws.internal.keyvaluestore;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import android.content.Context;
import android.content.SharedPreferences;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;

import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.regions.Regions;

import java.util.ArrayList;


@RunWith(AndroidJUnit4.class)
public class AWSKeyValueStoreMigrationIntegrationTest extends CoreIntegrationTestBase {

private static String TAG = CognitoCachingCredentialsProviderIntegrationTest.class.getSimpleName();

private ArrayList<CognitoCachingCredentialsProvider> credentialsProviders =new ArrayList<CognitoCachingCredentialsProvider>();
private CognitoCachingCredentialsProvider credentialsProvider;

private static SharedPreferences sharedPreferencesForAuth;
private String identityPoolId;
private long time;

@BeforeClass
public static void setupBeforeClass() {
sharedPreferencesForAuth = InstrumentationRegistry.getTargetContext()
.getSharedPreferences("com.amazonaws.android.auth", Context.MODE_PRIVATE);
}

@AfterClass
public static void tearDownAfterClass() {
sharedPreferencesForAuth
.edit()
.clear()
.commit();
}

@Before
public void setUp() throws Exception {
time = System.currentTimeMillis();
identityPoolId = getPackageConfigure().getString("identity_pool_id");
sharedPreferencesForAuth.edit()
.putString(identityPoolId + ".accessKey" , "accessKey")
.putString(identityPoolId + ".secretKey" , "secretKey")
.putString(identityPoolId + ".sessionToken" , "sessionToken")
.putString(identityPoolId + ".identityId" , "identityId")
.putLong(identityPoolId + ".expirationDate" , time)
.commit();
}

@After
public void tearDown() {
sharedPreferencesForAuth
.edit()
.clear()
.commit();

AWSKeyValueStore.cacheFactory.clear();
}

@Test
public void testCachedAWSCredentialsMigration() throws Exception {
Log.d(TAG, "SharedPreferences contents before migration for com.amazonaws.android.auth => " +
sharedPreferencesForAuth.getAll().toString());

assertEquals("accessKey", sharedPreferencesForAuth.getString(identityPoolId + ".accessKey", null));
assertEquals("secretKey", sharedPreferencesForAuth.getString(identityPoolId + ".secretKey", null));
assertEquals("sessionToken", sharedPreferencesForAuth.getString(identityPoolId + ".sessionToken", null));
assertEquals("identityId", sharedPreferencesForAuth.getString(identityPoolId + ".identityId", null));
assertEquals(time, sharedPreferencesForAuth.getLong(identityPoolId + ".expirationDate", 0));

credentialsProvider = new CognitoCachingCredentialsProvider(
InstrumentationRegistry.getTargetContext(),
getPackageConfigure().getString("identity_pool_id"),
Regions.US_EAST_1);
credentialsProviders.add(credentialsProvider);

AWSKeyValueStore awsKeyValueStore = new AWSKeyValueStore(InstrumentationRegistry.getTargetContext(),
"com.amazonaws.android.auth",
true);

Log.d(TAG, "SharedPreferences contents after migration for com.amazonaws.android.auth => " +
sharedPreferencesForAuth.getAll().toString());

assertEquals("accessKey", awsKeyValueStore.get(identityPoolId + ".accessKey"));
assertEquals("secretKey", awsKeyValueStore.get(identityPoolId + ".secretKey"));
assertEquals("sessionToken", awsKeyValueStore.get(identityPoolId + ".sessionToken"));
assertEquals("identityId", awsKeyValueStore.get(identityPoolId + ".identityId"));
assertEquals(String.valueOf(time), awsKeyValueStore.get(identityPoolId + ".expirationDate"));

credentialsProvider.clearCredentials();
credentialsProvider.clear();
assertNull(credentialsProvider.getCachedIdentityId());

assertNotNull(credentialsProvider.getCredentials());
assertNotNull(credentialsProvider.getIdentityId());
assertNotNull(credentialsProvider.getCachedIdentityId());

assertEquals(credentialsProvider.getIdentityId(), credentialsProvider.getCachedIdentityId());

verifySharedPreferencesContents();
verifyCredentialsProviderClear();
}

private void verifySharedPreferencesContents() {
assert sharedPreferencesForAuth.getAll().keySet().size() == credentialsProviders.size() * 5;

Log.d(TAG, "SharedPreferences Keys = " +
sharedPreferencesForAuth.getAll().keySet().toString());

for (int iterator = 0; iterator < credentialsProviders.size(); iterator++) {
final CognitoCachingCredentialsProvider cccp = credentialsProviders.get(iterator);
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".accessKey.encrypted" , null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".secretKey.encrypted", null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".sessionToken.encrypted", null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".identityId.encrypted", null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".expirationDate.encrypted", null));

assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".accessKey.encrypted.iv" , null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".secretKey.encrypted.iv", null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".sessionToken.encrypted.iv", null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".identityId.encrypted.iv", null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".expirationDate.encrypted.iv", null));

assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".accessKey.encrypted.keyvaluestoreversion" , null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".secretKey.encrypted.keyvaluestoreversion", null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".sessionToken.encrypted.keyvaluestoreversion", null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".identityId.encrypted.keyvaluestoreversion", null));
assertNotNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".expirationDate.encrypted.keyvaluestoreversion", null));

assertNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".accessKey", null));
assertNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".secretKey", null));
assertNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".sessionToken", null));
assertNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".identityId", null));
assertNull(sharedPreferencesForAuth.getString(cccp.getIdentityPoolId() + ".expirationDate", null));
}
}

private void verifyCredentialsProviderClear() {
for (int iterator = 0; iterator < credentialsProviders.size(); iterator++){
final CognitoCachingCredentialsProvider cccp = credentialsProviders.get(iterator);

cccp.clearCredentials();
cccp.clear();

assertNull(cccp.getCachedIdentityId());
assertNotNull(cccp.getIdentityId());
assertNotNull(cccp.getCachedIdentityId());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/**
* Copyright 2019-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://aws.amazon.com/apache2.0
*
* This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and
* limitations under the License.
*/

package com.amazonaws.internal.keyvaluestore;

import android.content.Context;
Expand Down Expand Up @@ -258,14 +273,34 @@ public void clear() {
}

/**
* Migrate all the keys except for the encryption metadata
* Migrate all the keys in the SharedPreferences namespace
* except for the encryption metadata
*/
private void onMigrateFromNoEncryption() {
for (final String spKey: sharedPreferences.getAll().keySet()) {
Map<String, ?> map = sharedPreferences.getAll();
for (String spKey : map.keySet()) {
if (!spKey.endsWith(SHARED_PREFERENCES_DATA_IDENTIFIER_SUFFIX) &&
!spKey.endsWith(SHARED_PREFERENCES_IV_SUFFIX) &&
!spKey.endsWith(SHARED_PREFERENCES_STORE_VERSION_SUFFIX)) {
put(spKey, sharedPreferences.getString(spKey, null));
!spKey.endsWith(SHARED_PREFERENCES_IV_SUFFIX) &&
!spKey.endsWith(SHARED_PREFERENCES_STORE_VERSION_SUFFIX)) {

// Check if its an instance of the dataType.
if (map.get(spKey) instanceof Long) {
Long longValue = sharedPreferences.getLong(spKey, 0);
put(spKey, String.valueOf(longValue));
} else if (map.get(spKey) instanceof String) {
put(spKey, sharedPreferences.getString(spKey, null));
} else if (map.get(spKey) instanceof Float) {
Float floatValue = sharedPreferences.getFloat(spKey, 0);
put(spKey, String.valueOf(floatValue));
} else if (map.get(spKey) instanceof Boolean) {
Boolean booleanValue = sharedPreferences.getBoolean(spKey, false);
put(spKey, String.valueOf(booleanValue));
} else if (map.get(spKey) instanceof Integer) {
Integer intValue = sharedPreferences.getInt(spKey, 0);
put(spKey, String.valueOf(intValue));
}

// Remove the key since key.encrypted is written.
sharedPreferences.edit().remove(spKey).apply();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

package com.amazonaws.services.s3;

import com.amazonaws.regions.Region;
Expand Down Expand Up @@ -27,7 +26,7 @@ public class CleanupBucketIntegrationTests extends AWSTestBase {
public void setup() throws FileNotFoundException, IOException {
setUpCredentials();
s3 = new AmazonS3Client(credentials);
s3.setRegion(Region.getRegion(Regions.US_WEST_2));
s3.setRegion(Region.getRegion(Regions.US_WEST_1));
}

@Test
Expand Down Expand Up @@ -58,7 +57,12 @@ public void testCleanup() {
|| bucket.getName().startsWith("java-get-object-integ-test")
|| bucket.getName().startsWith("java-multiget-object-iteration-test")
|| bucket.getName().startsWith("amazon-s3-client-integ-test")
|| bucket.getName().startsWith("android-sdk-mp-upload")) {
|| bucket.getName().startsWith("android-sdk-mp-upload")
|| bucket.getName().startsWith("java-sts-integ-test")
|| bucket.getName().startsWith("s3-low-level-presigned-url")
|| bucket.getName().startsWith("java-bucket-policy-integ-test")
|| bucket.getName().startsWith("copy-object-integ-test")
|| bucket.getName().startsWith("java-server-side-encryption-integ-test")) {

final String bucket_name = bucket.getName();
try {
Expand Down

0 comments on commit 6af4dec

Please sign in to comment.