public async Task POP_ShrValidation_Async() { using (var httpManager = new MockHttpManager()) { ConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId) .WithClientSecret(TestConstants.ClientSecret) .WithHttpManager(httpManager) .WithExperimentalFeatures(true) .BuildConcrete(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(ProtectedUrl)); var popConfig = new PoPAuthenticationConfiguration(request); var provider = PoPProviderFactory.GetOrCreateProvider(); httpManager.AddInstanceDiscoveryMockHandler(); httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop"); // Act var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray()) .WithAuthority(TestConstants.AuthorityUtidTenant) .WithProofOfPossession(popConfig) .ExecuteAsync() .ConfigureAwait(false); // access token parsing can be done with MSAL's id token parsing logic var claims = IdToken.Parse(result.AccessToken).ClaimsPrincipal; Assert.IsTrue(!string.IsNullOrEmpty(claims.FindAll("nonce").Single().Value)); AssertSingedHttpRequestClaims(provider, claims); } }
public void IdTokenParsing_B2CToken_OneEmail() { /* * "exp": 1538804860, * "nbf": 1538801260, * "ver": "1.0", * "iss": "https://login.microsoftonline.com/ba6c0d94-a8da-45b2-83ae-33871f9c2dd8/v2.0/", * "sub": "ad020f8e-b1ba-44b2-bd69-c22be86737f5", * "aud": "0a7f52dd-260e-432f-94de-b47828c3f372", * "iat": 1538801260, * "auth_time": 1538801260, * "idp": "live.com", * "name": "MSAL SDK Test", * "oid": "ad020f8e-b1ba-44b2-bd69-c22be86737f5", * "family_name": "SDK Test", * "given_name": "MSAL", * "emails": [ * "*****@*****.**", * ], * "tfp": "B2C_1_Signin", * "at_hash": "Q4O3HDClcaLl7y0uU-bJAg" * */ var addIdToken = TestConstants.CreateB2CTestTokenResponse().IdToken; var parsedToken = IdToken.Parse(addIdToken); Assert.AreEqual("*****@*****.**", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "emails").Value); Assert.AreEqual(ClaimValueTypes.String.ToString(), parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "emails").ValueType); }
internal MsalAccountCacheItem(string environment, MsalTokenResponse response, string preferredUsername, string tenantID) : this() { IdToken idToken = IdToken.Parse(response.IdToken); Init(environment, idToken?.ObjectId, response.ClientInfo, idToken.Name, preferredUsername, tenantID, idToken.GivenName, idToken.FamilyName); }
protected async Task <AuthenticationResult> CacheTokenResponseAndCreateAuthenticationResultAsync(MsalTokenResponse msalTokenResponse) { // developer passed in user object. AuthenticationRequestParameters.RequestContext.Logger.Info("Checking client info returned from the server.."); ClientInfo fromServer = null; if (!AuthenticationRequestParameters.IsClientCredentialRequest && !AuthenticationRequestParameters.IsRefreshTokenRequest && AuthenticationRequestParameters.AuthorityInfo.AuthorityType != AuthorityType.Adfs) { //client_info is not returned from client credential flows because there is no user present. fromServer = ClientInfo.CreateFromJson(msalTokenResponse.ClientInfo); } ValidateAccountIdentifiers(fromServer); IdToken idToken = IdToken.Parse(msalTokenResponse.IdToken); AuthenticationRequestParameters.TenantUpdatedCanonicalAuthority = AuthenticationRequestParameters.Authority.GetTenantedAuthority(idToken?.TenantId); AuthenticationRequestParameters.RequestContext.Logger.Info("Saving Token Response to cache.."); var tuple = await CacheManager.SaveTokenResponseAsync(msalTokenResponse).ConfigureAwait(false); return(new AuthenticationResult(tuple.Item1, tuple.Item2, AuthenticationRequestParameters.RequestContext.CorrelationId)); }
void OnDeserialized(StreamingContext context) { if (RawIdToken != null) { IdToken idToken = IdToken.Parse(RawIdToken); TenantId = idToken.TenantId; User = new User(idToken); } }
private AccessTokenCacheItem SaveTokenResponseToCache() { // developer passed in user object. string msg = "checking client info returned from the server.."; AuthenticationRequestParameters.RequestContext.Logger.Info(msg); AuthenticationRequestParameters.RequestContext.Logger.InfoPii(msg); ClientInfo fromServer = null; if (!AuthenticationRequestParameters.IsClientCredentialRequest) { //client_info is not returned from client credential flows because there is no user present. fromServer = ClientInfo.CreateFromJson(Response.ClientInfo); } if (fromServer != null && AuthenticationRequestParameters.ClientInfo != null) { if (!fromServer.UniqueIdentifier.Equals(AuthenticationRequestParameters.ClientInfo.UniqueIdentifier) || !fromServer.UniqueTenantIdentifier.Equals(AuthenticationRequestParameters.ClientInfo .UniqueTenantIdentifier)) { AuthenticationRequestParameters.RequestContext.Logger.ErrorPii(String.Format( CultureInfo.InvariantCulture, "Returned user identifiers (uid:{0} utid:{1}) does not meatch the sent user identifier (uid:{2} utid:{3})", fromServer.UniqueIdentifier, fromServer.UniqueTenantIdentifier, AuthenticationRequestParameters.ClientInfo.UniqueIdentifier, AuthenticationRequestParameters.ClientInfo.UniqueTenantIdentifier)); AuthenticationRequestParameters.RequestContext.Logger.Error("Returned user identifiers do not match the sent user" + "identifier"); throw new MsalServiceException("user_mismatch", "Returned user identifier does not match the sent user identifier"); } } IdToken idToken = IdToken.Parse(Response.IdToken); AuthenticationRequestParameters.TenantUpdatedCanonicalAuthority = Authority.UpdateTenantId( AuthenticationRequestParameters.Authority.CanonicalAuthority, idToken?.TenantId); if (StoreToCache) { msg = "Saving Token Response to cache.."; AuthenticationRequestParameters.RequestContext.Logger.Info(msg); AuthenticationRequestParameters.RequestContext.Logger.InfoPii(msg); return(TokenCache.SaveAccessAndRefreshToken(AuthenticationRequestParameters, Response)); } return(new AccessTokenCacheItem(AuthenticationRequestParameters.TenantUpdatedCanonicalAuthority, AuthenticationRequestParameters.ClientId, Response)); }
public void PopulateIdentifiers(TokenResponse response) { IdToken idToken = IdToken.Parse(response.IdToken); RawClientInfo = response.ClientInfo; ClientInfo = ClientInfo.CreateFromJson(RawClientInfo); DisplayableId = idToken.PreferredUsername; Name = idToken.Name; IdentityProvider = idToken.Issuer; User = new User(GetUserIdentifier(), DisplayableId, Name, IdentityProvider); }
/// <summary> /// Default constructor. /// </summary> public BaseTokenCacheItem(string authority, string clientId, string policy, TokenResponse response) { if (response.IdToken != null) { RawIdToken = response.IdToken; IdToken idToken = IdToken.Parse(response.IdToken); TenantId = idToken.TenantId; User = new User(idToken); } this.Authority = authority; this.ClientId = clientId; this.Policy = policy; }
private void CreateDerivedProperties() { ScopeSet = Scope.AsSet(); IdToken = IdToken.Parse(RawIdToken); if (!string.IsNullOrEmpty(RawClientInfo)) { // this should only happen for client credentials. ClientInfo = ClientInfo.CreateFromJson(RawClientInfo); } if (IdToken != null) { User = new User(GetUserIdentifier(), IdToken.PreferredUsername, IdToken.Name, IdToken.Issuer); } }
public void IdTokenParsing_AADToken() { /* * "aud": "b6c69a37-df96-4db0-9088-2ab96e1d8215", * "iss": "https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca/v2.0", * "iat": 1538538422, * "nbf": 1538538422, * "exp": 1538542322, * "name": "Cloud IDLAB Basic User", * "oid": "9f4880d8-80ba-4c40-97bc-f7a23c703084", * "preferred_username": "******", * "sub": "Y6YkBdHNNLHNmTKel9KhRz8wrasxdLRFiP14BRPWrn4", * "tid": "f645ad92-e38d-4d1a-b510-d1b09a74a8ca", * "uti": "6nciX02SMki9k73-F1sZAA", * "ver": "2.0" */ var addIdToken = TestConstants.CreateAadTestTokenResponse().IdToken; var parsedToken = IdToken.Parse(addIdToken); CoreAssert.AreEqual("Cloud IDLAB Basic User", parsedToken.Name, parsedToken.ClaimsPrincipal.FindFirst("name").Value); CoreAssert.AreEqual("9f4880d8-80ba-4c40-97bc-f7a23c703084", parsedToken.ObjectId, parsedToken.ClaimsPrincipal.FindFirst("oid").Value); CoreAssert.AreEqual("*****@*****.**", parsedToken.PreferredUsername, parsedToken.ClaimsPrincipal.FindFirst("preferred_username").Value); CoreAssert.AreEqual("Y6YkBdHNNLHNmTKel9KhRz8wrasxdLRFiP14BRPWrn4", parsedToken.Subject, parsedToken.ClaimsPrincipal.FindFirst("sub").Value); CoreAssert.AreEqual("f645ad92-e38d-4d1a-b510-d1b09a74a8ca", parsedToken.TenantId, parsedToken.ClaimsPrincipal.FindFirst("tid").Value); Assert.AreEqual("b6c69a37-df96-4db0-9088-2ab96e1d8215", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "aud").Value); Assert.AreEqual("https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca/v2.0", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "iss").Value); Assert.AreEqual("1538538422", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "iat").Value); Assert.AreEqual("1538538422", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "nbf").Value); Assert.AreEqual("1538542322", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "exp").Value); Assert.AreEqual("Cloud IDLAB Basic User", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "name").Value); Assert.AreEqual("9f4880d8-80ba-4c40-97bc-f7a23c703084", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "oid").Value); Assert.AreEqual("*****@*****.**", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "preferred_username").Value); Assert.AreEqual("Y6YkBdHNNLHNmTKel9KhRz8wrasxdLRFiP14BRPWrn4", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "sub").Value); Assert.AreEqual("f645ad92-e38d-4d1a-b510-d1b09a74a8ca", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "tid").Value); Assert.AreEqual("6nciX02SMki9k73-F1sZAA", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "uti").Value); Assert.AreEqual("2.0", parsedToken.ClaimsPrincipal.Claims.Single(c => c.Type == "ver").Value); Assert.IsTrue(parsedToken.ClaimsPrincipal.Claims.Where(c => (new[] { "nbf", "iat", "exp" }).Contains(c.Type) == true).All(c => c.ValueType == ClaimValueTypes.Integer.ToString())); Assert.IsTrue(parsedToken.ClaimsPrincipal.Claims.Where(c => (new[] { "nbf", "iat", "exp" }).Contains(c.Type) == false).All(c => c.ValueType == ClaimValueTypes.String.ToString())); Assert.IsNull(parsedToken.Upn); Assert.IsNull(parsedToken.FamilyName); Assert.IsNull(parsedToken.GivenName); Assert.IsTrue(parsedToken.ClaimsPrincipal.Claims.All(c => c.Issuer == "https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca/v2.0")); Assert.IsTrue(parsedToken.ClaimsPrincipal.Claims.All(c => c.OriginalIssuer == "https://login.microsoftonline.com/f645ad92-e38d-4d1a-b510-d1b09a74a8ca/v2.0")); }
public void IdTokenParsing_B2CToken_TwoEmails() { /* * { * "sub": "1234567890", * "emails": ["*****@*****.**", "*****@*****.**"], * "iat": 1516239022 * } * */ var addIdToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZW1haWxzIjpbImFAb3V0bG9vay5jb20iLCJiQGhvdG1haWwuY29tIl0sImlhdCI6MTUxNjIzOTAyMn0."; var parsedToken = IdToken.Parse(addIdToken); Assert.AreEqual(2, parsedToken.ClaimsPrincipal.Claims.Where(c => c.Type == "emails").Count()); Assert.IsTrue(parsedToken.ClaimsPrincipal.Claims.Where(c => c.Type == "emails").All(c => (new[] { "*****@*****.**", "*****@*****.**" }).Contains(c.Value))); }
internal MsalAccountCacheItem( string preferredCacheEnv, MsalTokenResponse response, string preferredUsername, string tenantId) : this() { var idToken = IdToken.Parse(response.IdToken); Init( preferredCacheEnv, idToken?.ObjectId, response.ClientInfo, idToken.Name, preferredUsername, tenantId, idToken.GivenName, idToken.FamilyName); }
public void GetSubsetScopesMatchedAccessTokenTest() { TokenCache cache = new TokenCache() { ClientId = TestConstants.ClientId }; AccessTokenCacheItem atItem = new AccessTokenCacheItem() { Authority = TestConstants.AuthorityHomeTenant, ClientId = TestConstants.ClientId, TokenType = "Bearer", ScopeSet = TestConstants.Scope, Scope = TestConstants.Scope.AsSingleString(), ExpiresOnUnixTimestamp = MsalHelpers.DateTimeToUnixTimestamp(DateTime.UtcNow + TimeSpan.FromHours(1)), RawIdToken = MockHelpers.CreateIdToken(TestConstants.UniqueId, TestConstants.DisplayableId), RawClientInfo = MockHelpers.CreateClientInfo(), }; atItem.IdToken = IdToken.Parse(atItem.RawIdToken); atItem.ClientInfo = ClientInfo.CreateFromJson(atItem.RawClientInfo); // create key out of access token cache item and then // set it as the value of the access token. AccessTokenCacheKey atKey = atItem.GetAccessTokenItemKey(); atItem.AccessToken = atKey.ToString(); cache.TokenCacheAccessor.AccessTokenCacheDictionary[atKey.ToString()] = JsonHelper.SerializeToJson(atItem); var param = new AuthenticationRequestParameters() { RequestContext = new RequestContext(Guid.Empty, null), ClientId = TestConstants.ClientId, Authority = Authority.CreateAuthority(TestConstants.AuthorityHomeTenant, false), Scope = new SortedSet <string>(), User = TestConstants.User }; param.Scope.Add("r1/scope1"); AccessTokenCacheItem item = cache.FindAccessToken(param); Assert.IsNotNull(item); Assert.AreEqual(atKey.ToString(), item.AccessToken); }
public void GetExpiredAccessTokenTest() { cache = new TokenCache() { ClientId = TestConstants.ClientId }; AccessTokenCacheItem item = new AccessTokenCacheItem() { Authority = TestConstants.AuthorityHomeTenant, ClientId = TestConstants.ClientId, TokenType = "Bearer", ExpiresOnUnixTimestamp = MsalHelpers.DateTimeToUnixTimestamp(DateTime.UtcNow), RawIdToken = MockHelpers.CreateIdToken(TestConstants.UniqueId, TestConstants.DisplayableId), RawClientInfo = MockHelpers.CreateClientInfo(), ScopeSet = TestConstants.Scope }; item.IdToken = IdToken.Parse(item.RawIdToken); item.ClientInfo = ClientInfo.CreateFromJson(item.RawClientInfo); item.AccessToken = item.GetAccessTokenItemKey().ToString(); cache.TokenCacheAccessor.AccessTokenCacheDictionary[item.GetAccessTokenItemKey().ToString()] = JsonHelper.SerializeToJson(item); cache.TokenCacheAccessor.AccessTokenCacheDictionary[item.GetAccessTokenItemKey().ToString()] = JsonHelper.SerializeToJson(item); Assert.IsNull(cache.FindAccessToken(new AuthenticationRequestParameters() { RequestContext = new RequestContext(Guid.Empty, null), ClientId = TestConstants.ClientId, Authority = Authority.CreateAuthority(TestConstants.AuthorityHomeTenant, false), Scope = TestConstants.Scope, User = new User() { DisplayableId = TestConstants.DisplayableId, Identifier = TestConstants.UserIdentifier } })); }
public async Task POP_NoHttpRequest_Async() { using (var httpManager = new MockHttpManager()) { ConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(TestConstants.ClientId) .WithClientSecret(TestConstants.ClientSecret) .WithHttpManager(httpManager) .WithExperimentalFeatures(true) .BuildConcrete(); // no HTTP method binding, but custom nonce var popConfig = new PoPAuthenticationConfiguration() { Nonce = CustomNonce }; var provider = PoPProviderFactory.GetOrCreateProvider(); httpManager.AddInstanceDiscoveryMockHandler(); httpManager.AddMockHandlerSuccessfulClientCredentialTokenResponseMessage(tokenType: "pop"); // Act var result = await app.AcquireTokenForClient(TestConstants.s_scope.ToArray()) .WithAuthority(TestConstants.AuthorityUtidTenant) .WithProofOfPossession(popConfig) .ExecuteAsync() .ConfigureAwait(false); // access token parsing can be done with MSAL's id token parsing logic var claims = IdToken.Parse(result.AccessToken).ClaimsPrincipal; Assert.AreEqual(CustomNonce, claims.FindAll("nonce").Single().Value); AssertTsAndJwkClaims(provider, claims); Assert.IsFalse(claims.FindAll("m").Any()); Assert.IsFalse(claims.FindAll("u").Any()); Assert.IsFalse(claims.FindAll("p").Any()); } }
public static void PopulateCache(TokenCacheAccessor accessor) { AccessTokenCacheItem item = new AccessTokenCacheItem() { Authority = TestConstants.AuthorityHomeTenant, ClientId = TestConstants.ClientId, TokenType = "Bearer", ExpiresOnUnixTimestamp = MsalHelpers.DateTimeToUnixTimestamp(new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(ValidExpiresIn))), RawIdToken = MockHelpers.CreateIdToken(TestConstants.UniqueId, TestConstants.DisplayableId), RawClientInfo = MockHelpers.CreateClientInfo(), Scope = TestConstants.Scope.AsSingleString(), ScopeSet = TestConstants.Scope }; item.IdToken = IdToken.Parse(item.RawIdToken); item.ClientInfo = ClientInfo.CreateFromJson(item.RawClientInfo); item.AccessToken = item.GetAccessTokenItemKey().ToString(); //add access token accessor.AccessTokenCacheDictionary[item.GetAccessTokenItemKey().ToString()] = JsonHelper.SerializeToJson(item); item = new AccessTokenCacheItem() { Authority = TestConstants.AuthorityGuestTenant, ClientId = TestConstants.ClientId, TokenType = "Bearer", ExpiresOnUnixTimestamp = MsalHelpers.DateTimeToUnixTimestamp(new DateTimeOffset(DateTime.UtcNow + TimeSpan.FromSeconds(ValidExpiresIn))), RawIdToken = MockHelpers.CreateIdToken(TestConstants.UniqueId + "more", TestConstants.DisplayableId), RawClientInfo = MockHelpers.CreateClientInfo(), Scope = TestConstants.ScopeForAnotherResource.AsSingleString(), ScopeSet = TestConstants.ScopeForAnotherResource }; item.IdToken = IdToken.Parse(item.RawIdToken); item.ClientInfo = ClientInfo.CreateFromJson(item.RawClientInfo); item.AccessToken = item.GetAccessTokenItemKey().ToString(); //add another access token accessor.AccessTokenCacheDictionary[item.GetAccessTokenItemKey().ToString()] = JsonHelper.SerializeToJson(item); AddRefreshTokenToCache(accessor, TestConstants.Uid, TestConstants.Utid, TestConstants.Name); }
async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem, Account> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { response.Log(requestParams.RequestContext.Logger, LogLevel.Verbose); MsalAccessTokenCacheItem msalAccessTokenCacheItem = null; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; MsalAccountCacheItem msalAccountCacheItem = null; IdToken idToken = IdToken.Parse(response.IdToken); if (idToken == null) { requestParams.RequestContext.Logger.Info("ID Token not present in response. "); } var tenantId = GetTenantId(idToken, requestParams); bool isAdfsAuthority = requestParams.AuthorityInfo.AuthorityType == AuthorityType.Adfs; string preferredUsername = GetPreferredUsernameFromIdToken(isAdfsAuthority, idToken); string username = isAdfsAuthority ? idToken?.Upn : preferredUsername; string homeAccountId = GetHomeAccountId(requestParams, response, idToken); string suggestedWebCacheKey = SuggestedWebCacheKeyFactory.GetKeyFromResponse(requestParams, homeAccountId); // Do a full instance discovery when saving tokens (if not cached), // so that the PreferredNetwork environment is up to date. var instanceDiscoveryMetadata = await ServiceBundle.InstanceDiscoveryManager .GetMetadataEntryAsync( requestParams.Authority.AuthorityInfo, requestParams.RequestContext) .ConfigureAwait(false); #region Create Cache Objects if (!string.IsNullOrEmpty(response.AccessToken)) { msalAccessTokenCacheItem = new MsalAccessTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.AppConfig.ClientId, response, tenantId, homeAccountId, requestParams.AuthenticationScheme.KeyId) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash, IsAdfs = isAdfsAuthority }; } if (!string.IsNullOrEmpty(response.RefreshToken)) { msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.AppConfig.ClientId, response, homeAccountId); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } } Dictionary <string, string> wamAccountIds = GetWamAccountIds(requestParams, response); Account account; if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.AppConfig.ClientId, response, tenantId, homeAccountId) { IsAdfs = isAdfsAuthority }; msalAccountCacheItem = new MsalAccountCacheItem( instanceDiscoveryMetadata.PreferredCache, response.ClientInfo, homeAccountId, idToken, preferredUsername, tenantId, wamAccountIds); } #endregion account = new Account( homeAccountId, username, instanceDiscoveryMetadata.PreferredNetwork, wamAccountIds); requestParams.RequestContext.Logger.Verbose("[SaveTokenResponseAsync] Entering token cache semaphore. "); await _semaphoreSlim.WaitAsync().ConfigureAwait(false); requestParams.RequestContext.Logger.Verbose("[SaveTokenResponseAsync] Entered token cache semaphore. "); try { #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete try { ITokenCacheInternal tokenCacheInternal = this; if (tokenCacheInternal.IsTokenCacheSerialized()) { var args = new TokenCacheNotificationArgs( this, ClientId, account, hasStateChanged: true, tokenCacheInternal.IsApplicationCache, hasTokens: tokenCacheInternal.HasTokensNoLocks(), requestParams.RequestContext.UserCancellationToken, suggestedCacheKey: suggestedWebCacheKey); Stopwatch sw = Stopwatch.StartNew(); await tokenCacheInternal.OnBeforeAccessAsync(args).ConfigureAwait(false); await tokenCacheInternal.OnBeforeWriteAsync(args).ConfigureAwait(false); requestParams.RequestContext.ApiEvent.DurationInCacheInMs += sw.ElapsedMilliseconds; } if (msalAccessTokenCacheItem != null) { requestParams.RequestContext.Logger.Info("Saving AT in cache and removing overlapping ATs..."); DeleteAccessTokensWithIntersectingScopes( requestParams, instanceDiscoveryMetadata.Aliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId, msalAccessTokenCacheItem.TokenType); _accessor.SaveAccessToken(msalAccessTokenCacheItem); } if (idToken != null) { requestParams.RequestContext.Logger.Info("Saving Id Token and Account in cache ..."); _accessor.SaveIdToken(msalIdTokenCacheItem); MergeWamAccountIds(msalAccountCacheItem); _accessor.SaveAccount(msalAccountCacheItem); } // if server returns the refresh token back, save it in the cache. if (msalRefreshTokenCacheItem != null) { requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.AppConfig.ClientId, instanceDiscoveryMetadata.PreferredCache, response.FamilyId); // Do not save RT in ADAL cache for client credentials flow or B2C if (ServiceBundle.Config.LegacyCacheCompatibilityEnabled && !requestParams.IsClientCredentialRequest && requestParams.AuthorityInfo.AuthorityType != AuthorityType.B2C) { var tenatedAuthority = Authority.CreateAuthorityWithTenant(requestParams.AuthorityInfo, tenantId); var authorityWithPreferredCache = Authority.CreateAuthorityWithEnvironment( tenatedAuthority.AuthorityInfo, instanceDiscoveryMetadata.PreferredCache); CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, authorityWithPreferredCache.AuthorityInfo.CanonicalAuthority, msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { ITokenCacheInternal tokenCacheInternal = this; if (tokenCacheInternal.IsTokenCacheSerialized()) { var args = new TokenCacheNotificationArgs( this, ClientId, account, hasStateChanged: true, tokenCacheInternal.IsApplicationCache, tokenCacheInternal.HasTokensNoLocks(), requestParams.RequestContext.UserCancellationToken, suggestedCacheKey: suggestedWebCacheKey); Stopwatch sw = Stopwatch.StartNew(); await tokenCacheInternal.OnAfterAccessAsync(args).ConfigureAwait(false); requestParams.RequestContext.ApiEvent.DurationInCacheInMs += sw.ElapsedMilliseconds; } #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = false; #pragma warning restore CS0618 // Type or member is obsolete } return(Tuple.Create(msalAccessTokenCacheItem, msalIdTokenCacheItem, account)); } finally { _semaphoreSlim.Release(); requestParams.RequestContext.Logger.Verbose("[SaveTokenResponseAsync] Released token cache semaphore. "); } }
public void GetUsersTest() { PublicClientApplication app = new PublicClientApplication(TestConstants.ClientId); IEnumerable <IUser> users = app.Users; Assert.IsNotNull(users); Assert.IsFalse(users.Any()); cache = new TokenCache() { ClientId = TestConstants.ClientId }; app.UserTokenCache = cache; TokenCacheHelper.PopulateCache(cache.TokenCacheAccessor); users = app.Users; Assert.IsNotNull(users); Assert.AreEqual(1, users.Count()); AccessTokenCacheItem item = new AccessTokenCacheItem() { Authority = TestConstants.AuthorityHomeTenant, ClientId = TestConstants.ClientId, TokenType = "Bearer", ExpiresOnUnixTimestamp = MsalHelpers.DateTimeToUnixTimestamp((DateTime.UtcNow + TimeSpan.FromSeconds(3600))), RawIdToken = MockHelpers.CreateIdToken(TestConstants.UniqueId, TestConstants.DisplayableId), RawClientInfo = MockHelpers.CreateClientInfo(), ScopeSet = TestConstants.Scope }; item.IdToken = IdToken.Parse(item.RawIdToken); item.ClientInfo = ClientInfo.CreateFromJson(item.RawClientInfo); item.AccessToken = item.GetAccessTokenItemKey().ToString(); cache.TokenCacheAccessor.AccessTokenCacheDictionary[item.GetAccessTokenItemKey().ToString()] = JsonHelper.SerializeToJson(item); // another cache entry for different uid. user count should be 2. RefreshTokenCacheItem rtItem = new RefreshTokenCacheItem() { Environment = TestConstants.ProductionEnvironment, ClientId = TestConstants.ClientId, RefreshToken = "someRT", RawClientInfo = MockHelpers.CreateClientInfo(TestConstants.Uid + "more", TestConstants.Utid), DisplayableId = TestConstants.DisplayableId, IdentityProvider = TestConstants.IdentityProvider, Name = TestConstants.Name }; rtItem.ClientInfo = ClientInfo.CreateFromJson(rtItem.RawClientInfo); cache.TokenCacheAccessor.RefreshTokenCacheDictionary[rtItem.GetRefreshTokenItemKey().ToString()] = JsonHelper.SerializeToJson(rtItem); Assert.AreEqual(2, cache.TokenCacheAccessor.RefreshTokenCacheDictionary.Count); users = app.Users; Assert.IsNotNull(users); Assert.AreEqual(2, users.Count()); // another cache entry for different environment. user count should still be 2. Sovereign cloud user must not be returned rtItem = new RefreshTokenCacheItem() { Environment = TestConstants.SovereignEnvironment, ClientId = TestConstants.ClientId, RefreshToken = "someRT", RawClientInfo = MockHelpers.CreateClientInfo(TestConstants.Uid + "more1", TestConstants.Utid), DisplayableId = TestConstants.DisplayableId, IdentityProvider = TestConstants.IdentityProvider, Name = TestConstants.Name }; rtItem.ClientInfo = ClientInfo.CreateFromJson(rtItem.RawClientInfo); cache.TokenCacheAccessor.RefreshTokenCacheDictionary[rtItem.GetRefreshTokenItemKey().ToString()] = JsonHelper.SerializeToJson(rtItem); Assert.AreEqual(3, cache.TokenCacheAccessor.RefreshTokenCacheDictionary.Count); users = app.Users; Assert.IsNotNull(users); Assert.AreEqual(2, users.Count()); }
async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { MsalAccessTokenCacheItem msalAccessTokenCacheItem = null; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; MsalAccountCacheItem msalAccountCacheItem = null; IdToken idToken = IdToken.Parse(response.IdToken); var tenantId = Authority .CreateAuthority(requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo.CanonicalAuthority) .TenantId; bool isAdfsAuthority = requestParams.AuthorityInfo.AuthorityType == AuthorityType.Adfs; string preferredUsername = GetPreferredUsernameFromIdToken(isAdfsAuthority, idToken); string username = isAdfsAuthority ? idToken?.Upn : preferredUsername; string homeAccountId = GetHomeAccountId(requestParams, response, idToken); // Do a full instance discovery when saving tokens (if not cached), // so that the PreferredNetwork environment is up to date. var instanceDiscoveryMetadata = await ServiceBundle.InstanceDiscoveryManager .GetMetadataEntryAsync( requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo.CanonicalAuthority, requestParams.RequestContext) .ConfigureAwait(false); #region Create Cache Objects if (!string.IsNullOrEmpty(response.AccessToken)) { msalAccessTokenCacheItem = new MsalAccessTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, tenantId, homeAccountId, requestParams.AuthenticationScheme.KeyId) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash, IsAdfs = isAdfsAuthority }; } if (!string.IsNullOrEmpty(response.RefreshToken)) { msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, homeAccountId); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } } if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, tenantId, homeAccountId) { IsAdfs = isAdfsAuthority }; msalAccountCacheItem = new MsalAccountCacheItem( instanceDiscoveryMetadata.PreferredCache, response.ClientInfo, homeAccountId, idToken, preferredUsername, tenantId); } #endregion Account account = new Account( homeAccountId, username, instanceDiscoveryMetadata.PreferredCache); await _semaphoreSlim.WaitAsync().ConfigureAwait(false); try { var args = new TokenCacheNotificationArgs( this, ClientId, account, hasStateChanged: true, (this as ITokenCacheInternal).IsApplicationCache, hasTokens: (this as ITokenCacheInternal).HasTokensNoLocks(), requestParams.SuggestedWebAppCacheKey); #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete try { await(this as ITokenCacheInternal).OnBeforeAccessAsync(args).ConfigureAwait(false); await(this as ITokenCacheInternal).OnBeforeWriteAsync(args).ConfigureAwait(false); if (msalAccessTokenCacheItem != null) { requestParams.RequestContext.Logger.Info("Saving AT in cache and removing overlapping ATs..."); DeleteAccessTokensWithIntersectingScopes( requestParams, instanceDiscoveryMetadata.Aliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId, msalAccessTokenCacheItem.TokenType); _accessor.SaveAccessToken(msalAccessTokenCacheItem); } if (idToken != null) { requestParams.RequestContext.Logger.Info("Saving Id Token and Account in cache ..."); _accessor.SaveIdToken(msalIdTokenCacheItem); _accessor.SaveAccount(msalAccountCacheItem); } // if server returns the refresh token back, save it in the cache. if (msalRefreshTokenCacheItem != null) { requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.ClientId, instanceDiscoveryMetadata.PreferredCache, response.FamilyId); // Do not save RT in ADAL cache for confidential client or B2C if (!requestParams.IsClientCredentialRequest && requestParams.AuthorityInfo.AuthorityType != AuthorityType.B2C) { var authorityWithPreferredCache = Authority.CreateAuthorityWithEnvironment( requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo, instanceDiscoveryMetadata.PreferredCache); CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, authorityWithPreferredCache.AuthorityInfo.CanonicalAuthority, msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { var args2 = new TokenCacheNotificationArgs( this, ClientId, account, hasStateChanged: true, (this as ITokenCacheInternal).IsApplicationCache, (this as ITokenCacheInternal).HasTokensNoLocks(), requestParams.SuggestedWebAppCacheKey); await(this as ITokenCacheInternal).OnAfterAccessAsync(args2).ConfigureAwait(false); #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = false; #pragma warning restore CS0618 // Type or member is obsolete } return(Tuple.Create(msalAccessTokenCacheItem, msalIdTokenCacheItem)); } finally { _semaphoreSlim.Release(); } }
async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { var tenantId = Authority .CreateAuthority(ServiceBundle, requestParams.TenantUpdatedCanonicalAuthority) .GetTenantId(); IdToken idToken = IdToken.Parse(response.IdToken); // The preferred_username value cannot be null or empty in order to comply with the ADAL/MSAL Unified cache schema. // It will be set to "preferred_username not in idtoken" var preferredUsername = !string.IsNullOrWhiteSpace(idToken?.PreferredUsername) ? idToken.PreferredUsername : NullPreferredUsernameDisplayLabel; var instanceDiscoveryMetadataEntry = GetCachedAuthorityMetaData(requestParams.TenantUpdatedCanonicalAuthority); var environmentAliases = GetEnvironmentAliases( requestParams.TenantUpdatedCanonicalAuthority, instanceDiscoveryMetadataEntry); var preferredEnvironmentHost = GetPreferredEnvironmentHost( requestParams.AuthorityInfo.Host, instanceDiscoveryMetadataEntry); var msalAccessTokenCacheItem = new MsalAccessTokenCacheItem(preferredEnvironmentHost, requestParams.ClientId, response, tenantId) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash }; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( preferredEnvironmentHost, requestParams.ClientId, response, tenantId); } await _semaphoreSlim.WaitAsync().ConfigureAwait(false); try { try { var args = new TokenCacheNotificationArgs { TokenCache = new NoLockTokenCacheProxy(this), ClientId = ClientId, Account = msalAccessTokenCacheItem.HomeAccountId != null ? new Account(msalAccessTokenCacheItem.HomeAccountId, preferredUsername, preferredEnvironmentHost) : null, HasStateChanged = true }; #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete await OnBeforeAccessAsync(args).ConfigureAwait(false); try { await OnBeforeWriteAsync(args).ConfigureAwait(false); DeleteAccessTokensWithIntersectingScopes( requestParams, environmentAliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId); _accessor.SaveAccessToken(msalAccessTokenCacheItem); if (idToken != null) { _accessor.SaveIdToken(msalIdTokenCacheItem); var msalAccountCacheItem = new MsalAccountCacheItem( preferredEnvironmentHost, response, preferredUsername, tenantId); _accessor.SaveAccount(msalAccountCacheItem); } // if server returns the refresh token back, save it in the cache. if (response.RefreshToken != null) { msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( preferredEnvironmentHost, requestParams.ClientId, response); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.ClientId, preferredEnvironmentHost, response.FamilyId); // save RT in ADAL cache for public clients // do not save RT in ADAL cache for MSAL B2C scenarios if (!requestParams.IsClientCredentialRequest && !requestParams.AuthorityInfo.AuthorityType.Equals(AuthorityType.B2C)) { CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, Authority.CreateAuthorityUriWithHost( requestParams.TenantUpdatedCanonicalAuthority, preferredEnvironmentHost), msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { await OnAfterAccessAsync(args).ConfigureAwait(false); } return(Tuple.Create(msalAccessTokenCacheItem, msalIdTokenCacheItem)); } finally { #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = false; #pragma warning restore CS0618 // Type or member is obsolete } } finally { _semaphoreSlim.Release(); } }
async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { var tenantId = Authority .CreateAuthority(ServiceBundle, requestParams.TenantUpdatedCanonicalAuthority) .GetTenantId(); bool isAdfsAuthority = requestParams.AuthorityInfo.AuthorityType == AuthorityType.Adfs; IdToken idToken = IdToken.Parse(response.IdToken); string subject = idToken?.Subject; if (idToken != null && string.IsNullOrEmpty(subject)) { requestParams.RequestContext.Logger.Warning("Subject not present in Id token"); } string preferredUsername; // The preferred_username value cannot be null or empty in order to comply with the ADAL/MSAL Unified cache schema. // It will be set to "preferred_username not in idtoken" if (idToken == null) { preferredUsername = NullPreferredUsernameDisplayLabel; } else if (string.IsNullOrWhiteSpace(idToken.PreferredUsername)) { if (isAdfsAuthority) { //The direct to adfs scenario does not return preferred_username in the id token so it needs to be set to the upn preferredUsername = !string.IsNullOrEmpty(idToken.Upn) ? idToken.Upn : NullPreferredUsernameDisplayLabel; } else { preferredUsername = NullPreferredUsernameDisplayLabel; } } else { preferredUsername = idToken.PreferredUsername; } var instanceDiscoveryMetadataEntry = GetCachedAuthorityMetaData(requestParams.TenantUpdatedCanonicalAuthority); var environmentAliases = GetEnvironmentAliases( requestParams.TenantUpdatedCanonicalAuthority, instanceDiscoveryMetadataEntry); var preferredEnvironmentHost = GetPreferredEnvironmentHost( requestParams.AuthorityInfo.Host, instanceDiscoveryMetadataEntry); var msalAccessTokenCacheItem = new MsalAccessTokenCacheItem(preferredEnvironmentHost, requestParams.ClientId, response, tenantId, subject) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash, IsAdfs = isAdfsAuthority }; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( preferredEnvironmentHost, requestParams.ClientId, response, tenantId, subject) { IsAdfs = isAdfsAuthority }; } await _semaphoreSlim.WaitAsync().ConfigureAwait(false); try { try { Account account = null; string username = isAdfsAuthority ? idToken?.Upn : preferredUsername; if (msalAccessTokenCacheItem.HomeAccountId != null) { account = new Account( msalAccessTokenCacheItem.HomeAccountId, username, preferredEnvironmentHost); } var args = new TokenCacheNotificationArgs(this, ClientId, account, true); #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete await OnBeforeAccessAsync(args).ConfigureAwait(false); try { await OnBeforeWriteAsync(args).ConfigureAwait(false); DeleteAccessTokensWithIntersectingScopes( requestParams, environmentAliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId); _accessor.SaveAccessToken(msalAccessTokenCacheItem); if (idToken != null) { _accessor.SaveIdToken(msalIdTokenCacheItem); var msalAccountCacheItem = new MsalAccountCacheItem( preferredEnvironmentHost, response, preferredUsername, tenantId); //The ADFS direct scenrio does not return client info so the home account id is acquired from the subject if (isAdfsAuthority && String.IsNullOrEmpty(msalAccountCacheItem.HomeAccountId)) { msalAccountCacheItem.HomeAccountId = idToken.Subject; } _accessor.SaveAccount(msalAccountCacheItem); } // if server returns the refresh token back, save it in the cache. if (response.RefreshToken != null) { msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( preferredEnvironmentHost, requestParams.ClientId, response, subject); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.ClientId, preferredEnvironmentHost, response.FamilyId); // save RT in ADAL cache for public clients // do not save RT in ADAL cache for MSAL B2C scenarios if (!requestParams.IsClientCredentialRequest && !requestParams.AuthorityInfo.AuthorityType.Equals(AuthorityType.B2C)) { CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, Authority.CreateAuthorityUriWithHost( requestParams.TenantUpdatedCanonicalAuthority, preferredEnvironmentHost), msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { await OnAfterAccessAsync(args).ConfigureAwait(false); } return(Tuple.Create(msalAccessTokenCacheItem, msalIdTokenCacheItem)); } finally { #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = false; #pragma warning restore CS0618 // Type or member is obsolete } } finally { _semaphoreSlim.Release(); } }
public void NoCacheLookup() { Authority authority = Authority.CreateAuthority(TestConstants.AuthorityHomeTenant, false); cache = new TokenCache() { ClientId = TestConstants.ClientId }; AccessTokenCacheItem atItem = new AccessTokenCacheItem() { Authority = TestConstants.AuthorityHomeTenant, ClientId = TestConstants.ClientId, RawIdToken = MockHelpers.CreateIdToken(TestConstants.UniqueId, TestConstants.DisplayableId), RawClientInfo = MockHelpers.CreateClientInfo(), TokenType = "Bearer", ExpiresOnUnixTimestamp = MsalHelpers.DateTimeToUnixTimestamp(DateTime.UtcNow + TimeSpan.FromSeconds(3599)), ScopeSet = TestConstants.Scope }; atItem.IdToken = IdToken.Parse(atItem.RawIdToken); atItem.ClientInfo = ClientInfo.CreateFromJson(atItem.RawClientInfo); AccessTokenCacheKey atKey = atItem.GetAccessTokenItemKey(); atItem.AccessToken = atKey.ToString(); cache.TokenCacheAccessor.AccessTokenCacheDictionary[atKey.ToString()] = JsonHelper.SerializeToJson(atItem); MockWebUI ui = new MockWebUI() { MockResult = new AuthorizationResult(AuthorizationStatus.Success, TestConstants.AuthorityHomeTenant + "?code=some-code") }; //add mock response for tenant endpoint discovery HttpMessageHandlerFactory.AddMockHandler(new MockHttpMessageHandler { Method = HttpMethod.Get, ResponseMessage = MockHelpers.CreateOpenIdConfigurationResponse(TestConstants.AuthorityHomeTenant) }); MockHttpMessageHandler mockHandler = new MockHttpMessageHandler(); mockHandler.Method = HttpMethod.Post; mockHandler.ResponseMessage = MockHelpers.CreateSuccessTokenResponseMessage(); HttpMessageHandlerFactory.AddMockHandler(mockHandler); AuthenticationRequestParameters parameters = new AuthenticationRequestParameters() { Authority = authority, ClientId = TestConstants.ClientId, Scope = TestConstants.Scope, TokenCache = cache, RequestContext = new RequestContext(Guid.Empty, null) }; parameters.RedirectUri = new Uri("some://uri"); parameters.ExtraQueryParameters = "extra=qp"; InteractiveRequest request = new InteractiveRequest(parameters, TestConstants.ScopeForAnotherResource.ToArray(), TestConstants.DisplayableId, UIBehavior.SelectAccount, ui); Task <AuthenticationResult> task = request.RunAsync(); task.Wait(); AuthenticationResult result = task.Result; Assert.IsNotNull(result); Assert.AreEqual(1, cache.TokenCacheAccessor.RefreshTokenCacheDictionary.Count); Assert.AreEqual(2, cache.TokenCacheAccessor.AccessTokenCacheDictionary.Count); Assert.AreEqual(result.AccessToken, "some-access-token"); Assert.IsTrue(HttpMessageHandlerFactory.IsMocksQueueEmpty, "All mocks should have been consumed"); Assert.IsNotNull(_myReceiver.EventsReceived.Find(anEvent => // Expect finding such an event anEvent[EventBase.EventNameKey].EndsWith("ui_event") && anEvent[UiEvent.UserCancelledKey] == "false")); Assert.IsNotNull(_myReceiver.EventsReceived.Find(anEvent => // Expect finding such an event anEvent[EventBase.EventNameKey].EndsWith("api_event") && anEvent[ApiEvent.UiBehaviorKey] == "select_account")); }
async Task <Tuple <MsalAccessTokenCacheItem, MsalIdTokenCacheItem> > ITokenCacheInternal.SaveTokenResponseAsync( AuthenticationRequestParameters requestParams, MsalTokenResponse response) { var tenantId = Authority .CreateAuthority(requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo.CanonicalAuthority) .GetTenantId(); bool isAdfsAuthority = requestParams.AuthorityInfo.AuthorityType == AuthorityType.Adfs; IdToken idToken = IdToken.Parse(response.IdToken); string subject = idToken?.Subject; if (idToken != null && string.IsNullOrEmpty(subject)) { requestParams.RequestContext.Logger.Warning("Subject not present in Id token"); } string preferredUsername = GetPreferredUsernameFromIdToken(isAdfsAuthority, idToken); // Do a full instance discovery when saving tokens (if not cached), // so that the PreferredNetwork environment is up to date. var instanceDiscoveryMetadata = await ServiceBundle.InstanceDiscoveryManager .GetMetadataEntryAsync( requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo.CanonicalAuthority, requestParams.RequestContext) .ConfigureAwait(false); var msalAccessTokenCacheItem = new MsalAccessTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, tenantId, subject, requestParams.AuthenticationScheme.KeyId) { UserAssertionHash = requestParams.UserAssertion?.AssertionHash, IsAdfs = isAdfsAuthority }; MsalRefreshTokenCacheItem msalRefreshTokenCacheItem = null; MsalIdTokenCacheItem msalIdTokenCacheItem = null; if (idToken != null) { msalIdTokenCacheItem = new MsalIdTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, tenantId, subject) { IsAdfs = isAdfsAuthority }; } await _semaphoreSlim.WaitAsync().ConfigureAwait(false); try { try { Account account = null; string username = isAdfsAuthority ? idToken?.Upn : preferredUsername; if (msalAccessTokenCacheItem.HomeAccountId != null) { account = new Account( msalAccessTokenCacheItem.HomeAccountId, username, instanceDiscoveryMetadata.PreferredCache); } var args = new TokenCacheNotificationArgs(this, ClientId, account, true, (this as ITokenCacheInternal).IsApplicationCache); #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = true; #pragma warning restore CS0618 // Type or member is obsolete await(this as ITokenCacheInternal).OnBeforeAccessAsync(args).ConfigureAwait(false); try { await(this as ITokenCacheInternal).OnBeforeWriteAsync(args).ConfigureAwait(false); DeleteAccessTokensWithIntersectingScopes( requestParams, instanceDiscoveryMetadata.Aliases, tenantId, msalAccessTokenCacheItem.ScopeSet, msalAccessTokenCacheItem.HomeAccountId, msalAccessTokenCacheItem.TokenType); _accessor.SaveAccessToken(msalAccessTokenCacheItem); if (idToken != null) { _accessor.SaveIdToken(msalIdTokenCacheItem); var msalAccountCacheItem = new MsalAccountCacheItem( instanceDiscoveryMetadata.PreferredCache, response, preferredUsername, tenantId); //The ADFS direct scenario does not return client info so the home account id is acquired from the subject if (isAdfsAuthority && String.IsNullOrEmpty(msalAccountCacheItem.HomeAccountId)) { msalAccountCacheItem.HomeAccountId = idToken.Subject; } _accessor.SaveAccount(msalAccountCacheItem); } // if server returns the refresh token back, save it in the cache. if (response.RefreshToken != null) { msalRefreshTokenCacheItem = new MsalRefreshTokenCacheItem( instanceDiscoveryMetadata.PreferredCache, requestParams.ClientId, response, subject); if (!_featureFlags.IsFociEnabled) { msalRefreshTokenCacheItem.FamilyId = null; } requestParams.RequestContext.Logger.Info("Saving RT in cache..."); _accessor.SaveRefreshToken(msalRefreshTokenCacheItem); } UpdateAppMetadata(requestParams.ClientId, instanceDiscoveryMetadata.PreferredCache, response.FamilyId); // save RT in ADAL cache for public clients // do not save RT in ADAL cache for MSAL B2C scenarios if (!requestParams.IsClientCredentialRequest && !requestParams.AuthorityInfo.AuthorityType.Equals(AuthorityType.B2C)) { var authorityWithPrefferedCache = Authority.CreateAuthorityWithEnvironment( requestParams.TenantUpdatedCanonicalAuthority.AuthorityInfo, instanceDiscoveryMetadata.PreferredCache); CacheFallbackOperations.WriteAdalRefreshToken( Logger, LegacyCachePersistence, msalRefreshTokenCacheItem, msalIdTokenCacheItem, authorityWithPrefferedCache.AuthorityInfo.CanonicalAuthority, msalIdTokenCacheItem.IdToken.ObjectId, response.Scope); } } finally { await(this as ITokenCacheInternal).OnAfterAccessAsync(args).ConfigureAwait(false); } return(Tuple.Create(msalAccessTokenCacheItem, msalIdTokenCacheItem)); } finally { #pragma warning disable CS0618 // Type or member is obsolete HasStateChanged = false; #pragma warning restore CS0618 // Type or member is obsolete } } finally { _semaphoreSlim.Release(); } }
internal MsalIdTokenCacheItem() { CredentialType = StorageJsonValues.CredentialTypeIdToken; idTokenLazy = new Lazy <IdToken>(() => IdToken.Parse(Secret)); }