internal static void MultipleUserAssertionHashTest() { TokenCacheKey key = new TokenCacheKey("https://localhost/MockSts/", "resource1", "client1", TokenSubjectType.Client, null, "user1"); TokenCacheKey key2 = new TokenCacheKey("https://localhost/MockSts/", "resource1", "client1", TokenSubjectType.Client, null, "user2"); AuthenticationResultEx value = CreateCacheValue(null, "user1"); value.UserAssertionHash = "hash1"; AuthenticationResultEx value2 = CreateCacheValue(null, "user2"); value2.UserAssertionHash = "hash2"; TokenCache cache = new TokenCache(); cache.tokenCacheDictionary[key] = value; cache.tokenCacheDictionary[key2] = value2; CacheQueryData data = new CacheQueryData() { AssertionHash = "hash1", Authority = "https://localhost/MockSts/", Resource = "resource1", ClientId = "client1", SubjectType = TokenSubjectType.Client, UniqueId = null, DisplayableId = null }; AuthenticationResultEx resultEx = cache.LoadFromCache(data, null); AreAuthenticationResultExsEqual(value, resultEx); data.AssertionHash = "hash2"; resultEx = cache.LoadFromCache(data, null); AreAuthenticationResultExsEqual(value2, resultEx); data.AssertionHash = null; try { cache.LoadFromCache(data, null); Assert.Fail("multiple_tokens_detected should have been thrown"); } catch (Exception exc) { Assert.IsTrue(exc is AdalException); Assert.AreEqual(((AdalException)exc).ErrorCode, AdalError.MultipleTokensMatched); } }
internal static async Task MultipleUserAssertionHashTestAsync() { TokenCacheKey key = new TokenCacheKey("https://localhost/MockSts/", "resource1", "client1", TokenSubjectType.Client, null, "user1"); TokenCacheKey key2 = new TokenCacheKey("https://localhost/MockSts/", "resource1", "client1", TokenSubjectType.Client, null, "user2"); AuthenticationResultEx value = CreateCacheValue(null, "user1"); value.UserAssertionHash = "hash1"; AuthenticationResultEx value2 = CreateCacheValue(null, "user2"); value2.UserAssertionHash = "hash2"; TokenCache cache = new TokenCache(); cache.tokenCacheDictionary[key] = value; cache.tokenCacheDictionary[key2] = value2; CacheQueryData data = new CacheQueryData() { AssertionHash = "hash1", Authority = "https://localhost/MockSts/", Resource = "resource1", ClientId = "client1", SubjectType = TokenSubjectType.Client, UniqueId = null, DisplayableId = null }; AuthenticationResultEx resultEx = await cache.LoadFromCacheAsync(data, CallState.Default).ConfigureAwait(false); AreAuthenticationResultExsEqual(value, resultEx); data.AssertionHash = "hash2"; resultEx = await cache.LoadFromCacheAsync(data, CallState.Default).ConfigureAwait(false); AreAuthenticationResultExsEqual(value2, resultEx); data.AssertionHash = null; // Multiple tokens in cache -> error var exc = AssertException.TaskThrows <AdalException>(async() => await cache.LoadFromCacheAsync(data, CallState.Default).ConfigureAwait(false)); Assert.AreEqual(exc.ErrorCode, AdalError.MultipleTokensMatched); }
/// <summary> /// Attempts to retrieve a fingerprint entry. /// If the query is successful, a <see cref="PipFingerprintEntry"/> is returned (or null, if there is no current entry for the fingerprint). /// </summary> public async Task <Possible <PipFingerprintEntry, Failure> > TryGetFingerprintEntryAsync(ContentFingerprint fingerprint, CacheQueryData cacheQueryData = null) { StrongContentFingerprint dummyFingerprint = ComputeDummyStrongFingerprint( m_pathTable, fingerprint); var weakFingerprint = new WeakContentFingerprint(fingerprint.Hash); Possible <CacheEntry?, Failure> maybeEntry = await m_twoPhaseStore.TryGetCacheEntryAsync( weakFingerprint : weakFingerprint, pathSetHash : s_dummyPathSetHash, strongFingerprint : dummyFingerprint); if (!maybeEntry.Succeeded) { return(maybeEntry.Failure); } if (!maybeEntry.Result.HasValue) { // Real miss. return((PipFingerprintEntry)null); } if (cacheQueryData != null) { cacheQueryData.WeakContentFingerprint = weakFingerprint; cacheQueryData.PathSetHash = s_dummyPathSetHash; cacheQueryData.StrongContentFingerprint = dummyFingerprint; cacheQueryData.MetadataHash = maybeEntry.Result.Value.MetadataHash; cacheQueryData.ContentCache = m_contentCache; } return(await TryLoadAndDeserializeContent(maybeEntry.Result.Value.MetadataHash)); }
/// <summary> /// Attempts to store a fingerprint entry; this is a compare-exchange operation, in which <paramref name="previousEntry"/> /// must match what is currently stored (or must be <c>null</c> if no entry is currently stored). /// This operation will fail if the previous entry doesn't match, or if the store could not normally proceed. /// </summary> public async Task <Possible <CacheEntryPublishResult, Failure> > TryStoreFingerprintEntryAsync( ContentFingerprint fingerprint, PipFingerprintEntry entry, PipFingerprintEntry previousEntry = null, bool replaceExisting = true, CacheQueryData cacheQueryData = null) { Contract.Assume(entry != null); Analysis.IgnoreArgument(previousEntry); // See class remarks; replace semantics are broken. // We have in hand a PipFingerprintEntry which the underlyign m_twoPhaseStore does not understand. // We will serialize it and store it to the CAS, and that CAS hash will be the stored entry's MetadataHash. // See symmetric deserialization in TryGetFingerprintEntryAsync. Possible <ContentHash, Failure> maybeStored = await m_contentCache.TrySerializeAndStoreContent(entry); if (!maybeStored.Succeeded) { return(maybeStored.Failure.Annotate("Failed to store cache-entry metadata to the CAS")); } ContentHash metadataHash = maybeStored.Result; // The metadata (single-phase entry) is stored, so now we can construct an entry that references it. // From now on, 'twoPhaseEntry' will mean 'the entry we are actually storing in the two-phase store'. // Meanwhile, like any implementation, we assume that the referenced content (e.g. output files) // were stored by the caller already. ContentHash[] twoPhaseReferencedHashes = entry.OutputContentHashes.Select(b => b.ToContentHash()).Where(hash => !hash.IsSpecialValue()).ToArray(); CacheEntry twoPhaseEntry = new CacheEntry(metadataHash, null, ArrayView <ContentHash> .FromArray(twoPhaseReferencedHashes)); StrongContentFingerprint dummyFingerprint = ComputeDummyStrongFingerprint( m_pathTable, fingerprint); var weakFingerprint = new WeakContentFingerprint(fingerprint.Hash); Possible <CacheEntryPublishResult, Failure> maybePublished = await m_twoPhaseStore.TryPublishCacheEntryAsync( weakFingerprint : weakFingerprint, pathSetHash : s_dummyPathSetHash, strongFingerprint : dummyFingerprint, entry : twoPhaseEntry, mode : replaceExisting?CacheEntryPublishMode.CreateNewOrReplaceExisting : CacheEntryPublishMode.CreateNew); if (cacheQueryData != null) { cacheQueryData.WeakContentFingerprint = weakFingerprint; cacheQueryData.PathSetHash = s_dummyPathSetHash; cacheQueryData.StrongContentFingerprint = dummyFingerprint; cacheQueryData.ContentCache = m_contentCache; } if (maybePublished.Succeeded) { if (maybePublished.Result.Status == CacheEntryPublishStatus.Published || (!replaceExisting && maybePublished.Result.Status == CacheEntryPublishStatus.RejectedDueToConflictingEntry)) { return(maybePublished.Result); } else { // ISinglePhaseFingerprintStore represents conflicts as failures. return(new Failure <string>( "Failed to publish a cache entry; the underlying two-phase store indicated an entry conflict (maybe it does not allow replacement of existing entries).")); } } else { return(maybePublished.Failure); } }
internal static void TokenCacheOperationsTest() { var tokenCache = new TokenCache(); var cacheDictionary = tokenCache.tokenCacheDictionary; tokenCache.Clear(); TokenCacheKey key = new TokenCacheKey("https://localhost/MockSts/", "resource1", "client1", TokenSubjectType.User, null, "user1"); TokenCacheKey key2 = new TokenCacheKey("https://localhost/MockSts/", "resource1", "client1", TokenSubjectType.User, null, "user2"); TokenCacheKey key3 = new TokenCacheKey("https://localhost/MockSts/", "resource1", "client1", TokenSubjectType.UserPlusClient, null, "user1"); Assert.AreNotEqual(key, key3); var value = CreateCacheValue(null, "user1"); AuthenticationResultEx value2; do { value2 = CreateCacheValue(null, "user2"); } while (value2 == value); Assert.AreEqual(0, cacheDictionary.Count); AddToDictionary(tokenCache, key, value); Assert.AreEqual(1, cacheDictionary.Count); var valueInCache = cacheDictionary[key]; VerifyAuthenticationResultExsAreEqual(valueInCache, value); VerifyAuthenticationResultExsAreNotEqual(valueInCache, value2); cacheDictionary[key] = value2; Assert.AreEqual(1, cacheDictionary.Count); valueInCache = cacheDictionary[key]; VerifyAuthenticationResultExsAreEqual(valueInCache, value2); VerifyAuthenticationResultExsAreNotEqual(valueInCache, value); // Duplicate key -> should fail to add again AssertException.Throws <ArgumentException>(() => AddToDictionary(tokenCache, key, value)); Log.Comment( "====== Verifying that correct values are retrieved when requested for different tenant with user and without user"); CacheQueryData data = new CacheQueryData() { Authority = "https://localhost/MockSts1", Resource = "resource1", ClientId = "client1", UniqueId = null, DisplayableId = "user1", SubjectType = TokenSubjectType.User }; AuthenticationResultEx resultEx = tokenCache.LoadFromCache(data, CallState.Default); Assert.IsNotNull(resultEx); Assert.IsTrue(RemoveFromDictionary(tokenCache, key)); Assert.IsFalse(RemoveFromDictionary(tokenCache, key)); Assert.AreEqual(0, cacheDictionary.Count); AddToDictionary(tokenCache, key, value); AddToDictionary(tokenCache, key2, value2); Assert.AreEqual(2, cacheDictionary.Count); Assert.AreEqual(cacheDictionary[key], value); Assert.AreEqual(cacheDictionary[key2], value2); // Null key -> error AssertException.Throws <ArgumentNullException>(() => AddToDictionary(tokenCache, null, value)); // Null key -> error AssertException.Throws <ArgumentNullException>(() => AddToDictionary(tokenCache, null, value)); Assert.IsFalse(cacheDictionary.IsReadOnly); var keys = cacheDictionary.Keys.ToList(); var values = cacheDictionary.Values.ToList(); Assert.AreEqual(2, keys.Count); Assert.AreEqual(2, values.Count); if (keys[0].Equals(key)) { Assert.AreEqual(keys[1], key2); Assert.AreEqual(values[0], value); Assert.AreEqual(values[1], value2); } else { Assert.AreEqual(keys[0], key2); Assert.AreEqual(keys[1], key); Assert.AreEqual(values[0], value2); Assert.AreEqual(values[1], value); } Assert.IsTrue(cacheDictionary.ContainsKey(key)); Assert.IsTrue(cacheDictionary.ContainsKey(key2)); Assert.IsFalse(cacheDictionary.ContainsKey(key3)); Assert.IsTrue(cacheDictionary.Contains(new KeyValuePair <TokenCacheKey, AuthenticationResultEx>(key, value))); Assert.IsTrue(cacheDictionary.Contains(new KeyValuePair <TokenCacheKey, AuthenticationResultEx>(key2, value2))); Assert.IsFalse(cacheDictionary.Contains(new KeyValuePair <TokenCacheKey, AuthenticationResultEx>(key, value2))); Assert.IsFalse(cacheDictionary.Contains(new KeyValuePair <TokenCacheKey, AuthenticationResultEx>(key2, value))); // Duplicate key -> error AssertException.Throws <ArgumentException>(() => AddToDictionary(tokenCache, key, value)); AddToDictionary(tokenCache, key3, value); Assert.AreEqual(3, cacheDictionary.Keys.Count); Assert.IsTrue(cacheDictionary.ContainsKey(key3)); var cacheItemsCopy = new KeyValuePair <TokenCacheKey, AuthenticationResultEx> [cacheDictionary.Count + 1]; cacheDictionary.CopyTo(cacheItemsCopy, 1); for (int i = 0; i < cacheDictionary.Count; i++) { Assert.AreEqual(cacheItemsCopy[i + 1].Value, cacheDictionary[cacheItemsCopy[i + 1].Key]); } AssertException.Throws <ArgumentException>(() => cacheDictionary.CopyTo(cacheItemsCopy, 2)); AssertException.Throws <ArgumentOutOfRangeException>(() => cacheDictionary.CopyTo(cacheItemsCopy, -1)); RemoveFromDictionary(tokenCache, key2); Assert.AreEqual(2, cacheDictionary.Keys.Count); foreach (var kvp in cacheDictionary) { Assert.IsTrue(kvp.Key.Equals(key) || kvp.Key.Equals(key3)); Assert.IsTrue(kvp.Value.Equals(value)); } AuthenticationResultEx cacheValue; Assert.IsTrue(cacheDictionary.TryGetValue(key, out cacheValue)); Assert.AreEqual(cacheValue, value); Assert.IsTrue(cacheDictionary.TryGetValue(key3, out cacheValue)); Assert.AreEqual(cacheValue, value); Assert.IsFalse(cacheDictionary.TryGetValue(key2, out cacheValue)); cacheDictionary.Clear(); Assert.AreEqual(0, cacheDictionary.Keys.Count); }