diff --git a/IdentityCore/src/cache/accessor/MSIDDefaultTokenCacheAccessor.m b/IdentityCore/src/cache/accessor/MSIDDefaultTokenCacheAccessor.m index fe819dbb3..c05f3e2a2 100644 --- a/IdentityCore/src/cache/accessor/MSIDDefaultTokenCacheAccessor.m +++ b/IdentityCore/src/cache/accessor/MSIDDefaultTokenCacheAccessor.m @@ -783,8 +783,7 @@ - (BOOL)saveAccessTokenWithConfiguration:(MSIDConfiguration *)configuration MSIDAccessToken *accessToken = [factory accessTokenFromResponse:response configuration:configuration]; if (!accessToken) { - MSIDFillAndLogError(error, MSIDErrorInternal, @"Response does not contain an access token", context.correlationId); - return NO; + return YES; } if (![self checkAccountIdentifier:accessToken.accountIdentifier.homeAccountId context:context error:error]) diff --git a/IdentityCore/src/oauth2/MSIDOauth2Factory.m b/IdentityCore/src/oauth2/MSIDOauth2Factory.m index 11b168ff9..dfdb5efa8 100644 --- a/IdentityCore/src/oauth2/MSIDOauth2Factory.m +++ b/IdentityCore/src/oauth2/MSIDOauth2Factory.m @@ -97,11 +97,11 @@ - (BOOL)verifyResponse:(MSIDTokenResponse *)response return NO; } - if (![self verifyAccessToken:response.accessToken]) + if (![self verifyToken:response.accessToken] && ![self verifyToken:response.idToken]) { if (error) { - *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Authentication response received without expected accessToken", nil, nil, nil, context.correlationId, nil, YES); + *error = MSIDCreateError(MSIDErrorDomain, MSIDErrorInternal, @"Authentication response received without expected accessToken and idToken", nil, nil, nil, context.correlationId, nil, YES); } return NO; } @@ -109,9 +109,9 @@ - (BOOL)verifyResponse:(MSIDTokenResponse *)response return YES; } -- (BOOL)verifyAccessToken:(NSString *)accessToken +- (BOOL)verifyToken:(NSString *)token { - return ![NSString msidIsStringNilOrBlank:accessToken]; + return ![NSString msidIsStringNilOrBlank:token]; } #pragma mark - Tokens diff --git a/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.m b/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.m index 4a069f580..12e83202a 100644 --- a/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.m +++ b/IdentityCore/src/requests/sdk/msal/MSIDDefaultTokenResponseValidator.m @@ -43,6 +43,11 @@ - (BOOL)validateTokenResult:(MSIDTokenResult *)tokenResult we'd like to throw an error and specify which scopes were granted and which ones not */ + if (tokenResult.accessToken == nil) + { + return YES; + } + NSOrderedSet *grantedScopes = tokenResult.accessToken.scopes; NSOrderedSet *normalizedGrantedScopes = grantedScopes.normalizedScopeSet; diff --git a/IdentityCore/tests/MSIDOauth2FactoryTests.m b/IdentityCore/tests/MSIDOauth2FactoryTests.m index 786b5641b..e35516263 100644 --- a/IdentityCore/tests/MSIDOauth2FactoryTests.m +++ b/IdentityCore/tests/MSIDOauth2FactoryTests.m @@ -115,7 +115,7 @@ - (void)testVerifyResponse_whenOAuthError_shouldReturnError XCTAssertEqualObjects(error.userInfo[MSIDOAuthErrorKey], @"invalid_grant"); } -- (void)testVerifyResponse_whenNoAccessToken_shouldReturnError +- (void)testVerifyResponse_whenNoAccessTokenAndNoIdToken_shouldReturnError { MSIDOauth2Factory *factory = [MSIDOauth2Factory new]; @@ -129,10 +129,10 @@ - (void)testVerifyResponse_whenNoAccessToken_shouldReturnError XCTAssertFalse(result); XCTAssertEqual(error.domain, MSIDErrorDomain); - XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Authentication response received without expected accessToken"); + XCTAssertEqualObjects(error.userInfo[MSIDErrorDescriptionKey], @"Authentication response received without expected accessToken and idToken"); } -- (void)testVerifyResponse_whenValidResponseWithTokens_shouldReturnNoError +- (void)testVerifyResponse_whenValidResponseWithAccessTokens_shouldReturnNoError { MSIDOauth2Factory *factory = [MSIDOauth2Factory new]; @@ -149,6 +149,23 @@ - (void)testVerifyResponse_whenValidResponseWithTokens_shouldReturnNoError XCTAssertNil(error); } +- (void)testVerifyResponse_whenValidResponseWithIdTokens_shouldReturnNoError +{ + MSIDOauth2Factory *factory = [MSIDOauth2Factory new]; + + NSString *rawClientInfo = [@{ @"uid" : @"1", @"utid" : @"1234-5678-90abcdefg"} msidBase64UrlJson]; + MSIDTokenResponse *response = [[MSIDTokenResponse alloc] initWithJSONDictionary:@{@"id_token":@"fake_id_token", + @"refresh_token":@"fake_refresh_token", + @"client_info":rawClientInfo + } + error:nil]; + NSError *error = nil; + BOOL result = [factory verifyResponse:response context:nil error:&error]; + + XCTAssertTrue(result); + XCTAssertNil(error); +} + #pragma mark - Tokens - (void)testBaseTokenFromResponse_whenNilResponse_shouldReturnNil diff --git a/IdentityCore/tests/integration/MSIDDefaultTokenCacheIntegrationTests.m b/IdentityCore/tests/integration/MSIDDefaultTokenCacheIntegrationTests.m index d27148766..f926ae740 100644 --- a/IdentityCore/tests/integration/MSIDDefaultTokenCacheIntegrationTests.m +++ b/IdentityCore/tests/integration/MSIDDefaultTokenCacheIntegrationTests.m @@ -150,7 +150,7 @@ - (void)testSaveTokensWithRequestParams_withAccessToken_andIntuneEnrolled_should [self setUpEnrollmentIdsCache:YES]; } -- (void)testSaveTokensWithRequestParams_withNilAccessToken_shouldNotSaveToken_returnError +- (void)testSaveTokensWithRequestParams_withNilAccessToken_shouldSaveToken { MSIDTokenResponse *tokenResponse = [MSIDTestTokenResponse v2TokenResponseWithAT:nil RT:@"rt" @@ -167,9 +167,62 @@ - (void)testSaveTokensWithRequestParams_withNilAccessToken_shouldNotSaveToken_re context:nil error:&error]; - XCTAssertNotNil(error); - XCTAssertFalse(result); - XCTAssertEqual(error.code, MSIDErrorInternal); + XCTAssertNil(error); + XCTAssertTrue(result); + + NSArray *idTokens = [MSIDTestCacheAccessorHelper getAllIdTokens:_cacheAccessor]; + XCTAssertNil(error); + + XCTAssertEqual([idTokens count], 1); + XCTAssertEqualObjects([idTokens[0] rawIdToken], tokenResponse.idToken); +} + +- (void)testSaveTokensWithRequestParams_withNilIdToken_shouldSaveToken +{ + MSIDTokenResponse *tokenResponse = [MSIDTestTokenResponse v2TokenResponseWithAT:@"access_token" + RT:@"rt" + scopes:[NSOrderedSet orderedSetWithObjects:DEFAULT_TEST_SCOPE, nil] + idToken:nil + uid:@"uid" + utid:@"utid" + familyId:@"family_id"]; + + NSError *error = nil; + BOOL result = [_cacheAccessor saveTokensWithConfiguration:[MSIDTestConfiguration v2DefaultConfiguration] + response:tokenResponse + factory:[MSIDAADV2Oauth2Factory new] + context:nil + error:&error]; + + XCTAssertNil(error); + XCTAssertTrue(result); + + NSArray *accessTokens = [MSIDTestCacheAccessorHelper getAllDefaultAccessTokens:_cacheAccessor]; + XCTAssertNil(error); + + XCTAssertEqual([accessTokens count], 1); + XCTAssertEqualObjects([accessTokens[0] accessToken], tokenResponse.accessToken); +} + +- (void)testSaveTokensWithRequestParams_withNilAccessTokenAndNilIdToken_shouldNotSaveToken +{ + MSIDTokenResponse *tokenResponse = [MSIDTestTokenResponse v2TokenResponseWithAT:nil + RT:nil + scopes:[NSOrderedSet orderedSetWithObjects:DEFAULT_TEST_SCOPE, nil] + idToken:nil + uid:@"uid" + utid:@"utid" + familyId:@"family_id"]; + + NSError *error = nil; + BOOL result = [_cacheAccessor saveTokensWithConfiguration:[MSIDTestConfiguration v2DefaultConfiguration] + response:tokenResponse + factory:[MSIDAADV2Oauth2Factory new] + context:nil + error:&error]; + + XCTAssertNil(error); + XCTAssertTrue(result); NSError *readError = nil; NSArray *allTokens = [_cacheAccessor allTokensWithContext:nil error:&readError]; diff --git a/IdentityCore/tests/integration/ios/MSIDDefaultSilentTokenRequestTests.m b/IdentityCore/tests/integration/ios/MSIDDefaultSilentTokenRequestTests.m index 039aaee16..50c5a551e 100644 --- a/IdentityCore/tests/integration/ios/MSIDDefaultSilentTokenRequestTests.m +++ b/IdentityCore/tests/integration/ios/MSIDDefaultSilentTokenRequestTests.m @@ -1022,7 +1022,7 @@ - (void)testAcquireTokenSilent_whenAccessTokenInCache_andForceRefreshYES_andNoAT requestScopes:@"user.read tasks.read openid profile offline_access" responseAT:@"" responseRT:@"new rt" - responseID:nil + responseID:@"" responseScope:@"user.read tasks.read" responseClientInfo:differentClientInfo url:DEFAULT_TEST_TOKEN_ENDPOINT_GUID