VerifyAssertionTests.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright 2023 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import Foundation
  15. import XCTest
  16. @testable import FirebaseAuth
  17. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  18. class VerifyAssertionTests: RPCBaseTests {
  19. private let kTestProviderID = "ProviderID"
  20. private let kProviderIDKey = "providerId"
  21. private let kProviderAccessTokenKey = "access_token"
  22. private let kTestProviderAccessToken = "testProviderAccessToken"
  23. private let kPostBodyKey = "postBody"
  24. private let kIDTokenKey = "idToken"
  25. private let kReturnSecureTokenKey = "returnSecureToken"
  26. private let kAutoCreateKey = "autoCreate"
  27. private let kProviderIDTokenKey = "id_token"
  28. private let kTestProviderIDToken = "ProviderIDToken"
  29. private let kTestAccessToken = "ACCESS_TOKEN"
  30. private let kInputEmailKey = "identifier"
  31. private let kTestInputEmail = "testInputEmail"
  32. private let kTestPendingToken = "testPendingToken"
  33. private let kProviderOAuthTokenSecretKey = "oauth_token_secret"
  34. private let kTestProviderOAuthTokenSecret = "testProviderOAuthTokenSecret"
  35. private let kTestIDToken = "ID_TOKEN"
  36. private let kTestExpiresIn = "12345"
  37. private let kTestRefreshToken = "REFRESH_TOKEN"
  38. private let kTestProvider = "Provider"
  39. private let kPhotoUrlKey = "photoUrl"
  40. private let kTestPhotoUrl = "www.example.com"
  41. private let kUsername = "Joe Doe"
  42. private let kVerifiedProviderKey = "verifiedProvider"
  43. private let kExpiresInKey = "expiresIn"
  44. private let kRefreshTokenKey = "refreshToken"
  45. private let kRawUserInfoKey = "rawUserInfo"
  46. private let kUsernameKey = "username"
  47. private let kIsNewUserKey = "isNewUser"
  48. private let kExpectedAPIURL =
  49. "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyAssertion?key=APIKey"
  50. /** @fn testVerifyAssertionRequestProviderAccessToken
  51. @brief Tests the verify assertion request with the @c providerAccessToken field set.
  52. @remarks The presence of the @c providerAccessToken will prevent an @c
  53. InvalidArgumentException exception from being raised.
  54. */
  55. func testVerifyAssertionRequestProviderAccessToken() async throws {
  56. let request = makeVerifyAssertionRequest()
  57. request.returnSecureToken = false
  58. try await checkRequest(
  59. request: request,
  60. expected: kExpectedAPIURL,
  61. key: kIDTokenKey,
  62. value: nil
  63. )
  64. var components = URLComponents()
  65. components.queryItems = [
  66. URLQueryItem(name: kProviderIDKey, value: kTestProviderID),
  67. URLQueryItem(name: kProviderAccessTokenKey, value: kTestProviderAccessToken),
  68. ]
  69. let requestDictionary = try XCTUnwrap(rpcIssuer.decodedRequest as? [String: AnyHashable])
  70. XCTAssertEqual(requestDictionary[kPostBodyKey], components.query)
  71. XCTAssertNil(requestDictionary[kReturnSecureTokenKey])
  72. // Auto-create flag Should be true by default.
  73. XCTAssertTrue(try XCTUnwrap(requestDictionary[kAutoCreateKey] as? Bool))
  74. }
  75. /** @fn testVerifyAssertionRequestOptionalFields
  76. @brief Tests the verify assertion request with all optional fields set.
  77. */
  78. func testVerifyAssertionRequestOptionalFields() async throws {
  79. let request = makeVerifyAssertionRequest()
  80. request.providerIDToken = kTestProviderIDToken
  81. request.accessToken = kTestAccessToken
  82. request.inputEmail = kTestInputEmail
  83. request.pendingToken = kTestPendingToken
  84. request.providerOAuthTokenSecret = kTestProviderOAuthTokenSecret
  85. request.autoCreate = false
  86. let kFakeGivenName = "Paul"
  87. let kFakeFamilyName = "B"
  88. var fullName = PersonNameComponents()
  89. fullName.givenName = kFakeGivenName
  90. fullName.familyName = kFakeFamilyName
  91. request.fullName = fullName
  92. // The name fields may be sorted either way.
  93. let userJSON = "{\"name\":{\"firstName\":\"\(kFakeGivenName)\"," +
  94. "\"lastName\":\"\(kFakeFamilyName)\"}}"
  95. try await checkRequest(
  96. request: request,
  97. expected: kExpectedAPIURL,
  98. key: kIDTokenKey,
  99. value: kTestAccessToken
  100. )
  101. var components = URLComponents()
  102. components.queryItems = [
  103. URLQueryItem(name: kProviderIDKey, value: kTestProviderID),
  104. URLQueryItem(name: kProviderIDTokenKey, value: kTestProviderIDToken),
  105. URLQueryItem(name: kProviderAccessTokenKey, value: kTestProviderAccessToken),
  106. URLQueryItem(name: kProviderOAuthTokenSecretKey, value: kTestProviderOAuthTokenSecret),
  107. URLQueryItem(name: kInputEmailKey, value: kTestInputEmail),
  108. URLQueryItem(name: "user", value: userJSON),
  109. ]
  110. let requestDictionary = try XCTUnwrap(rpcIssuer.decodedRequest as? [String: AnyHashable])
  111. XCTAssertEqual(requestDictionary[kPostBodyKey], components.query)
  112. XCTAssertTrue(try XCTUnwrap(requestDictionary[kReturnSecureTokenKey] as? Bool))
  113. XCTAssertFalse(try XCTUnwrap(requestDictionary[kAutoCreateKey] as? Bool))
  114. }
  115. func testVerifyAssertionRequestErrors() async throws {
  116. let kTestInvalidCredentialError = "INVALID_IDP_RESPONSE"
  117. let kUserDisabledErrorMessage = "USER_DISABLED"
  118. let kFederatedUserIDAlreadyLinkedMessage = "FEDERATED_USER_ID_ALREADY_LINKED:"
  119. let kOperationNotAllowedErrorMessage = "OPERATION_NOT_ALLOWED"
  120. let kPasswordLoginDisabledErrorMessage = "PASSWORD_LOGIN_DISABLED"
  121. try await checkBackendError(
  122. request: makeVerifyAssertionRequest(),
  123. message: kTestInvalidCredentialError,
  124. errorCode: AuthErrorCode.invalidCredential
  125. )
  126. try await checkBackendError(
  127. request: makeVerifyAssertionRequest(),
  128. message: kUserDisabledErrorMessage,
  129. errorCode: AuthErrorCode.userDisabled
  130. )
  131. try await checkBackendError(
  132. request: makeVerifyAssertionRequest(),
  133. message: kFederatedUserIDAlreadyLinkedMessage,
  134. errorCode: AuthErrorCode.credentialAlreadyInUse
  135. )
  136. try await checkBackendError(
  137. request: makeVerifyAssertionRequest(),
  138. message: kOperationNotAllowedErrorMessage,
  139. errorCode: AuthErrorCode.operationNotAllowed
  140. )
  141. try await checkBackendError(
  142. request: makeVerifyAssertionRequest(),
  143. message: kPasswordLoginDisabledErrorMessage,
  144. errorCode: AuthErrorCode.operationNotAllowed
  145. )
  146. }
  147. private let profile = [
  148. "iss": "https://accounts.google.com\\",
  149. "email": "test@email.com",
  150. "given_name": "User",
  151. "family_name": "Doe",
  152. ]
  153. /** @fn testSuccessfulVerifyAssertionResponse
  154. @brief This test simulates a successful verify assertion flow.
  155. */
  156. func testSuccessfulVerifyAssertionResponse() async throws {
  157. rpcIssuer?.respondBlock = {
  158. try self.rpcIssuer?.respond(withJSON: [
  159. self.kProviderIDKey: self.kTestProviderID,
  160. self.kIDTokenKey: self.kTestIDToken,
  161. self.kExpiresInKey: self.kTestExpiresIn,
  162. self.kRefreshTokenKey: self.kTestRefreshToken,
  163. self.kVerifiedProviderKey: [self.kTestProvider],
  164. self.kPhotoUrlKey: self.kTestPhotoUrl,
  165. self.kUsernameKey: self.kUsername,
  166. self.kIsNewUserKey: true,
  167. self.kRawUserInfoKey: self.profile,
  168. ])
  169. }
  170. let rpcResponse = try await AuthBackend.call(with: makeVerifyAssertionRequest())
  171. XCTAssertEqual(rpcResponse.idToken, kTestIDToken)
  172. XCTAssertEqual(rpcResponse.refreshToken, kTestRefreshToken)
  173. XCTAssertEqual(rpcResponse.verifiedProvider, [kTestProvider])
  174. XCTAssertEqual(rpcResponse.photoURL, URL(string: kTestPhotoUrl))
  175. XCTAssertEqual(rpcResponse.username, kUsername)
  176. XCTAssertEqual(try XCTUnwrap(rpcResponse.profile as? [String: String]), profile)
  177. let expiresIn = try XCTUnwrap(rpcResponse.approximateExpirationDate?.timeIntervalSinceNow)
  178. XCTAssertEqual(expiresIn, 12345, accuracy: 0.1)
  179. XCTAssertEqual(rpcResponse.providerID, kTestProviderID)
  180. XCTAssertTrue(rpcResponse.isNewUser)
  181. }
  182. /** @fn testSuccessfulVerifyAssertionResponseWithTextData
  183. @brief This test simulates a successful verify assertion flow when response collection
  184. fields are sent as text values.
  185. */
  186. func testSuccessfulVerifyAssertionResponseWithTextData() async throws {
  187. rpcIssuer?.respondBlock = {
  188. try self.rpcIssuer?.respond(withJSON: [
  189. self.kProviderIDKey: self.kTestProviderID,
  190. self.kIDTokenKey: self.kTestIDToken,
  191. self.kExpiresInKey: self.kTestExpiresIn,
  192. self.kRefreshTokenKey: self.kTestRefreshToken,
  193. self.kVerifiedProviderKey: self.convertToJson([self.kTestProvider]),
  194. self.kPhotoUrlKey: self.kTestPhotoUrl,
  195. self.kUsernameKey: self.kUsername,
  196. self.kIsNewUserKey: false,
  197. self.kRawUserInfoKey: self.convertToJson(self.profile),
  198. ])
  199. }
  200. let rpcResponse = try await AuthBackend.call(with: makeVerifyAssertionRequest())
  201. XCTAssertEqual(rpcResponse.idToken, kTestIDToken)
  202. XCTAssertEqual(rpcResponse.refreshToken, kTestRefreshToken)
  203. XCTAssertEqual(rpcResponse.verifiedProvider, [kTestProvider])
  204. XCTAssertEqual(rpcResponse.photoURL, URL(string: kTestPhotoUrl))
  205. XCTAssertEqual(rpcResponse.username, kUsername)
  206. XCTAssertEqual(try XCTUnwrap(rpcResponse.profile as? [String: String]), profile)
  207. let expiresIn = try XCTUnwrap(rpcResponse.approximateExpirationDate?.timeIntervalSinceNow)
  208. XCTAssertEqual(expiresIn, 12345, accuracy: 0.1)
  209. XCTAssertEqual(rpcResponse.providerID, kTestProviderID)
  210. XCTAssertFalse(rpcResponse.isNewUser)
  211. }
  212. private func convertToJson(_ input: AnyHashable) throws -> String {
  213. let data = try JSONSerialization.data(withJSONObject: input)
  214. return String(decoding: data, as: UTF8.self)
  215. }
  216. private func makeVerifyAssertionRequest() -> VerifyAssertionRequest {
  217. let request = VerifyAssertionRequest(providerID: kTestProviderID,
  218. requestConfiguration: makeRequestConfiguration())
  219. request.providerAccessToken = kTestProviderAccessToken
  220. return request
  221. }
  222. }