FIRVerifyPasswordResponseTests.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  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. /** @var _requestConfiguration
  150. @brief This is the request configuration used for testing.
  151. */
  152. FIRAuthRequestConfiguration *_requestConfiguration;
  153. }
  154. - (void)setUp {
  155. [super setUp];
  156. FIRFakeBackendRPCIssuer *RPCIssuer = [[FIRFakeBackendRPCIssuer alloc] init];
  157. [FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:RPCIssuer];
  158. _RPCIssuer = RPCIssuer;
  159. _requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kTestAPIKey];
  160. }
  161. /** @fn testUserDisabledError
  162. @brief Tests that @c FIRAuthErrorCodeUserDisabled error is received if the email is disabled.
  163. */
  164. - (void)testUserDisabledError {
  165. FIRVerifyPasswordRequest *request =
  166. [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  167. password:kTestPassword
  168. requestConfiguration:_requestConfiguration];
  169. __block BOOL callbackInvoked;
  170. __block FIRVerifyPasswordResponse *RPCResponse;
  171. __block NSError *RPCError;
  172. [FIRAuthBackend verifyPassword:request
  173. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  174. NSError *_Nullable error) {
  175. RPCResponse = response;
  176. RPCError = error;
  177. callbackInvoked = YES;
  178. }];
  179. [_RPCIssuer respondWithServerErrorMessage:kUserDisabledErrorMessage];
  180. XCTAssert(callbackInvoked);
  181. XCTAssertNil(RPCResponse);
  182. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeUserDisabled);
  183. }
  184. /** @fn testEmailNotFoundError
  185. @brief Tests that @c FIRAuthErrorCodeEmailNotFound error is received if the email is not found.
  186. */
  187. - (void)testEmailNotFoundError {
  188. FIRVerifyPasswordRequest *request =
  189. [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  190. password:kTestPassword
  191. requestConfiguration:_requestConfiguration];
  192. __block BOOL callbackInvoked;
  193. __block FIRVerifyPasswordResponse *RPCResponse;
  194. __block NSError *RPCError;
  195. [FIRAuthBackend verifyPassword:request
  196. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  197. NSError *_Nullable error) {
  198. RPCResponse = response;
  199. RPCError = error;
  200. callbackInvoked = YES;
  201. }];
  202. [_RPCIssuer respondWithServerErrorMessage:kEmailNotFoundErrorMessage];
  203. XCTAssert(callbackInvoked);
  204. XCTAssertNil(RPCResponse);
  205. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeUserNotFound);
  206. }
  207. /** @fn testInvalidPasswordError
  208. @brief Tests that @c FIRAuthErrorCodeInvalidPassword error is received if the password is
  209. invalid.
  210. */
  211. - (void)testInvalidPasswordError {
  212. FIRVerifyPasswordRequest *request =
  213. [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  214. password:kTestPassword
  215. requestConfiguration:_requestConfiguration];
  216. __block BOOL callbackInvoked;
  217. __block FIRVerifyPasswordResponse *RPCResponse;
  218. __block NSError *RPCError;
  219. [FIRAuthBackend verifyPassword:request
  220. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  221. NSError *_Nullable error) {
  222. RPCResponse = response;
  223. RPCError = error;
  224. callbackInvoked = YES;
  225. }];
  226. [_RPCIssuer respondWithServerErrorMessage:kWrongPasswordErrorMessage];
  227. XCTAssert(callbackInvoked);
  228. XCTAssertNil(RPCResponse);
  229. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeWrongPassword);
  230. }
  231. /** @fn testInvalidEmailError
  232. @brief Tests that @c FIRAuthErrorCodeInvalidEmail error is received if the email address has an
  233. incorrect format.
  234. */
  235. - (void)testInvalidEmailError {
  236. FIRVerifyPasswordRequest *request =
  237. [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  238. password:kTestPassword
  239. requestConfiguration:_requestConfiguration];
  240. __block BOOL callbackInvoked;
  241. __block FIRVerifyPasswordResponse *RPCResponse;
  242. __block NSError *RPCError;
  243. [FIRAuthBackend verifyPassword:request
  244. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  245. NSError *_Nullable error) {
  246. RPCResponse = response;
  247. RPCError = error;
  248. callbackInvoked = YES;
  249. }];
  250. [_RPCIssuer respondWithServerErrorMessage:kInvalidEmailErrorMessage];
  251. XCTAssert(callbackInvoked);
  252. XCTAssertNil(RPCResponse);
  253. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeInvalidEmail);
  254. }
  255. /** @fn testTooManyAttemptsError
  256. @brief Tests that @c FIRAuthErrorCodeTooManyRequests error is received if too many sign-in
  257. attempts were made.
  258. */
  259. - (void)testTooManySignInAttemptsError {
  260. FIRVerifyPasswordRequest *request =
  261. [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  262. password:kTestPassword
  263. requestConfiguration:_requestConfiguration];
  264. __block BOOL callbackInvoked;
  265. __block FIRVerifyPasswordResponse *RPCResponse;
  266. __block NSError *RPCError;
  267. [FIRAuthBackend verifyPassword:request
  268. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  269. NSError *_Nullable error) {
  270. RPCResponse = response;
  271. RPCError = error;
  272. callbackInvoked = YES;
  273. }];
  274. [_RPCIssuer respondWithServerErrorMessage:kTooManyAttemptsErrorMessage];
  275. XCTAssert(callbackInvoked);
  276. XCTAssertNil(RPCResponse);
  277. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeTooManyRequests);
  278. }
  279. /** @fn testKeyInvalid
  280. @brief Tests that @c FIRAuthErrorCodeInvalidApiKey error is received from the server.
  281. */
  282. - (void)testKeyInvalid {
  283. FIRVerifyPasswordRequest *request =
  284. [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  285. password:kTestPassword
  286. requestConfiguration:_requestConfiguration];
  287. __block BOOL callbackInvoked;
  288. __block FIRVerifyPasswordResponse *RPCResponse;
  289. __block NSError *RPCError;
  290. [FIRAuthBackend verifyPassword:request
  291. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  292. NSError *_Nullable error) {
  293. RPCResponse = response;
  294. RPCError = error;
  295. callbackInvoked = YES;
  296. }];
  297. NSDictionary *errorDictionary = @{
  298. @"error" : @{
  299. @"message" : kBadRequestErrorMessage,
  300. @"errors" : @[ @{ @"reason" : kInvalidKeyReasonValue } ]
  301. }
  302. };
  303. [_RPCIssuer respondWithJSONError:errorDictionary];
  304. XCTAssert(callbackInvoked);
  305. XCTAssertNil(RPCResponse);
  306. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeInvalidAPIKey);
  307. }
  308. /** @fn testOperationNotAllowedError
  309. @brief This test simulates a @c FIRAuthErrorCodeOperationNotAllowed error.
  310. */
  311. - (void)testOperationNotAllowedError {
  312. FIRVerifyPasswordRequest *request =
  313. [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  314. password:kTestPassword
  315. requestConfiguration:_requestConfiguration];
  316. __block BOOL callbackInvoked;
  317. __block FIRVerifyPasswordResponse *RPCResponse;
  318. __block NSError *RPCError;
  319. [FIRAuthBackend verifyPassword:request
  320. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  321. NSError *_Nullable error) {
  322. callbackInvoked = YES;
  323. RPCResponse = response;
  324. RPCError = error;
  325. }];
  326. [_RPCIssuer respondWithServerErrorMessage:kOperationNotAllowedErrorMessage];
  327. XCTAssert(callbackInvoked);
  328. XCTAssertNotNil(RPCError);
  329. XCTAssertNil(RPCResponse);
  330. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeOperationNotAllowed);
  331. }
  332. /** @fn testPasswordLoginDisabledError
  333. @brief This test simulates a @c FIRAuthErrorCodeOperationNotAllowed error.
  334. */
  335. - (void)testPasswordLoginDisabledError {
  336. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  337. password:kTestPassword
  338. requestConfiguration:_requestConfiguration];
  339. __block BOOL callbackInvoked;
  340. __block FIRVerifyPasswordResponse *RPCResponse;
  341. __block NSError *RPCError;
  342. [FIRAuthBackend verifyPassword:request
  343. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  344. NSError *_Nullable error) {
  345. callbackInvoked = YES;
  346. RPCResponse = response;
  347. RPCError = error;
  348. }];
  349. [_RPCIssuer respondWithServerErrorMessage:kPasswordLoginDisabledErrorMessage];
  350. XCTAssert(callbackInvoked);
  351. XCTAssertNotNil(RPCError);
  352. XCTAssertNil(RPCResponse);
  353. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeOperationNotAllowed);
  354. }
  355. /** @fn testAppNotAuthorized
  356. @brief Tests that @c FIRAuthErrorCodeAppNotAuthorized error is received from the server.
  357. */
  358. - (void)testAppNotAuthorized {
  359. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  360. password:kTestPassword
  361. requestConfiguration:_requestConfiguration];
  362. __block BOOL callbackInvoked;
  363. __block FIRVerifyPasswordResponse *RPCResponse;
  364. __block NSError *RPCError;
  365. [FIRAuthBackend verifyPassword:request
  366. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  367. NSError *_Nullable error) {
  368. RPCResponse = response;
  369. RPCError = error;
  370. callbackInvoked = YES;
  371. }];
  372. NSDictionary *errorDictionary = @{
  373. @"error" : @{
  374. @"message" : kBadRequestErrorMessage,
  375. @"errors" : @[ @{ @"reason" : kAppNotAuthorizedReasonValue } ]
  376. }
  377. };
  378. [_RPCIssuer respondWithJSONError:errorDictionary];
  379. XCTAssert(callbackInvoked);
  380. XCTAssertNil(RPCResponse);
  381. XCTAssertEqual(RPCError.code, FIRAuthErrorCodeAppNotAuthorized);
  382. }
  383. /** @fn testSuccessfulVerifyPasswordResponse
  384. @brief Tests a succesful attempt of the verify password flow.
  385. */
  386. - (void)testSuccessfulVerifyPasswordResponse {
  387. FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:kTestEmail
  388. password:kTestPassword
  389. requestConfiguration:_requestConfiguration];
  390. __block BOOL callbackInvoked;
  391. __block FIRVerifyPasswordResponse *RPCResponse;
  392. __block NSError *RPCError;
  393. [FIRAuthBackend verifyPassword:request
  394. callback:^(FIRVerifyPasswordResponse *_Nullable response,
  395. NSError *_Nullable error) {
  396. RPCResponse = response;
  397. RPCError = error;
  398. callbackInvoked = YES;
  399. }];
  400. [_RPCIssuer respondWithJSON:@{
  401. kLocalIDKey : kTestLocalID,
  402. kEmailKey : kTestEmail,
  403. kDisplayNameKey : kTestDisplayName,
  404. kIDTokenKey : kTestIDToken,
  405. kExpiresInKey : kTestExpiresIn,
  406. kRefreshTokenKey : kTestRefreshToken,
  407. kPhotoUrlKey : kTestPhotoUrl
  408. }];
  409. XCTAssert(callbackInvoked);
  410. XCTAssertNotNil(RPCResponse);
  411. XCTAssertEqualObjects(RPCResponse.email, kTestEmail);
  412. XCTAssertEqualObjects(RPCResponse.localID, kTestLocalID);
  413. XCTAssertEqualObjects(RPCResponse.displayName, kTestDisplayName);
  414. XCTAssertEqualObjects(RPCResponse.IDToken, kTestIDToken);
  415. NSTimeInterval expiresIn = [RPCResponse.approximateExpirationDate timeIntervalSinceNow];
  416. XCTAssertEqualWithAccuracy(expiresIn, [kTestExpiresIn doubleValue], kAllowedTimeDifference);
  417. XCTAssertEqualObjects(RPCResponse.refreshToken, kTestRefreshToken);
  418. XCTAssertEqualObjects(RPCResponse.photoURL.absoluteString, kTestPhotoUrl );
  419. }
  420. @end