Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -767,4 +767,16 @@ private Bundle buildAuthBundle(UserAccount userAccount) {
private String decryptUserData(Account account, String key, String encryptionKey) {
return SalesforceSDKManager.decrypt(accountManager.getUserData(account, key), encryptionKey);
}

/**
* Clears the stored current user info from shared preferences. This should be called
* when the last user logs out to ensure no user information remains on the device.
*/
public void clearStoredCurrentUserInfo() {
clearCachedCurrentUser();
final SharedPreferences sp = context.getSharedPreferences(CURRENT_USER_PREF,
Context.MODE_PRIVATE);
sp.edit().clear().apply();
SalesforceSDKLogger.d(TAG, "Cleared current user info from shared preferences");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ import com.salesforce.androidsdk.rest.NotificationsActionsResponseBody
import com.salesforce.androidsdk.rest.NotificationsApiClient
import com.salesforce.androidsdk.rest.RestClient
import com.salesforce.androidsdk.security.BiometricAuthenticationManager
import com.salesforce.androidsdk.security.SalesforceKeyGenerator
import com.salesforce.androidsdk.security.SalesforceKeyGenerator.getEncryptionKey
import com.salesforce.androidsdk.security.ScreenLockManager
import com.salesforce.androidsdk.ui.AccountSwitcherActivity
Expand Down Expand Up @@ -790,6 +791,10 @@ open class SalesforceSDKManager protected constructor(
(screenLockManager as ScreenLockManager?)?.reset()
screenLockManager = null
biometricAuthenticationManager = null

// Clear stored identifiers and user info from shared preferences
SalesforceKeyGenerator.clearAll()
userAccountManager.clearStoredCurrentUserInfo()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,15 @@ private static String getSharedPrefKey(String name) {
final String suffix = TextUtils.isEmpty(name) ? "" : name;
return String.format(Locale.US, ENCRYPTED_ID_SHARED_PREF_KEY, suffix);
}

/**
* Clears all stored identifiers from shared preferences. This should be called
* when the last user logs out to ensure no encrypted identifiers remain on the device.
*/
public synchronized static void clearAll() {
final SharedPreferences prefs = SalesforceSDKManager.getInstance().getAppContext().getSharedPreferences(SHARED_PREF_FILE, 0);
prefs.edit().clear().apply();
CACHED_ENCRYPTION_KEYS.clear();
SalesforceSDKLogger.d(TAG, "Cleared all identifiers from shared preferences");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import android.accounts.AccountManager;
import android.content.Context;
import android.content.IntentFilter;
import android.content.SharedPreferences;

import androidx.core.content.ContextCompat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
Expand All @@ -42,6 +43,7 @@

import com.salesforce.androidsdk.app.SalesforceSDKManager;
import com.salesforce.androidsdk.auth.OAuth2;
import com.salesforce.androidsdk.security.SalesforceKeyGenerator;
import com.salesforce.androidsdk.util.LogoutCompleteReceiver;

import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -201,6 +203,40 @@ public void testSignoutBackgroundUser() {
Assert.assertEquals(TEST_USERNAME, logoutCompleteReceiver.getLastUserAccountReceived().getUsername());
}

/**
* Test that shared preferences are cleared when the last user logs out.
* This verifies the fix for W-17366971 - ensuring that identifier.xml
* and current_user_info files are deleted on logout.
*/
@Test
public void testSharedPreferencesCleanupOnLastUserLogout() {
final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();

// Create a user and force creation of identifier.xml by accessing the encryption key
createTestAccountInAccountManager(userAccMgr);
String encryptionKey = SalesforceKeyGenerator.getEncryptionKey("test_key");
Assert.assertNotNull("Encryption key should be created", encryptionKey);

// Verify that identifier.xml shared preferences exists with data
SharedPreferences identifierPrefs = context.getSharedPreferences("identifier.xml", 0);
Assert.assertFalse("identifier.xml should have data", identifierPrefs.getAll().isEmpty());

// Verify that current_user_info shared preferences exists with data
SharedPreferences currentUserPrefs = context.getSharedPreferences("current_user_info", 0);
Assert.assertFalse("current_user_info should have data", currentUserPrefs.getAll().isEmpty());

// Logout the last user
userAccMgr.signoutCurrentUser(null, false, OAuth2.LogoutReason.USER_LOGOUT);

// Verify that identifier.xml shared preferences is cleared
identifierPrefs = context.getSharedPreferences("identifier.xml", 0);
Assert.assertTrue("identifier.xml should be empty after logout", identifierPrefs.getAll().isEmpty());

// Verify that current_user_info shared preferences is cleared
currentUserPrefs = context.getSharedPreferences("current_user_info", 0);
Assert.assertTrue("current_user_info should be empty after logout", currentUserPrefs.getAll().isEmpty());
}

/**
* Removes any existing accounts.
*/
Expand Down