public void GetExactScopesMatchedAccessTokenTest() { var atItem = Credential.CreateAccessToken( MsalTestConstants.HomeAccountId, MsalTestConstants.ProductionPrefNetworkEnvironment, new Uri(MsalTestConstants.AuthorityTestTenant).GetRealm(), MsalTestConstants.ClientId, ScopeUtils.JoinScopes(MsalTestConstants.Scope), TimeUtils.GetSecondsFromEpochNow(), TimeUtils.GetSecondsFromEpochNow() + MsalCacheV2TestConstants.ValidExpiresIn, TimeUtils.GetSecondsFromEpochNow() + MsalCacheV2TestConstants.ValidExtendedExpiresIn, TheSecret, string.Empty); _storageWorker.WriteCredentials( new List <Credential> { atItem }); using (var httpManager = new MockHttpManager()) { var serviceBundle = ServiceBundle.CreateWithCustomHttpManager(httpManager); var cacheManager = new CacheManager( _storageManager, new AuthenticationRequestParameters { Account = MsalTestConstants.User, // TODO: In MSALC++, the request parameters only really needs the // Authority URI itself since the cache isn't meant to // do ANY network calls. // So it would be great if we could reduce the complexity/dependencies // here and do any of the validated authority cache / instance discovery // outside of the context of the authentication parameters and // cache interaction and just track the authority we're using... // AccountId = MsalTestConstants.HomeAccountId, // Authority = new Uri(MsalTestConstants.AuthorityTestTenant), Authority = Authority.CreateAuthority( serviceBundle, MsalTestConstants.AuthorityTestTenant, false), ClientId = MsalTestConstants.ClientId, Scope = new SortedSet <string>(MsalCacheV2TestConstants.Scope) // todo(mzuber): WHY SORTED SET? }); Assert.IsTrue(cacheManager.TryReadCache(out var tokenResponse, out var accountResponse)); Assert.IsNotNull(tokenResponse); Assert.IsNull(accountResponse); Assert.AreEqual(TheSecret, tokenResponse.AccessToken); } }
public MsalTokenResponse ToMsalTokenResponse() { return(new MsalTokenResponse { AccessToken = AccessToken, ExpiresIn = Convert.ToInt64(DateTime.UtcNow.Subtract(ExpiresOn).TotalSeconds), ExtendedExpiresIn = Convert.ToInt64(DateTime.UtcNow.Subtract(ExtendedExpiresOn).TotalSeconds), Claims = string.Empty, ClientInfo = RawClientInfo, IdToken = IdToken.ToString(), RefreshToken = RefreshToken, Scope = ScopeUtils.JoinScopes(GrantedScopes), TokenType = "whatgoeshere", // TODO: figure out MsalTokenResponse TokenType value(s) }); }
/// <inheritdoc /> public bool TryReadCache(out MsalTokenResponse msalTokenResponse, out IAccount account) { msalTokenResponse = null; account = null; string homeAccountId = _authParameters.Account.HomeAccountId.Identifier; var authority = new Uri(_authParameters.Authority.CanonicalAuthority); string environment = authority.GetEnvironment(); string realm = authority.GetRealm(); string clientId = _authParameters.ClientId; string target = ScopeUtils.JoinScopes(_authParameters.Scope); if (string.IsNullOrWhiteSpace(homeAccountId) || string.IsNullOrWhiteSpace(environment) || string.IsNullOrWhiteSpace(realm) || string.IsNullOrWhiteSpace(clientId) || string.IsNullOrWhiteSpace(target)) { msalTokenResponse = null; account = null; return(false); } var credentialsResponse = _storageManager.ReadCredentials( string.Empty, homeAccountId, environment, realm, clientId, string.Empty, target, new HashSet <CredentialType> { CredentialType.OAuth2AccessToken, CredentialType.OAuth2RefreshToken, CredentialType.OidcIdToken }); if (credentialsResponse.Status.StatusType != OperationStatusType.Success) { // error reading credentials from the cache return(false); } if (!credentialsResponse.Credentials.Any()) { // no credentials found in the cache return(false); } if (credentialsResponse.Credentials.ToList().Count > 3) { // expected to read up to 3 credentials from cache, somehow read more... } Credential accessToken = null; Credential refreshToken = null; Credential idToken = null; foreach (var credential in credentialsResponse.Credentials) { switch (credential.CredentialType) { case CredentialType.OAuth2AccessToken: if (accessToken != null) { // warning, more than one access token read from cache } accessToken = credential; break; case CredentialType.OAuth2RefreshToken: if (refreshToken != null) { // warning, more than one refresh token read from cache } refreshToken = credential; break; case CredentialType.OidcIdToken: if (idToken != null) { // warning, more than one idtoken read from cache } idToken = credential; break; default: // warning unknown credential type break; } } if (idToken == null) { // warning, no id token } if (accessToken == null) { // warning no access token } else if (!IsAccessTokenValid(accessToken)) { DeleteCachedAccessToken( homeAccountId, environment, realm, clientId, target); accessToken = null; } if (accessToken != null) { refreshToken = null; // there's no need to return a refresh token, just the access token } else if (refreshToken == null) { // warning, no valid access token and no refresh token found in cache return(false); } IdToken idTokenJwt = null; if (idToken != null) { idTokenJwt = new IdToken(idToken.Secret); } if (accessToken != null) { var accountResponse = _storageManager.ReadAccount(string.Empty, homeAccountId, environment, realm); if (accountResponse.Status.StatusType != OperationStatusType.Success) { // warning, error reading account from cache } else { account = accountResponse.Account; } if (account == null) { // warning, no account in cache, will still return token if found } } msalTokenResponse = new TokenResponse(idTokenJwt, accessToken, refreshToken).ToMsalTokenResponse(); return(true); }
/// <inheritdoc /> public IAccount CacheTokenResponse(MsalTokenResponse msalTokenResponse) { var tokenResponse = new TokenResponse(msalTokenResponse); string homeAccountId = GetHomeAccountId(tokenResponse); var authority = new Uri(_authParameters.Authority.CanonicalAuthority); string environment = authority.GetEnvironment(); string realm = authority.GetRealm(); string clientId = _authParameters.ClientId; string target = ScopeUtils.JoinScopes(tokenResponse.GrantedScopes); if (string.IsNullOrWhiteSpace(homeAccountId) || string.IsNullOrWhiteSpace(environment) || string.IsNullOrWhiteSpace(realm) || string.IsNullOrWhiteSpace(clientId) || string.IsNullOrWhiteSpace(target)) { // skipping writing to the cache, PK is empty return(null); } var credentialsToWrite = new List <Credential>(); long cachedAt = DateTime.UtcNow.Ticks; // todo: this is probably wrong if (tokenResponse.HasRefreshToken) { credentialsToWrite.Add( Credential.CreateRefreshToken( homeAccountId, environment, clientId, cachedAt, tokenResponse.RefreshToken, string.Empty)); } if (tokenResponse.HasAccessToken) { long expiresOn = tokenResponse.ExpiresOn.Ticks; // todo: this is probably wrong long extendedExpiresOn = tokenResponse.ExtendedExpiresOn.Ticks; // todo: this is probably wrong var accessToken = Credential.CreateAccessToken( homeAccountId, environment, realm, clientId, target, cachedAt, expiresOn, extendedExpiresOn, tokenResponse.AccessToken, string.Empty); if (IsAccessTokenValid(accessToken)) { credentialsToWrite.Add(accessToken); } } var idTokenJwt = tokenResponse.IdToken; if (!idTokenJwt.IsEmpty) { credentialsToWrite.Add( Credential.CreateIdToken( homeAccountId, environment, realm, clientId, cachedAt, idTokenJwt.Raw, string.Empty)); } var status = _storageManager.WriteCredentials(string.Empty, credentialsToWrite); if (status.StatusType != OperationStatusType.Success) { // warning error writing to cache } // if id token jwt is empty, return null string localAccountId = GetLocalAccountId(idTokenJwt); var authorityType = GetAuthorityType(); var account = Microsoft.Identity.Client.CacheV2.Schema.Account.Create( homeAccountId, environment, realm, localAccountId, authorityType, idTokenJwt.PreferredUsername, idTokenJwt.GivenName, idTokenJwt.FamilyName, idTokenJwt.MiddleName, idTokenJwt.Name, idTokenJwt.AlternativeId, tokenResponse.RawClientInfo, string.Empty); status = _storageManager.WriteAccount(string.Empty, account); if (status.StatusType != OperationStatusType.Success) { // warning error writing account to cache } return(account); }