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); }
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); }
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; }
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)); } }
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); }
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); } } }
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); } }
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)); } }
/// <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); }
/// <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); } }
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); } }
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"); }
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); } }
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); }
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); }
/// <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); }
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)); }
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 })); }
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()); } }