Exemple #1
0
        internal static void AddMsalParamsToRequest(
            AuthenticationRequestParameters authenticationRequestParameters,
            WebTokenRequest webTokenRequest,
            ICoreLogger logger,
            string overridenAuthority = null)
        {
            AddExtraParamsToRequest(webTokenRequest, authenticationRequestParameters.ExtraQueryParameters);
            string authority = overridenAuthority ??
                               authenticationRequestParameters.AuthorityManager.OriginalAuthority.AuthorityInfo.CanonicalAuthority;
            bool validate = authenticationRequestParameters.AuthorityInfo.ValidateAuthority;

            AddAuthorityParamToRequest(authority, validate, webTokenRequest);

            AddTelemetryPropertiesToRequest(webTokenRequest, logger);
        }
        private static string GetHomeAccountId(AuthenticationRequestParameters requestParams, MsalTokenResponse response, IdToken idToken)
        {
            string subject = idToken?.Subject;

            if (idToken?.Subject != null)
            {
                requestParams.RequestContext.Logger.Info("Subject not present in Id token");
            }

            ClientInfo clientInfo = response.ClientInfo != null?ClientInfo.CreateFromJson(response.ClientInfo) : null;

            string homeAccountId = clientInfo?.ToAccountIdentifier() ?? subject; // ADFS does not have client info, so we use subject

            return(homeAccountId);
        }
Exemple #3
0
        public void GlobalSetup()
        {
            var serviceBundle = TestCommon.CreateServiceBundleWithCustomHttpManager(null, isLegacyCacheEnabled: EnableLegacyCache);

            _cache    = new TokenCache(serviceBundle, false);
            _response = TestConstants.CreateMsalTokenResponse(TestConstants.Utid);

            _requestParams         = TestCommon.CreateAuthenticationRequestParameters(serviceBundle);
            _requestParams.Account = new Account(TestConstants.s_userIdentifier, $"1{TestConstants.DisplayableId}", TestConstants.ProductionPrefNetworkEnvironment);

            AddHostToInstanceCache(serviceBundle, TestConstants.ProductionPrefCacheEnvironment);

            LegacyTokenCacheHelper.PopulateLegacyCache(serviceBundle.ApplicationLogger, _cache.LegacyPersistence, TokenCacheSize);
            TokenCacheHelper.AddRefreshTokensToCache(_cache.Accessor, TokenCacheSize);
        }
        private static MsalAccessTokenCacheItem GetSingleResult(
            AuthenticationRequestParameters requestParams,
            IReadOnlyList <MsalAccessTokenCacheItem> filteredItems)
        {
            // if only one cached token found
            if (filteredItems.Count == 1)
            {
                return(filteredItems[0]);
            }

            requestParams.RequestContext.Logger.Error("Multiple tokens found for matching authority, client_id, user and scopes. ");
            throw new MsalClientException(
                      MsalError.MultipleTokensMatchedError,
                      MsalErrorMessage.MultipleTokensMatched);
        }
Exemple #5
0
        public async Task <MsalTokenResponse> AcquireTokenInteractiveAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenInteractiveParameters acquireTokenInteractiveParameters)
        {
            using (_logger.LogMethodDuration())
            {
                Dictionary <string, string> brokerRequest = CreateBrokerRequestDictionary(
                    authenticationRequestParameters,
                    acquireTokenInteractiveParameters);

                await InvokeIosBrokerAsync(brokerRequest).ConfigureAwait(false);

                return(ProcessBrokerResponse());
            }
        }
        public OnBehalfOfRequest(AuthenticationRequestParameters authenticationRequestParameters, UserAssertion userAssertion)
            : base(authenticationRequestParameters)
        {
            if (userAssertion == null)
            {
                throw new ArgumentNullException("userAssertion");
            }

            this.userAssertion = userAssertion;
            this.User          = new User {
                DisplayableId = userAssertion.UserName
            };
            this.assertionHash = PlatformPlugin.CryptographyHelper.CreateSha256Hash(userAssertion.Assertion);
            this.SupportADFS   = false;
        }
Exemple #7
0
        public void TryThrottle(AuthenticationRequestParameters requestParams, IReadOnlyDictionary <string, string> bodyParams)
        {
            if (!ThrottlingCache.IsEmpty() &&
                ThrottleCommon.IsRetryAfterAndHttpStatusThrottlingSupported(requestParams))
            {
                var logger = requestParams.RequestContext.Logger;

                string strictThumbprint = ThrottleCommon.GetRequestStrictThumbprint(
                    bodyParams,
                    requestParams.AuthorityInfo.CanonicalAuthority,
                    requestParams.Account?.HomeAccountId?.Identifier);

                ThrottleCommon.TryThrow(strictThumbprint, ThrottlingCache, logger, nameof(HttpStatusProvider));
            }
        }
Exemple #8
0
        public static string GetKeyFromResponse(AuthenticationRequestParameters requestParameters, string homeAccountIdFromResponse)
        {
            if (GetOboOrAppKey(requestParameters, out string key))
            {
                return(key);
            }

            if (requestParameters.IsConfidentialClient ||
                requestParameters.ApiId == TelemetryCore.Internal.Events.ApiEvent.ApiIds.AcquireTokenSilent)
            {
                return(homeAccountIdFromResponse);
            }

            return(null);
        }
Exemple #9
0
        public Task <WebTokenRequest> CreateWebTokenRequestAsync(
            WebAccountProvider provider,
            AuthenticationRequestParameters authenticationRequestParameters,
            bool isForceLoginPrompt,
            bool isInteractive,
            bool isAccountInWam)
        {
            string loginHint = !string.IsNullOrEmpty(authenticationRequestParameters.LoginHint) ?
                               authenticationRequestParameters.LoginHint :
                               authenticationRequestParameters.Account?.Username;

            bool setLoginHint =
                isInteractive &&
                !isAccountInWam &&
                !string.IsNullOrEmpty(loginHint);

            var wamPrompt = setLoginHint || (isInteractive && isForceLoginPrompt) ?
                            WebTokenRequestPromptType.ForceAuthentication :
                            WebTokenRequestPromptType.Default;

            WebTokenRequest request = new WebTokenRequest(
                provider,
                ScopeHelper.GetMsalScopes(authenticationRequestParameters.Scope).AsSingleString(),
                authenticationRequestParameters.AppConfig.ClientId,
                wamPrompt);

            if (setLoginHint)
            {
                request.Properties.Add("LoginHint", authenticationRequestParameters.LoginHint);
            }

            request.Properties.Add("wam_compat", "2.0");
            if (ApiInformation.IsPropertyPresent("Windows.Security.Authentication.Web.Core.WebTokenRequest", "CorrelationId"))
            {
                request.CorrelationId = authenticationRequestParameters.CorrelationId.ToString();
            }
            else
            {
                request.Properties.Add("correlationId", authenticationRequestParameters.CorrelationId.ToString());
            }

            if (!string.IsNullOrEmpty(authenticationRequestParameters.ClaimsAndClientCapabilities))
            {
                request.Properties.Add("claims", authenticationRequestParameters.ClaimsAndClientCapabilities);
            }

            return(Task.FromResult(request));
        }
        private async Task <IWebTokenRequestResultWrapper> AcquireInteractiveWithoutPickerAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            Prompt msalPrompt,
            IWamPlugin wamPlugin,
            WebAccountProvider provider,
            WebAccount wamAccount)
        {
            bool isForceLoginPrompt = IsForceLoginPrompt(msalPrompt);

            WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                provider,
                authenticationRequestParameters,
                isForceLoginPrompt : isForceLoginPrompt,
                isInteractive : true,
                isAccountInWam : true)
                                              .ConfigureAwait(false);

            AddPromptToRequest(msalPrompt, isForceLoginPrompt, webTokenRequest);

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest);

            try
            {
                IWebTokenRequestResultWrapper wamResult;
                if (wamAccount != null)
                {
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest,
                        wamAccount).ConfigureAwait(false);
                }
                else
                {
                    // default user
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest).ConfigureAwait(false);
                }
                return(wamResult);
            }
            catch (Exception ex)
            {
                _logger.ErrorPii(ex);
                throw new MsalServiceException(
                          MsalError.WamInteractiveError,
                          "AcquireTokenInteractive without picker failed. See inner exception for details. ", ex);
            }
        }
        public void SilentRefreshFailedNoCacheItemFoundTest()
        {
            using (var httpManager = new MockHttpManager())
            {
                var serviceBundle        = ServiceBundle.CreateWithCustomHttpManager(httpManager);
                var aadInstanceDiscovery = new AadInstanceDiscovery(httpManager, new TelemetryManager());
                var authority            = Authority.CreateAuthority(serviceBundle, MsalTestConstants.AuthorityHomeTenant, false);
                _cache = new TokenCache()
                {
                    ClientId      = MsalTestConstants.ClientId,
                    ServiceBundle = serviceBundle
                };

                httpManager.AddInstanceDiscoveryMockHandler();

                var parameters = new AuthenticationRequestParameters()
                {
                    Authority = authority,
                    ClientId  = MsalTestConstants.ClientId,
                    Scope     = ScopeHelper.CreateSortedSetFromEnumerable(
                        new[]
                    {
                        "some-scope1",
                        "some-scope2"
                    }),
                    TokenCache     = _cache,
                    Account        = new Account(MsalTestConstants.UserIdentifier, MsalTestConstants.DisplayableId, null),
                    RequestContext = new RequestContext(null, new MsalLogger(Guid.NewGuid(), null))
                };

                var crypto           = PlatformProxyFactory.GetPlatformProxy().CryptographyManager;
                var telemetryManager = new TelemetryManager();

                try
                {
                    var request = new SilentRequest(serviceBundle, parameters, ApiEvent.ApiIds.None, false);
                    Task <AuthenticationResult> task = request.RunAsync(CancellationToken.None);
                    var authenticationResult         = task.Result;
                    Assert.Fail("MsalUiRequiredException should be thrown here");
                }
                catch (AggregateException ae)
                {
                    var exc = ae.InnerException as MsalUiRequiredException;
                    Assert.IsNotNull(exc, "Actual exception type is " + ae.InnerException.GetType());
                    Assert.AreEqual(MsalUiRequiredException.NoTokensFoundError, exc.ErrorCode);
                }
            }
        }
Exemple #12
0
        private async Task <IWebTokenRequestResultWrapper> AcquireInteractiveWithoutPickerAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            Prompt prompt,
            IWamPlugin wamPlugin,
            WebAccountProvider provider,
            WebAccount wamAccount)
        {
            bool isForceLoginPrompt = IsForceLoginPrompt(prompt);

            WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                provider,
                authenticationRequestParameters,
                isForceLoginPrompt : isForceLoginPrompt,
                isInteractive : true,
                isAccountInWam : true)
                                              .ConfigureAwait(false);

            if (isForceLoginPrompt &&
                ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 6))
            {
                // this feature works correctly since windows RS4, aka 1803 with the AAD plugin only!
                webTokenRequest.Properties["prompt"] = prompt.PromptValue;
            }

            AddCommonParamsToRequest(authenticationRequestParameters, webTokenRequest);

            try
            {
#if WINDOWS_APP
                // UWP requires being on the UI thread
                await _synchronizationContext;
#endif

                var wamResult = await _wamProxy.RequestTokenForWindowAsync(
                    _parentHandle,
                    webTokenRequest,
                    wamAccount).ConfigureAwait(false);

                return(wamResult);
            }
            catch (Exception ex)
            {
                _logger.ErrorPii(ex);
                throw new MsalServiceException(
                          MsalError.WamInteractiveError,
                          "AcquireTokenInteractive without picker failed. See inner exception for details. ", ex);
            }
        }
Exemple #13
0
        public async Task <MsalTokenResponse> AcquireTokenSilentAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenSilentParameters acquireTokenSilentParameters)
        {
            using (_logger.LogMethodDuration())
            {
                // Important: MSAL will have already resolved the authority by now,
                // so we are not expecting "common" or "organizations" but a tenanted authority
                bool isMsa = await IsMsaRequestAsync(
                    authenticationRequestParameters.Authority,
                    null,
                    IsMsaPassthrough(authenticationRequestParameters)).ConfigureAwait(false);

                IWamPlugin         wamPlugin = isMsa ? _msaPlugin : _aadPlugin;
                WebAccountProvider provider  = await GetProviderAsync(
                    authenticationRequestParameters.Authority.AuthorityInfo.CanonicalAuthority,
                    isMsa).ConfigureAwait(false);

                WebAccount webAccount = await FindWamAccountForMsalAccountAsync(
                    provider,
                    wamPlugin,
                    authenticationRequestParameters.Account,
                    null, // ATS requires an account object, login_hint is not supported on its own
                    authenticationRequestParameters.ClientId).ConfigureAwait(false);

                if (webAccount == null)
                {
                    throw new MsalUiRequiredException(
                              MsalError.InteractionRequired,
                              "Could not find a WAM account for the silent request.");
                }

                WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                    provider,
                    authenticationRequestParameters,
                    isForceLoginPrompt : false,
                    isAccountInWam : true,
                    isInteractive : false)
                                                  .ConfigureAwait(false);

                AddCommonParamsToRequest(authenticationRequestParameters, webTokenRequest);

                var wamResult =
                    await _wamProxy.GetTokenSilentlyAsync(webAccount, webTokenRequest).ConfigureAwait(false);

                return(CreateMsalTokenResponse(wamResult, wamPlugin, isInteractive: false));
            }
        }
Exemple #14
0
        /// <summary>
        /// IMPORTANT: this class is perf critical; any changes must be benchmarked using Microsoft.Identity.Test.Performace.
        /// More information about how to test and what data to look for is in https://aka.ms/msal-net-performance-testing.
        ///
        /// Scenario: client_creds with default in-memory cache can get to ~500k tokens
        /// </summary>
        async Task <MsalAccessTokenCacheItem> ITokenCacheInternal.FindAccessTokenAsync(
            AuthenticationRequestParameters requestParams)
        {
            var logger = requestParams.RequestContext.Logger;

            // no authority passed
            if (requestParams.AuthorityInfo?.CanonicalAuthority == null)
            {
                logger.Warning("FindAccessToken: No authority provided. Skipping cache lookup ");
                return(null);
            }

            // take a snapshot of the access tokens to avoid problems where the underlying collection is changed,
            // as this method is NOT locked by the semaphore
            IEnumerable <MsalAccessTokenCacheItem> tokenCacheItems = GetAllAccessTokensWithNoLocks(true).ToList();

            tokenCacheItems = FilterByHomeAccountTenantOrAssertion(requestParams, tokenCacheItems);
            tokenCacheItems = FilterByTokenType(requestParams, tokenCacheItems);
            tokenCacheItems = FilterByScopes(requestParams, tokenCacheItems);
            tokenCacheItems = await FilterByEnvironmentAsync(requestParams, tokenCacheItems).ConfigureAwait(false);

            // perf: take a snapshot as calling Count(), Any() etc. on the IEnumerable evaluates it each time
            IReadOnlyList <MsalAccessTokenCacheItem> finalList = tokenCacheItems.ToList();

            CacheInfoTelemetry cacheInfoTelemetry = CacheInfoTelemetry.None;

            // no match
            if (finalList.Count == 0)
            {
                logger.Verbose("No tokens found for matching authority, client_id, user and scopes.");
                cacheInfoTelemetry = CacheInfoTelemetry.NoCachedAT;
                return(null);
            }

            MsalAccessTokenCacheItem msalAccessTokenCacheItem = GetSingleResult(requestParams, finalList);

            msalAccessTokenCacheItem = FilterByKeyId(msalAccessTokenCacheItem, requestParams);
            msalAccessTokenCacheItem = FilterByExpiry(msalAccessTokenCacheItem, requestParams);

            if (msalAccessTokenCacheItem == null)
            {
                cacheInfoTelemetry = CacheInfoTelemetry.Expired;
            }

            requestParams.RequestContext.ApiEvent.CacheInfo = (int)cacheInfoTelemetry;

            return(msalAccessTokenCacheItem);
        }
        private Dictionary <string, string> CreateBrokerRequestDictionary(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenInteractiveParameters acquireTokenInteractiveParameters)
        {
            var brokerRequest = new Dictionary <string, string>(16);

            brokerRequest.Add(BrokerParameter.Authority, authenticationRequestParameters.Authority.AuthorityInfo.CanonicalAuthority);
            string scopes = EnumerableExtensions.AsSingleString(authenticationRequestParameters.Scope);

            brokerRequest.Add(BrokerParameter.Scope, scopes);
            brokerRequest.Add(BrokerParameter.ClientId, authenticationRequestParameters.AppConfig.ClientId);
            brokerRequest.Add(BrokerParameter.CorrelationId, authenticationRequestParameters.RequestContext.CorrelationId.ToString());
            brokerRequest.Add(BrokerParameter.ClientVersion, MsalIdHelper.GetMsalVersion());

            // this needs to be case sensitive because the AppBundle is case sensitive
            brokerRequest.Add(
                BrokerParameter.RedirectUri,
                authenticationRequestParameters.RedirectUri.OriginalString);

            if (authenticationRequestParameters.ExtraQueryParameters?.Any() == true)
            {
                string extraQP = string.Join("&", authenticationRequestParameters.ExtraQueryParameters.Select(x => x.Key + "=" + x.Value));
                brokerRequest.Add(BrokerParameter.ExtraQp, extraQP);
            }

            brokerRequest.Add(BrokerParameter.Username, authenticationRequestParameters.Account?.Username ?? string.Empty);
            brokerRequest.Add(BrokerParameter.ExtraOidcScopes, BrokerParameter.OidcScopesValue);

            var prompt = acquireTokenInteractiveParameters.Prompt;

            if (prompt == Prompt.NoPrompt || prompt == Prompt.NotSpecified)
            {
                brokerRequest.Add(BrokerParameter.Prompt, Prompt.SelectAccount.PromptValue);
            }
            else
            {
                brokerRequest.Add(BrokerParameter.Prompt, acquireTokenInteractiveParameters.Prompt.PromptValue);
            }

            if (!string.IsNullOrEmpty(authenticationRequestParameters.Claims))
            {
                brokerRequest.Add(BrokerParameter.Claims, authenticationRequestParameters.Claims);
            }

            AddCommunicationParams(brokerRequest);

            return(brokerRequest);
        }
        public async Task <MsalTokenResponse> AcquireTokenSilentAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            AcquireTokenSilentParameters acquireTokenSilentParameters)
        {
            var cancellationToken = authenticationRequestParameters.RequestContext.UserCancellationToken;
            MsalTokenResponse msalTokenResponse = null;

            _logger.Verbose("[WamBroker] Acquiring token silently.");

            using (var core = new NativeInterop.Core())
                using (var authParams = WamAdapters.GetCommonAuthParameters(authenticationRequestParameters, _wamOptions.MsaPassthrough))
                {
                    using (var account = await core.ReadAccountByIdAsync(
                               acquireTokenSilentParameters.Account.HomeAccountId.ObjectId,
                               authenticationRequestParameters.CorrelationId.ToString("D"),
                               cancellationToken).ConfigureAwait(false))
                    {
                        if (account == null)
                        {
                            _logger.WarningPii(
                                $"Could not find a WAM account for the selected user {acquireTokenSilentParameters.Account.Username}",
                                "Could not find a WAM account for the selected user");

                            throw new MsalUiRequiredException(
                                      "wam_no_account_for_id",
                                      $"Could not find a WAM account for the selected user {acquireTokenSilentParameters.Account.Username}");
                        }

                        using (NativeInterop.AuthResult result = await core.AcquireTokenSilentlyAsync(
                                   authParams,
                                   authenticationRequestParameters.CorrelationId.ToString("D"),
                                   account,
                                   cancellationToken).ConfigureAwait(false))
                        {
                            if (result.IsSuccess)
                            {
                                msalTokenResponse = WamAdapters.ParseRuntimeResponse(result, authenticationRequestParameters, _logger);
                            }
                            else
                            {
                                WamAdapters.ThrowExceptionFromWamError(result, authenticationRequestParameters, _logger);
                            }
                        }
                    }
                }

            return(msalTokenResponse);
        }
Exemple #17
0
        /// <summary>
        /// delete all cache entries with intersecting scopes.
        /// this should not happen but we have this as a safe guard
        /// against multiple matches.
        /// </summary>
        private void DeleteAccessTokensWithIntersectingScopes(
            AuthenticationRequestParameters requestParams,
            IEnumerable <string> environmentAliases,
            string tenantId,
            HashSet <string> scopeSet,
            string homeAccountId,
            string tokenType)
        {
            if (requestParams.RequestContext.Logger.IsLoggingEnabled(LogLevel.Info))
            {
                requestParams.RequestContext.Logger.Info(
                    "Looking for scopes for the authority in the cache which intersect with " +
                    requestParams.Scope.AsSingleString());
            }

            var accessTokensToDelete     = new List <MsalAccessTokenCacheItem>();
            var partitionKeyFromResponse = CacheKeyFactory.GetInternalPartitionKeyFromResponse(requestParams, homeAccountId);

            Debug.Assert(partitionKeyFromResponse != null || !requestParams.IsConfidentialClient, "On confidential client, cache must be partitioned.");

            foreach (var accessToken in Accessor.GetAllAccessTokens(partitionKeyFromResponse))
            {
                if (accessToken.ClientId.Equals(ClientId, StringComparison.OrdinalIgnoreCase) &&
                    environmentAliases.Contains(accessToken.Environment) &&
                    string.Equals(accessToken.TokenType ?? "", tokenType ?? "", StringComparison.OrdinalIgnoreCase) &&
                    string.Equals(accessToken.TenantId, tenantId, StringComparison.OrdinalIgnoreCase) &&
                    accessToken.ScopeSet.Overlaps(scopeSet))
                {
                    requestParams.RequestContext.Logger.Verbose("Intersecting scopes found");
                    accessTokensToDelete.Add(accessToken);
                }
            }

            requestParams.RequestContext.Logger.Info("Intersecting scope entries count - " + accessTokensToDelete.Count);

            if (!requestParams.IsClientCredentialRequest)
            {
                // filter by identifier of the user instead
                accessTokensToDelete.RemoveAll(
                    item => !item.HomeAccountId.Equals(homeAccountId, StringComparison.OrdinalIgnoreCase));
                requestParams.RequestContext.Logger.Info("Matching entries after filtering by user - " + accessTokensToDelete.Count);
            }

            foreach (var cacheItem in accessTokensToDelete)
            {
                Accessor.DeleteAccessToken(cacheItem);
            }
        }
Exemple #18
0
        async Task <bool?> ITokenCacheInternal.IsFociMemberAsync(AuthenticationRequestParameters requestParams, string familyId)
        {
            var logger = requestParams.RequestContext.Logger;

            if (requestParams?.AuthorityInfo?.CanonicalAuthority == null)
            {
                logger.Warning("No authority details, can't check app metadta. Returning unkown");
                return(null);
            }

            var instanceDiscoveryMetadataEntry = await GetCachedOrDiscoverAuthorityMetaDataAsync(
                requestParams.AuthorityInfo.CanonicalAuthority,
                requestParams.RequestContext).ConfigureAwait(false);

            var environmentAliases = GetEnvironmentAliases(
                requestParams.AuthorityInfo.CanonicalAuthority,
                instanceDiscoveryMetadataEntry);

            TokenCacheNotificationArgs args = new TokenCacheNotificationArgs(this, ClientId, requestParams?.Account, false);

            //TODO: bogavril - is the env ok here? Can I cache it or pass it in?
            MsalAppMetadataCacheItem appMetadata;
            await _semaphoreSlim.WaitAsync().ConfigureAwait(false);

            try
            {
                await OnBeforeAccessAsync(args).ConfigureAwait(false);

                appMetadata =
                    environmentAliases
                    .Select(env => _accessor.GetAppMetadata(new MsalAppMetadataCacheKey(ClientId, env)))
                    .FirstOrDefault(item => item != null);

                await OnAfterAccessAsync(args).ConfigureAwait(false);
            }
            finally
            {
                _semaphoreSlim.Release();
            }

            if (appMetadata == null)
            {
                logger.Warning("No app metadata found. Returning unkown");
                return(null);
            }

            return(appMetadata.FamilyId == familyId);
        }
        public void RecordException(AuthenticationRequestParameters requestParams, IReadOnlyDictionary <string, string> bodyParams, MsalServiceException ex)
        {
            if (ex is MsalUiRequiredException && IsRequestSupported(requestParams))
            {
                var logger = requestParams.RequestContext.Logger;

                logger.Info($"[Throttling] MsalUiRequiredException encountered - " +
                            $"throttling for {s_uiRequiredExpiration.TotalSeconds} seconds");

                var thumbprint = GetRequestStrictThumbprint(bodyParams,
                                                            requestParams.AuthorityInfo.CanonicalAuthority,
                                                            requestParams.RequestContext.ServiceBundle.PlatformProxy.CryptographyManager);
                var entry = new ThrottlingCacheEntry(ex, s_uiRequiredExpiration);
                ThrottlingCache.AddAndCleanup(thumbprint, entry, logger);
            }
        }
Exemple #20
0
        public void ExpiredTokenRefreshFlowTest()
        {
            Authority  authority = Authority.CreateAuthority(TestConstants.AuthorityHomeTenant, false);
            TokenCache cache     = new TokenCache()
            {
                ClientId = TestConstants.ClientId
            };

            TokenCacheHelper.PopulateCache(cache.TokenCacheAccessor);

            AuthenticationRequestParameters parameters = new AuthenticationRequestParameters()
            {
                Authority = authority,
                ClientId  = TestConstants.ClientId,
                Scope     = new[] { "some-scope1", "some-scope2" }.CreateSetFromEnumerable(),
                                            TokenCache     = cache,
                                            RequestContext = new RequestContext(Guid.Empty, null),
                                            User           = new User()
                {
                    Identifier    = TestConstants.UserIdentifier,
                    DisplayableId = TestConstants.DisplayableId
                }
            };

            //add mock response for tenant endpoint discovery
            HttpMessageHandlerFactory.AddMockHandler(new MockHttpMessageHandler
            {
                Method          = HttpMethod.Get,
                ResponseMessage = MockHelpers.CreateOpenIdConfigurationResponse(TestConstants.AuthorityHomeTenant)
            });

            HttpMessageHandlerFactory.AddMockHandler(new MockHttpMessageHandler()
            {
                Method          = HttpMethod.Post,
                ResponseMessage = MockHelpers.CreateSuccessTokenResponseMessage()
            });

            SilentRequest request              = new SilentRequest(parameters, false);
            Task <AuthenticationResult> task   = request.RunAsync();
            AuthenticationResult        result = task.Result;

            Assert.IsNotNull(result);
            Assert.AreEqual("some-access-token", result.AccessToken);
            Assert.AreEqual("some-scope1 some-scope2", result.Scopes.AsSingleString());

            Assert.IsTrue(HttpMessageHandlerFactory.IsMocksQueueEmpty, "All mocks should have been consumed");
        }
Exemple #21
0
        private async Task <IWebTokenRequestResultWrapper> AcquireInteractiveWithWamAccountAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            Prompt msalPrompt,
            IWamPlugin wamPlugin,
            WebAccountProvider provider,
            WebAccount wamAccount)
        {
            WebTokenRequest webTokenRequest = await wamPlugin.CreateWebTokenRequestAsync(
                provider,
                authenticationRequestParameters,
                isForceLoginPrompt : false,
                isInteractive : true,
                isAccountInWam : true)
                                              .ConfigureAwait(false);

            // because of https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/2476
            string differentAuthority = WorkaroundOrganizationsBug(authenticationRequestParameters, wamAccount);

            WamAdapters.AddMsalParamsToRequest(authenticationRequestParameters, webTokenRequest, _logger, differentAuthority);

            try
            {
                IWebTokenRequestResultWrapper wamResult;
                if (wamAccount != null)
                {
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest,
                        wamAccount).ConfigureAwait(false);
                }
                else
                {
                    // default user
                    wamResult = await _wamProxy.RequestTokenForWindowAsync(
                        _parentHandle,
                        webTokenRequest).ConfigureAwait(false);
                }
                return(wamResult);
            }
            catch (Exception ex)
            {
                _logger.ErrorPii(ex);
                throw new MsalServiceException(
                          MsalError.WamInteractiveError,
                          "AcquireTokenInteractive without picker failed. See inner exception for details. ", ex);
            }
        }
Exemple #22
0
        internal RefreshTokenCacheItem FindRefreshToken(AuthenticationRequestParameters requestParams)
        {
            var cacheEvent = new CacheEvent(CacheEvent.TokenCacheLookup)
            {
                TokenType = CacheEvent.TokenTypes.RT
            };

            Telemetry.GetInstance().StartEvent(requestParams.RequestContext.TelemetryRequestId, cacheEvent);
            try
            {
                return(FindRefreshTokenCommon(requestParams));
            }
            finally
            {
                Telemetry.GetInstance().StopEvent(requestParams.RequestContext.TelemetryRequestId, cacheEvent);
            }
        }
        public async Task <string> TryFetchTransferTokenAsync(AuthenticationRequestParameters authenticationRequestParameters, WebAccountProvider accountProvider)
        {
            if (!authenticationRequestParameters.AppConfig.IsMsaPassthrough)
            {
                throw new InvalidOperationException("Not configured for msa-pt");
            }

            // Apps can have MSA-PT enabled and can configured to allow MSA users
            // However, some older apps have 2 incarnations, one in AAD tenant and one in MSA tenant
            // For this second case, we can't fetch the transfer token from the client_ID in AAD and this will fail
            _logger.Verbose("WAM MSA-PT - fetching transfer token");
            string transferToken = await FetchMsaPassthroughTransferTokenAsync(
                authenticationRequestParameters, accountProvider)
                                   .ConfigureAwait(false);

            return(transferToken);
        }
Exemple #24
0
        public void SaveAccessAndRefreshTokenWithLessScopesTest()
        {
            TokenCache cache = new TokenCache()
            {
                ClientId = TestConstants.ClientId
            };

            TokenResponse response = new TokenResponse();

            response.IdToken       = MockHelpers.CreateIdToken(TestConstants.UniqueId, TestConstants.DisplayableId);
            response.ClientInfo    = MockHelpers.CreateClientInfo();
            response.AccessToken   = "access-token";
            response.ExpiresIn     = 3599;
            response.CorrelationId = "correlation-id";
            response.RefreshToken  = "refresh-token";
            response.Scope         = TestConstants.Scope.AsSingleString();
            response.TokenType     = "Bearer";

            RequestContext requestContext = new RequestContext(Guid.NewGuid(), null);
            AuthenticationRequestParameters requestParams = new AuthenticationRequestParameters()
            {
                RequestContext = requestContext,
                Authority      = Authority.CreateAuthority(TestConstants.AuthorityHomeTenant, false),
                ClientId       = TestConstants.ClientId,
                TenantUpdatedCanonicalAuthority = TestConstants.AuthorityHomeTenant
            };

            cache.SaveAccessAndRefreshToken(requestParams, response);

            response               = new TokenResponse();
            response.IdToken       = MockHelpers.CreateIdToken(TestConstants.UniqueId, TestConstants.DisplayableId);
            response.ClientInfo    = MockHelpers.CreateClientInfo();
            response.AccessToken   = "access-token-2";
            response.ExpiresIn     = 3599;
            response.CorrelationId = "correlation-id";
            response.RefreshToken  = "refresh-token-2";
            response.Scope         = TestConstants.Scope.First();
            response.TokenType     = "Bearer";

            cache.SaveAccessAndRefreshToken(requestParams, response);

            Assert.AreEqual(1, cache.TokenCacheAccessor.RefreshTokenCacheDictionary.Count);
            Assert.AreEqual(1, cache.TokenCacheAccessor.AccessTokenCacheDictionary.Count);
            Assert.AreEqual("refresh-token-2", cache.GetAllRefreshTokensForClient(requestContext).First().RefreshToken);
            Assert.AreEqual("access-token-2", cache.GetAllAccessTokensForClient(requestContext).First().AccessToken);
        }
        public void ActAsCurrentUserNoSsoHeaderForLoginHintOnlyTest()
        {
            //this test validates that no SSO header is added when developer passes only login hint and UiOption.ActAsCurrentUser
            Authenticator authenticator = new Authenticator(TestConstants.DefaultAuthorityHomeTenant, false, Guid.NewGuid());
            TokenCache    cache         = new TokenCache();
            TokenCacheKey key           = new TokenCacheKey(TestConstants.DefaultAuthorityHomeTenant,
                                                            TestConstants.DefaultScope, TestConstants.DefaultClientId,
                                                            TestConstants.DefaultUniqueId, TestConstants.DefaultDisplayableId, TestConstants.DefaultHomeObjectId,
                                                            TestConstants.DefaultPolicy);
            AuthenticationResultEx ex = new AuthenticationResultEx();

            ex.Result = new AuthenticationResult("Bearer", key.ToString(),
                                                 new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(3599)));
            ex.Result.User = new User
            {
                DisplayableId = TestConstants.DefaultDisplayableId,
                UniqueId      = TestConstants.DefaultUniqueId,
                HomeObjectId  = TestConstants.DefaultHomeObjectId
            };
            ex.Result.FamilyId = "1";
            ex.RefreshToken    = "someRT";
            cache.tokenCacheDictionary[key] = ex;

            MockWebUI webUi = new MockWebUI();

            webUi.MockResult = new AuthorizationResult(AuthorizationStatus.Success,
                                                       TestConstants.DefaultAuthorityHomeTenant + "?code=some-code");

            AuthenticationRequestParameters parameters = new AuthenticationRequestParameters()
            {
                Authenticator        = authenticator,
                ClientKey            = new ClientKey(TestConstants.DefaultClientId),
                Policy               = TestConstants.DefaultPolicy,
                RestrictToSingleUser = TestConstants.DefaultRestrictToSingleUser,
                Scope      = TestConstants.DefaultScope.ToArray(),
                TokenCache = cache
            };

            InteractiveRequest request = new InteractiveRequest(parameters,
                                                                TestConstants.ScopeForAnotherResource.ToArray(),
                                                                new Uri("some://uri"), new PlatformParameters(),
                                                                ex.Result.User, UiOptions.ActAsCurrentUser, "extra=qp", webUi);

            request.PreRunAsync().Wait();
            request.PreTokenRequest().Wait();
        }
        private static bool GetOboOrAppKey(AuthenticationRequestParameters requestParameters, out string key)
        {
            if (requestParameters.ApiId == TelemetryCore.Internal.Events.ApiEvent.ApiIds.AcquireTokenOnBehalfOf)
            {
                key = requestParameters.UserAssertion.AssertionHash;
                return(true);
            }

            if (requestParameters.ApiId == TelemetryCore.Internal.Events.ApiEvent.ApiIds.AcquireTokenForClient)
            {
                key = requestParameters.ClientId + "_AppTokenCache";
                return(true);
            }

            key = null;
            return(false);
        }
Exemple #27
0
        /// <summary>
        /// Some WAM operations fail for work and school accounts when the authority is env/organizations
        /// Chaing the authority to env/common in this case works around this problem.
        ///
        /// https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/3217
        /// </summary>
        private async Task <string> WorkaroundOrganizationsBugAsync(
            AuthenticationRequestParameters authenticationRequestParameters,
            WebAccountProvider webAccountProvider)
        {
            string differentAuthority = null;

            if (string.Equals(authenticationRequestParameters.Authority.TenantId, Constants.OrganizationsTenant)) // /organizations used
            {
                if (webAccountProvider != null && _webAccountProviderFactory.IsOrganizationsProvider(webAccountProvider) ||
                    (await IsDefaultAccountAndAadAsync(authenticationRequestParameters.Account).ConfigureAwait(false)))
                {
                    differentAuthority = authenticationRequestParameters.Authority.GetTenantedAuthority("common");
                }
            }

            return(differentAuthority);
        }
Exemple #28
0
        async Task <MsalAccessTokenCacheItem> ITokenCacheInternal.FindAccessTokenAsync(
            AuthenticationRequestParameters requestParams)
        {
            var logger = requestParams.RequestContext.Logger;

            // no authority passed
            if (requestParams.AuthorityInfo?.CanonicalAuthority == null)
            {
                logger.Warning("No authority provided. Skipping cache lookup ");
                return(null);
            }

            logger.Info("Looking up access token in the cache.");
            IEnumerable <MsalAccessTokenCacheItem> tokenCacheItems = GetAllAccessTokensWithNoLocks(true);

            tokenCacheItems = FilterByHomeAccountTenantOrAssertion(requestParams, tokenCacheItems);
            tokenCacheItems = FilterByTokenType(requestParams, tokenCacheItems);

            // no match found after initial filtering
            if (!tokenCacheItems.Any())
            {
                logger.Info("No matching entry found for user or assertion");
                return(null);
            }

            if (logger.IsLoggingEnabled(LogLevel.Info))
            {
                logger.Info("Matching entry count - " + tokenCacheItems.Count());
            }

            tokenCacheItems = FilterByScopes(requestParams, tokenCacheItems);
            tokenCacheItems = await FilterByEnvironmentAsync(requestParams, tokenCacheItems).ConfigureAwait(false);

            // no match
            if (!tokenCacheItems.Any())
            {
                logger.Info("No tokens found for matching authority, client_id, user and scopes.");
                return(null);
            }

            MsalAccessTokenCacheItem msalAccessTokenCacheItem = GetSingleResult(requestParams, tokenCacheItems);

            msalAccessTokenCacheItem = FilterByKeyId(msalAccessTokenCacheItem, requestParams);

            return(GetUnexpiredAccessTokenOrNull(requestParams, msalAccessTokenCacheItem));
        }
Exemple #29
0
        public void GetRefreshTokenTest()
        {
            TokenCache cache = new TokenCache()
            {
                ClientId = TestConstants.ClientId
            };
            RefreshTokenCacheItem rtItem = new RefreshTokenCacheItem()
            {
                Environment      = TestConstants.ProductionEnvironment,
                ClientId         = TestConstants.ClientId,
                RefreshToken     = "someRT",
                RawClientInfo    = MockHelpers.CreateClientInfo(),
                DisplayableId    = TestConstants.DisplayableId,
                IdentityProvider = TestConstants.IdentityProvider,
                Name             = TestConstants.Name
            };

            rtItem.ClientInfo = ClientInfo.CreateFromJson(rtItem.RawClientInfo);

            RefreshTokenCacheKey rtKey = rtItem.GetRefreshTokenItemKey();

            cache.TokenCacheAccessor.RefreshTokenCacheDictionary[rtKey.ToString()] = JsonHelper.SerializeToJson(rtItem);
            var authParams = new AuthenticationRequestParameters()
            {
                RequestContext = new RequestContext(Guid.Empty, null),
                ClientId       = TestConstants.ClientId,
                Authority      = Authority.CreateAuthority(TestConstants.AuthorityHomeTenant, false),
                Scope          = TestConstants.Scope,
                User           = TestConstants.User
            };

            Assert.IsNotNull(cache.FindRefreshToken(authParams));

            // RT is stored by environment, client id and userIdentifier as index.
            // any change to authority (within same environment), uniqueid and displyableid will not
            // change the outcome of cache look up.
            Assert.IsNotNull(cache.FindRefreshToken(new AuthenticationRequestParameters()
            {
                RequestContext = new RequestContext(Guid.Empty, null),
                ClientId       = TestConstants.ClientId,
                Authority      = Authority.CreateAuthority(TestConstants.AuthorityHomeTenant + "more", false),
                Scope          = TestConstants.Scope,
                User           = TestConstants.User
            }));
        }
Exemple #30
0
        private void DeleteAccessTokensWithIntersectingScopes(
            AuthenticationRequestParameters requestParams,
            IEnumerable <string> environmentAliases,
            string tenantId,
            HashSet <string> scopeSet,
            string homeAccountId,
            string tokenType)
        {
            // delete all cache entries with intersecting scopes.
            // this should not happen but we have this as a safe guard
            // against multiple matches.
            requestParams.RequestContext.Logger.Info("Looking for scopes for the authority in the cache which intersect with " +
                                                     requestParams.Scope.AsSingleString());
            IList <MsalAccessTokenCacheItem> accessTokenItemList = new List <MsalAccessTokenCacheItem>();

            foreach (var accessToken in _accessor.GetAllAccessTokens())
            {
                if (accessToken.ClientId.Equals(ClientId, StringComparison.OrdinalIgnoreCase) &&
                    environmentAliases.Contains(accessToken.Environment) &&
                    string.Equals(accessToken.TokenType ?? "", tokenType ?? "", StringComparison.OrdinalIgnoreCase) &&
                    (accessToken.IsAdfs || accessToken.TenantId.Equals(tenantId, StringComparison.OrdinalIgnoreCase)) &&
                    accessToken.ScopeSet.Overlaps(scopeSet))
                {
                    requestParams.RequestContext.Logger.Verbose("Intersecting scopes found");
                    accessTokenItemList.Add(accessToken);
                }
            }

            requestParams.RequestContext.Logger.Info("Intersecting scope entries count - " + accessTokenItemList.Count);

            if (!requestParams.IsClientCredentialRequest)
            {
                // filter by identifier of the user instead
                accessTokenItemList =
                    accessTokenItemList.Where(
                        item => item.HomeAccountId.Equals(homeAccountId, StringComparison.OrdinalIgnoreCase))
                    .ToList();
                requestParams.RequestContext.Logger.Info("Matching entries after filtering by user - " + accessTokenItemList.Count);
            }

            foreach (var cacheItem in accessTokenItemList)
            {
                _accessor.DeleteAccessToken(cacheItem.GetKey());
            }
        }