FIRVerifyPasswordResponseTests.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import <XCTest/XCTest.h>
  17. #import "FIRAuthErrors.h"
  18. #import "FIRAuthBackend.h"
  19. #import "FIRVerifyPasswordRequest.h"
  20. #import "FIRVerifyPasswordResponse.h"
  21. #import "FIRFakeBackendRPCIssuer.h"
  22. /** @var kTestPassword
  23. @brief Testing user password.
  24. */
  25. static NSString *const kTestPassword = @"testpassword";
  26. /** @var kTestAPIKey
  27. @brief Fake API key used for testing.
  28. */
  29. static NSString *const kTestAPIKey = @"_test_API_key_";
  30. /** @var kLocalIDKey
  31. @brief The name of the 'localID' property in the response.
  32. */
  33. static NSString *const kLocalIDKey = @"localId";
  34. /** @var kTestLocalID
  35. @brief The fake localID for testing the response.
  36. */
  37. static NSString *const kTestLocalID = @"testLocalId";
  38. /** @var kEmailKey
  39. @brief The name of the 'email' property in the response.
  40. */
  41. static NSString *const kEmailKey = @"email";
  42. /** @var kTestEmail
  43. @brief Fake user email for testing the response.
  44. */
  45. static NSString *const kTestEmail = @"test@gmail.com";
  46. /** @var kDisplayNameKey
  47. @brief The name of the 'displayName' property in the response.
  48. */
  49. static NSString *const kDisplayNameKey = @"displayName";
  50. /** @var kTestDisplayName
  51. @brief Fake displayName for testing the response.
  52. */
  53. static NSString *const kTestDisplayName = @"testDisplayName";
  54. /** @var kIDTokenKey
  55. @brief The name of the "IDToken" property in the response.
  56. */
  57. static NSString *const kIDTokenKey = @"idToken";
  58. /** @var kTestIDToken
  59. @brief Testing ID token for verifying assertion.
  60. */
  61. static NSString *const kTestIDToken = @"ID_TOKEN";
  62. /** @var kExpiresInKey
  63. @brief The name of the "expiresIn" property in the response.
  64. */
  65. static NSString *const kExpiresInKey = @"expiresIn";
  66. /** @var kTestExpiresIn
  67. @brief Fake token expiration time.
  68. */
  69. static NSString *const kTestExpiresIn = @"12345";
  70. /** @var kRefreshTokenKey
  71. @brief The name of the "refreshToken" property in the response.
  72. */
  73. static NSString *const kRefreshTokenKey = @"refreshToken";
  74. /** @var kTestRefreshToken
  75. @brief Fake refresh token.
  76. */
  77. static NSString *const kTestRefreshToken = @"REFRESH_TOKEN";
  78. /** @var kOperationNotAllowedErrorMessage
  79. @brief This is the error message the server will respond with if Admin disables IDP specified by
  80. provider.
  81. */
  82. static NSString *const kOperationNotAllowedErrorMessage = @"OPERATION_NOT_ALLOWED";
  83. /** @var kPasswordLoginDisabledErrorMessage
  84. @brief This is the error message the server responds with if password login is disabled.
  85. */
  86. static NSString *const kPasswordLoginDisabledErrorMessage = @"PASSWORD_LOGIN_DISABLED";
  87. /** @var kPhotoUrlKey
  88. @brief The name of the 'photoUrl' property in the response.
  89. */
  90. static NSString *const kPhotoUrlKey = @"photoUrl";
  91. /** @var kTestPhotoUrl
  92. @brief Fake photoUrl for testing the response.
  93. */
  94. static NSString *const kTestPhotoUrl = @"www.example.com";
  95. /** @var kUserDisabledErrorMessage
  96. @brief This is the error message the server will respond with if the user's account has been
  97. disabled.
  98. */
  99. static NSString *const kUserDisabledErrorMessage = @"USER_DISABLED";
  100. /** @var kEmailNotFoundErrorMessage
  101. @brief This is the error message the server will respond with if the email entered is not
  102. found.
  103. */
  104. static NSString *const kEmailNotFoundErrorMessage = @"EMAIL_NOT_FOUND";
  105. /** @var kWrongPasswordErrorMessage
  106. @brief This is the error message the server will respond with if the user entered a wrong
  107. password.
  108. */
  109. static NSString *const kWrongPasswordErrorMessage = @"INVALID_PASSWORD";
  110. /** @var kInvalidEmailErrorMessage
  111. @brief The error returned by the server if the email is invalid.
  112. */
  113. static NSString *const kInvalidEmailErrorMessage = @"INVALID_EMAIL";
  114. /** @var kBadRequestErrorMessage
  115. @brief This is the error message returned when a bad request is made; often due to a bad API
  116. Key.
  117. */
  118. static NSString *const kBadRequestErrorMessage = @"Bad Request";
  119. /** @var kInvalidKeyReasonValue
  120. @brief The value for the "reason" key indicating an invalid API Key was received by the server.
  121. */
  122. static NSString *const kInvalidKeyReasonValue = @"keyInvalid";
  123. /** @var kAppNotAuthorizedReasonValue
  124. @brief The value for the "reason" key indicating the App is not authorized to use Firebase
  125. Authentication.
  126. */
  127. static NSString *const kAppNotAuthorizedReasonValue = @"ipRefererBlocked";
  128. /** @var kTooManyAttemptsErrorMessage
  129. @brief This is the error message the server will respond with if a user has tried (and failed)
  130. to sign in too many times.
  131. */
  132. static NSString *const kTooManyAttemptsErrorMessage = @"TOO_MANY_ATTEMPTS_TRY_LATER:";
  133. /** @var kAllowedTimeDifference
  134. @brief Allowed difference when comparing times because of execution time and floating point
  135. error.
  136. */
  137. static const double kAllowedTimeDifference = 0.1;
  138. /** @class FIRVerifyPasswordResponseTests
  139. @brief Tests for @c FIRVerifyPasswordResponse.
  140. */
  141. @interface FIRVerifyPasswordResponseTests : XCTestCase
  142. @end
  143. @implementation FIRVerifyPasswordResponseTests {
  144. /** @var _RPCIssuer
  145. @brief This backend RPC issuer is used to fake network responses for each test in the suite.
  146. In the @c setUp method we initialize this and set @c FIRAuthBackend's RPC issuer to it.
  147. */
  148. FIRFakeBackendRPCIssuer *_RPCIssuer;
  149. }
  150. - (void)setUp {
  151. FIRFakeBackendRPCIssuer *RPCIssuer = [[FIRFakeBackendRPCIssuer alloc] init];
  152. [FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:RPCIssuer];
  153. _RPCIssuer = RPCIssuer;
  154. }
  155. /** @fn testUserDisabledError
  156. @brief Tests that @c FIRAuthErrorCodeUserDisabled error is received if the email is disabled.
  157. */
  158. - (void)testUserDisabledError {
  159. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  160. password:kTestPassword
  161. APIKey:kTestAPIKey];
  162. __block BOOL callbackInvoked;
  163. __block FIRVerifyPasswordResponse *RPCResponse;
  164. __block NSError *RPCError;
  165. [FIRAuthBackend verifyPassword:request
  166. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  167. NSError *_Nullable error) {
  168. RPCResponse = response;
  169. RPCError = error;
  170. callbackInvoked = YES;
  171. }];
  172. [_RPCIssuer respondWithServerErrorMessage:kUserDisabledErrorMessage];
  173. XCTAssert(callbackInvoked);
  174. XCTAssertNil(RPCResponse);
  175. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeUserDisabled);
  176. }
  177. /** @fn testEmailNotFoundError
  178. @brief Tests that @c FIRAuthErrorCodeEmailNotFound error is received if the email is not found.
  179. */
  180. - (void)testEmailNotFoundError {
  181. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  182. password:kTestPassword
  183. APIKey:kTestAPIKey];
  184. __block BOOL callbackInvoked;
  185. __block FIRVerifyPasswordResponse *RPCResponse;
  186. __block NSError *RPCError;
  187. [FIRAuthBackend verifyPassword:request
  188. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  189. NSError *_Nullable error) {
  190. RPCResponse = response;
  191. RPCError = error;
  192. callbackInvoked = YES;
  193. }];
  194. [_RPCIssuer respondWithServerErrorMessage:kEmailNotFoundErrorMessage];
  195. XCTAssert(callbackInvoked);
  196. XCTAssertNil(RPCResponse);
  197. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeUserNotFound);
  198. }
  199. /** @fn testInvalidPasswordError
  200. @brief Tests that @c FIRAuthErrorCodeInvalidPassword error is received if the password is
  201. invalid.
  202. */
  203. - (void)testInvalidPasswordError {
  204. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  205. password:kTestPassword
  206. APIKey:kTestAPIKey];
  207. __block BOOL callbackInvoked;
  208. __block FIRVerifyPasswordResponse *RPCResponse;
  209. __block NSError *RPCError;
  210. [FIRAuthBackend verifyPassword:request
  211. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  212. NSError *_Nullable error) {
  213. RPCResponse = response;
  214. RPCError = error;
  215. callbackInvoked = YES;
  216. }];
  217. [_RPCIssuer respondWithServerErrorMessage:kWrongPasswordErrorMessage];
  218. XCTAssert(callbackInvoked);
  219. XCTAssertNil(RPCResponse);
  220. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeWrongPassword);
  221. }
  222. /** @fn testInvalidEmailError
  223. @brief Tests that @c FIRAuthErrorCodeInvalidEmail error is received if the email address has an
  224. incorrect format.
  225. */
  226. - (void)testInvalidEmailError {
  227. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  228. password:kTestPassword
  229. APIKey:kTestAPIKey];
  230. __block BOOL callbackInvoked;
  231. __block FIRVerifyPasswordResponse *RPCResponse;
  232. __block NSError *RPCError;
  233. [FIRAuthBackend verifyPassword:request
  234. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  235. NSError *_Nullable error) {
  236. RPCResponse = response;
  237. RPCError = error;
  238. callbackInvoked = YES;
  239. }];
  240. [_RPCIssuer respondWithServerErrorMessage:kInvalidEmailErrorMessage];
  241. XCTAssert(callbackInvoked);
  242. XCTAssertNil(RPCResponse);
  243. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeInvalidEmail);
  244. }
  245. /** @fn testTooManyAttemptsError
  246. @brief Tests that @c FIRAuthErrorCodeTooManyRequests error is received if too many sign-in
  247. attempts were made.
  248. */
  249. - (void)testTooManySignInAttemptsError {
  250. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  251. password:kTestPassword
  252. APIKey:kTestAPIKey];
  253. __block BOOL callbackInvoked;
  254. __block FIRVerifyPasswordResponse *RPCResponse;
  255. __block NSError *RPCError;
  256. [FIRAuthBackend verifyPassword:request
  257. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  258. NSError *_Nullable error) {
  259. RPCResponse = response;
  260. RPCError = error;
  261. callbackInvoked = YES;
  262. }];
  263. [_RPCIssuer respondWithServerErrorMessage:kTooManyAttemptsErrorMessage];
  264. XCTAssert(callbackInvoked);
  265. XCTAssertNil(RPCResponse);
  266. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeTooManyRequests);
  267. }
  268. /** @fn testKeyInvalid
  269. @brief Tests that @c FIRAuthErrorCodeInvalidApiKey error is received from the server.
  270. */
  271. - (void)testKeyInvalid {
  272. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  273. password:kTestPassword
  274. APIKey:kTestAPIKey];
  275. __block BOOL callbackInvoked;
  276. __block FIRVerifyPasswordResponse *RPCResponse;
  277. __block NSError *RPCError;
  278. [FIRAuthBackend verifyPassword:request
  279. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  280. NSError *_Nullable error) {
  281. RPCResponse = response;
  282. RPCError = error;
  283. callbackInvoked = YES;
  284. }];
  285. NSDictionary *errorDictionary = @{
  286. @"error" : @{
  287. @"message" : kBadRequestErrorMessage,
  288. @"errors" : @[ @{ @"reason" : kInvalidKeyReasonValue } ]
  289. }
  290. };
  291. [_RPCIssuer respondWithJSONError:errorDictionary];
  292. XCTAssert(callbackInvoked);
  293. XCTAssertNil(RPCResponse);
  294. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeInvalidAPIKey);
  295. }
  296. /** @fn testOperationNotAllowedError
  297. @brief This test simulates a @c FIRAuthErrorCodeOperationNotAllowed error.
  298. */
  299. - (void)testOperationNotAllowedError {
  300. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  301. password:kTestPassword
  302. APIKey:kTestAPIKey];
  303. __block BOOL callbackInvoked;
  304. __block FIRVerifyPasswordResponse *RPCResponse;
  305. __block NSError *RPCError;
  306. [FIRAuthBackend verifyPassword:request
  307. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  308. NSError *_Nullable error) {
  309. callbackInvoked = YES;
  310. RPCResponse = response;
  311. RPCError = error;
  312. }];
  313. [_RPCIssuer respondWithServerErrorMessage:kOperationNotAllowedErrorMessage];
  314. XCTAssert(callbackInvoked);
  315. XCTAssertNotNil(RPCError);
  316. XCTAssertNil(RPCResponse);
  317. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeOperationNotAllowed);
  318. }
  319. /** @fn testPasswordLoginDisabledError
  320. @brief This test simulates a @c FIRAuthErrorCodeOperationNotAllowed error.
  321. */
  322. - (void)testPasswordLoginDisabledError {
  323. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  324. password:kTestPassword
  325. APIKey:kTestAPIKey];
  326. __block BOOL callbackInvoked;
  327. __block FIRVerifyPasswordResponse *RPCResponse;
  328. __block NSError *RPCError;
  329. [FIRAuthBackend verifyPassword:request
  330. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  331. NSError *_Nullable error) {
  332. callbackInvoked = YES;
  333. RPCResponse = response;
  334. RPCError = error;
  335. }];
  336. [_RPCIssuer respondWithServerErrorMessage:kPasswordLoginDisabledErrorMessage];
  337. XCTAssert(callbackInvoked);
  338. XCTAssertNotNil(RPCError);
  339. XCTAssertNil(RPCResponse);
  340. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeOperationNotAllowed);
  341. }
  342. /** @fn testAppNotAuthorized
  343. @brief Tests that @c FIRAuthErrorCodeAppNotAuthorized error is received from the server.
  344. */
  345. - (void)testAppNotAuthorized {
  346. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  347. password:kTestPassword
  348. APIKey:kTestAPIKey];
  349. __block BOOL callbackInvoked;
  350. __block FIRVerifyPasswordResponse *RPCResponse;
  351. __block NSError *RPCError;
  352. [FIRAuthBackend verifyPassword:request
  353. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  354. NSError *_Nullable error) {
  355. RPCResponse = response;
  356. RPCError = error;
  357. callbackInvoked = YES;
  358. }];
  359. NSDictionary *errorDictionary = @{
  360. @"error" : @{
  361. @"message" : kBadRequestErrorMessage,
  362. @"errors" : @[ @{ @"reason" : kAppNotAuthorizedReasonValue } ]
  363. }
  364. };
  365. [_RPCIssuer respondWithJSONError:errorDictionary];
  366. XCTAssert(callbackInvoked);
  367. XCTAssertNil(RPCResponse);
  368. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeAppNotAuthorized);
  369. }
  370. /** @fn testSuccessfulVerifyPasswordResponse
  371. @brief Tests a succesful attempt of the verify password flow.
  372. */
  373. - (void)testSuccessfulVerifyPasswordResponse {
  374. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  375. password:kTestPassword
  376. APIKey:kTestAPIKey];
  377. __block BOOL callbackInvoked;
  378. __block FIRVerifyPasswordResponse *RPCResponse;
  379. __block NSError *RPCError;
  380. [FIRAuthBackend verifyPassword:request
  381. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  382. NSError *_Nullable error) {
  383. RPCResponse = response;
  384. RPCError = error;
  385. callbackInvoked = YES;
  386. }];
  387. [_RPCIssuer respondWithJSON:@{
  388. kLocalIDKey : kTestLocalID,
  389. kEmailKey : kTestEmail,
  390. kDisplayNameKey : kTestDisplayName,
  391. kIDTokenKey : kTestIDToken,
  392. kExpiresInKey : kTestExpiresIn,
  393. kRefreshTokenKey : kTestRefreshToken,
  394. kPhotoUrlKey : kTestPhotoUrl
  395. }];
  396. XCTAssert(callbackInvoked);
  397. XCTAssertNotNil(RPCResponse);
  398. XCTAssertEqualObjects(RPCResponse.email, kTestEmail);
  399. XCTAssertEqualObjects(RPCResponse.localID, kTestLocalID);
  400. XCTAssertEqualObjects(RPCResponse.displayName, kTestDisplayName);
  401. XCTAssertEqualObjects(RPCResponse.IDToken, kTestIDToken);
  402. NSTimeInterval expiresIn = [RPCResponse.approximateExpirationDate timeIntervalSinceNow];
  403. XCTAssertEqualWithAccuracy(expiresIn, [kTestExpiresIn doubleValue], kAllowedTimeDifference);
  404. XCTAssertEqualObjects(RPCResponse.refreshToken, kTestRefreshToken);
  405. XCTAssertEqualObjects(RPCResponse.photoURL.absoluteString, kTestPhotoUrl );
  406. }
  407. @end