FIRVerifyPasswordResponseTests.m 17 KB

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