Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
9 changes: 4 additions & 5 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
vNext
Version 23.1.1-RC1
----------
- [MINOR] Share SharedPreferencesInMemoryCache across instances of BrokerOAuth2TokenCache (#2813)
- [MINOR] Use SharedPreferencesInMemoryCache implementation in Broker (#2802)

Version 23.1.1-RC1
----------

Version 23.1.0
----------
- [MINOR] Add OpenTelemetry support for passkey operations (#2795)
Expand Down Expand Up @@ -1199,4 +1198,4 @@ Version 0.0.3
* Separate methods for PII/OII logging
- Initial Exception model implemented
* BaseException + Client & Service subclasses
- Substantial portions of HTTP/S networking code migrated from ADAL & MSAL to this module
- Substantial portions of HTTP/S networking code migrated from ADAL & MSAL to this module
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,17 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.when;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;

import com.microsoft.identity.common.components.AndroidPlatformComponentsFactory;
import com.microsoft.identity.common.components.MockPlatformComponentsFactory;
import com.microsoft.identity.common.internal.platform.AndroidPlatformUtil;
import com.microsoft.identity.common.java.cache.BrokerApplicationMetadata;
Expand All @@ -66,10 +67,15 @@
import com.microsoft.identity.common.java.cache.SharedPreferencesAccountCredentialCache;
import com.microsoft.identity.common.java.cache.AccountDeletionRecord;
import com.microsoft.identity.common.java.cache.ICacheRecord;
import com.microsoft.identity.common.java.cache.SharedPreferencesAccountCredentialCacheWithMemoryCache;
import com.microsoft.identity.common.java.dto.AccountRecord;
import com.microsoft.identity.common.java.dto.Credential;
import com.microsoft.identity.common.java.dto.CredentialType;
import com.microsoft.identity.common.java.exception.ClientException;
import com.microsoft.identity.common.java.flighting.CommonFlight;
import com.microsoft.identity.common.java.flighting.CommonFlightsManager;
import com.microsoft.identity.common.java.flighting.IFlightsManager;
import com.microsoft.identity.common.java.flighting.IFlightsProvider;
import com.microsoft.identity.common.java.interfaces.INameValueStorage;
import com.microsoft.identity.common.java.interfaces.IPlatformComponents;
import com.microsoft.identity.common.java.providers.microsoft.MicrosoftAccount;
Expand All @@ -79,14 +85,15 @@
import com.microsoft.identity.common.java.providers.oauth2.OAuth2TokenCache;
import com.microsoft.identity.common.shadows.ShadowAndroidSdkStorageEncryptionManager;

import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowSharedPreferences;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -236,6 +243,7 @@ public void tearDown() throws Exception {
}

mApplicationMetadataCache.clear();
CommonFlightsManager.INSTANCE.resetFlightsManager();
}

private void initOtherCaches(final IPlatformComponents components) {
Expand Down Expand Up @@ -1241,4 +1249,120 @@ public void testClearAll() throws ClientException {
assertEquals(false, mBrokerOAuth2TokenCache.isClientIdKnownToCache(clientId));
}
}

@Test
public void testSingleCacheInstancePerStoreName_FlightEnabled() {
// Enable the flight
updateUseInMemoryCacheFlight(true);

final String storeName = "test_store_name";
final IPlatformComponents components1 = mPlatformComponents;
final IPlatformComponents components2 = mPlatformComponents;

// Call getCacheToBeUsed twice with the same storeName
final IAccountCredentialCache cache1 = BrokerOAuth2TokenCache.getCacheToBeUsed(components1, storeName);
final IAccountCredentialCache cache2 = BrokerOAuth2TokenCache.getCacheToBeUsed(components2, storeName);

// Verify both references point to the same instance
assertNotNull(cache1);
assertNotNull(cache2);
assertSame("Expected same cache instance for same storeName", cache1, cache2);
assertTrue("Cache should be of type SharedPreferencesAccountCredentialCacheWithMemoryCache",
cache1 instanceof SharedPreferencesAccountCredentialCacheWithMemoryCache);
}

@Test
public void testDifferentCacheInstancesPerStoreName_FlightEnabled() {
// Enable the flight
updateUseInMemoryCacheFlight(true);

final String storeName1 = "test_store_name_1";
final String storeName2 = "test_store_name_2";
final IPlatformComponents components = mPlatformComponents;

// Call getCacheToBeUsed with different storeNames
final IAccountCredentialCache cache1 = BrokerOAuth2TokenCache.getCacheToBeUsed(components, storeName1);
final IAccountCredentialCache cache2 = BrokerOAuth2TokenCache.getCacheToBeUsed(components, storeName2);

// Verify both are valid but different instances
assertNotNull(cache1);
assertNotNull(cache2);
assertNotSame("Expected different cache instances for different storeNames", cache1, cache2);
assertTrue("Cache should be of type SharedPreferencesAccountCredentialCacheWithMemoryCache",
cache1 instanceof SharedPreferencesAccountCredentialCacheWithMemoryCache);
assertTrue("Cache should be of type SharedPreferencesAccountCredentialCacheWithMemoryCache",
cache2 instanceof SharedPreferencesAccountCredentialCacheWithMemoryCache);
}

@Test
public void testCacheInstanceReusedAcrossMultipleBrokerTokenCaches_FlightEnabled() {
// Enable the flight
updateUseInMemoryCacheFlight(true);

final String storeName = getBrokerUidSequesteredFilename(TEST_APP_UID);

// Create multiple BrokerOAuth2TokenCache instances
final BrokerOAuth2TokenCache tokenCache1 = new BrokerOAuth2TokenCache
(mPlatformComponents,
TEST_APP_UID,
new NameValueStorageBrokerApplicationMetadataCache(mPlatformComponents));
final BrokerOAuth2TokenCache tokenCache2 = new BrokerOAuth2TokenCache(mPlatformComponents, TEST_APP_UID,
new NameValueStorageBrokerApplicationMetadataCache(mPlatformComponents));

// Get the underlying account credential caches
final IAccountCredentialCache cache1 = tokenCache1.getCacheToBeUsed(mPlatformComponents, storeName);
final IAccountCredentialCache cache2 = tokenCache2.getCacheToBeUsed(mPlatformComponents, storeName);

// Verify same instance is reused
assertNotNull(cache1);
assertNotNull(cache2);
assertSame(cache1, cache2);
}

@Test
public void testFociCacheInstanceReused_FlightEnabled() {
// Enable the flight
updateUseInMemoryCacheFlight(true);

final String fociStoreName = BROKER_FOCI_ACCOUNT_CREDENTIAL_SHARED_PREFERENCES;

// Call getCacheToBeUsed multiple times for FOCI cache
final IAccountCredentialCache fociCache1 = BrokerOAuth2TokenCache.getCacheToBeUsed(mPlatformComponents, fociStoreName);
final IAccountCredentialCache fociCache2 = BrokerOAuth2TokenCache.getCacheToBeUsed(mPlatformComponents, fociStoreName);

// Verify same FOCI cache instance is reused
assertNotNull(fociCache1);
assertNotNull(fociCache2);
assertSame(fociCache1, fociCache2);
}

private void updateUseInMemoryCacheFlight(boolean enabled) {
final IFlightsProvider mockFlightsProvider = Mockito.mock(IFlightsProvider.class);
Mockito.when(mockFlightsProvider.isFlightEnabled(CommonFlight.USE_IN_MEMORY_CACHE_FOR_ACCOUNTS_AND_CREDENTIALS))
.thenReturn(enabled);

// Create anonymous IFlightsManager
IFlightsManager anonymousFlightsManager = new IFlightsManager() {
@Override
public @NotNull IFlightsProvider getFlightsProvider(long waitForConfigsWithTimeoutInMs) {
return mockFlightsProvider;
}
@Override
public @NotNull IFlightsProvider getFlightsProviderForTenant(@NotNull String tenantId, long waitForConfigsWithTimeoutInMs) {
return mockFlightsProvider;
}
@Override
public @NotNull IFlightsProvider getFlightsProviderForTenant(@NotNull String tenantId) {
return mockFlightsProvider;
}
@NonNull
@Override
public IFlightsProvider getFlightsProvider() {
return mockFlightsProvider;
}
};

// Initialize CommonFlightsManager with the anonymous implementation
CommonFlightsManager.INSTANCE.initializeCommonFlightsManager(anonymousFlightsManager);
}
}
Loading
Loading