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);
        }
Esempio n. 3
0
        /// <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));
        }
Esempio n. 4
0
        /// <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);
        }