VerifyAssertionRequest.swift 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. /** @var kVerifyAssertionEndpoint
  16. @brief The "verifyAssertion" endpoint.
  17. */
  18. private let kVerifyAssertionEndpoint = "verifyAssertion"
  19. /** @var kProviderIDKey
  20. @brief The key for the "providerId" value in the request.
  21. */
  22. private let kProviderIDKey = "providerId"
  23. /** @var kProviderIDTokenKey
  24. @brief The key for the "id_token" value in the request.
  25. */
  26. private let kProviderIDTokenKey = "id_token"
  27. /** @var kProviderNonceKey
  28. @brief The key for the "nonce" value in the request.
  29. */
  30. private let kProviderNonceKey = "nonce"
  31. /** @var kProviderAccessTokenKey
  32. @brief The key for the "access_token" value in the request.
  33. */
  34. private let kProviderAccessTokenKey = "access_token"
  35. /** @var kProviderOAuthTokenSecretKey
  36. @brief The key for the "oauth_token_secret" value in the request.
  37. */
  38. private let kProviderOAuthTokenSecretKey = "oauth_token_secret"
  39. /** @var kIdentifierKey
  40. @brief The key for the "identifier" value in the request.
  41. */
  42. private let kIdentifierKey = "identifier"
  43. /** @var kRequestURIKey
  44. @brief The key for the "requestUri" value in the request.
  45. */
  46. private let kRequestURIKey = "requestUri"
  47. /** @var kPostBodyKey
  48. @brief The key for the "postBody" value in the request.
  49. */
  50. private let kPostBodyKey = "postBody"
  51. /** @var kPendingTokenKey
  52. @brief The key for the "pendingToken" value in the request.
  53. */
  54. private let kPendingTokenKey = "pendingToken"
  55. /** @var kAutoCreateKey
  56. @brief The key for the "autoCreate" value in the request.
  57. */
  58. private let kAutoCreateKey = "autoCreate"
  59. /** @var kIDTokenKey
  60. @brief The key for the "idToken" value in the request. This is actually the STS Access Token,
  61. despite it's confusing (backwards compatiable) parameter name.
  62. */
  63. private let kIDTokenKey = "idToken"
  64. /** @var kReturnSecureTokenKey
  65. @brief The key for the "returnSecureToken" value in the request.
  66. */
  67. private let kReturnSecureTokenKey = "returnSecureToken"
  68. /** @var kReturnIDPCredentialKey
  69. @brief The key for the "returnIdpCredential" value in the request.
  70. */
  71. private let kReturnIDPCredentialKey = "returnIdpCredential"
  72. /** @var kSessionIDKey
  73. @brief The key for the "sessionID" value in the request.
  74. */
  75. private let kSessionIDKey = "sessionId"
  76. /** @var kTenantIDKey
  77. @brief The key for the tenant id value in the request.
  78. */
  79. private let kTenantIDKey = "tenantId"
  80. /** @var kUserKey
  81. @brief The key for the "user" value in the request. The value is a JSON object that contains the
  82. name of the user.
  83. */
  84. private let kUserKey = "user"
  85. /** @var kNameKey
  86. @brief The key for the "name" value in the request. The value is a JSON object that contains the
  87. first and/or last name of the user.
  88. */
  89. private let kNameKey = "name"
  90. /** @var kFirstNameKey
  91. @brief The key for the "firstName" value in the request.
  92. */
  93. private let kFirstNameKey = "firstName"
  94. /** @var kLastNameKey
  95. @brief The key for the "lastName" value in the request.
  96. */
  97. private let kLastNameKey = "lastName"
  98. /** @class FIRVerifyAssertionRequest
  99. @brief Represents the parameters for the verifyAssertion endpoint.
  100. @see https://developers.google.com/identity/toolkit/web/reference/relyingparty/verifyAssertion
  101. */
  102. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
  103. class VerifyAssertionRequest: IdentityToolkitRequest, AuthRPCRequest {
  104. typealias Response = VerifyAssertionResponse
  105. /** @property requestURI
  106. @brief The URI to which the IDP redirects the user back. It may contain federated login result
  107. params added by the IDP.
  108. */
  109. var requestURI: String?
  110. /** @property pendingToken
  111. @brief The Firebase ID Token for the IDP pending to be confirmed by the user.
  112. */
  113. var pendingToken: String?
  114. /** @property accessToken
  115. @brief The STS Access Token for the authenticated user, only needed for linking the user.
  116. */
  117. var accessToken: String?
  118. /** @property returnSecureToken
  119. @brief Whether the response should return access token and refresh token directly.
  120. @remarks The default value is @c YES .
  121. */
  122. var returnSecureToken: Bool = false
  123. // MARK: - Components of "postBody"
  124. /** @property providerID
  125. @brief The ID of the IDP whose credentials are being presented to the endpoint.
  126. */
  127. let providerID: String
  128. /** @property providerAccessToken
  129. @brief An access token from the IDP.
  130. */
  131. var providerAccessToken: String?
  132. /** @property providerIDToken
  133. @brief An ID Token from the IDP.
  134. */
  135. var providerIDToken: String?
  136. /** @property providerRawNonce
  137. @brief An raw nonce from the IDP.
  138. */
  139. var providerRawNonce: String?
  140. /** @property returnIDPCredential
  141. @brief Whether the response should return the IDP credential directly.
  142. */
  143. var returnIDPCredential: Bool = false
  144. /** @property providerOAuthTokenSecret
  145. @brief A session ID used to map this request to a headful-lite flow.
  146. */
  147. var sessionID: String?
  148. /** @property providerOAuthTokenSecret
  149. @brief An OAuth client secret from the IDP.
  150. */
  151. var providerOAuthTokenSecret: String?
  152. /** @property inputEmail
  153. @brief The originally entered email in the UI.
  154. */
  155. var inputEmail: String?
  156. /** @property autoCreate
  157. @brief A flag that indicates whether or not the user should be automatically created.
  158. */
  159. var autoCreate: Bool = false
  160. /** @property fullName
  161. @brief A full name from the IdP.
  162. */
  163. var fullName: PersonNameComponents?
  164. init(providerID: String, requestConfiguration: AuthRequestConfiguration) {
  165. self.providerID = providerID
  166. returnSecureToken = true
  167. autoCreate = true
  168. returnIDPCredential = true
  169. super.init(endpoint: kVerifyAssertionEndpoint, requestConfiguration: requestConfiguration)
  170. }
  171. func unencodedHTTPRequestBody() throws -> [String: AnyHashable] {
  172. var components = URLComponents()
  173. var queryItems: [URLQueryItem] = [URLQueryItem(name: kProviderIDKey, value: providerID)]
  174. if let providerIDToken = providerIDToken {
  175. queryItems.append(URLQueryItem(name: kProviderIDTokenKey, value: providerIDToken))
  176. }
  177. if let providerRawNonce = providerRawNonce {
  178. queryItems.append(URLQueryItem(name: kProviderNonceKey, value: providerRawNonce))
  179. }
  180. if let providerAccessToken = providerAccessToken {
  181. queryItems
  182. .append(URLQueryItem(name: kProviderAccessTokenKey, value: providerAccessToken))
  183. }
  184. guard providerIDToken != nil || providerAccessToken != nil || pendingToken != nil ||
  185. requestURI != nil else {
  186. fatalError("One of IDToken, accessToken, pendingToken, or requestURI must be supplied.")
  187. }
  188. if let providerOAuthTokenSecret = providerOAuthTokenSecret {
  189. queryItems
  190. .append(URLQueryItem(name: kProviderOAuthTokenSecretKey,
  191. value: providerOAuthTokenSecret))
  192. }
  193. if let inputEmail = inputEmail {
  194. queryItems.append(URLQueryItem(name: kIdentifierKey, value: inputEmail))
  195. }
  196. if fullName?.givenName != nil || fullName?.familyName != nil {
  197. var nameDict = [String: String]()
  198. if let given = fullName?.givenName {
  199. nameDict[kFirstNameKey] = given
  200. }
  201. if let lastName = fullName?.familyName {
  202. nameDict[kLastNameKey] = lastName
  203. }
  204. let userDict = [kNameKey: nameDict]
  205. do {
  206. let encoder = JSONEncoder()
  207. encoder.outputFormatting = .sortedKeys
  208. let userJson = try encoder.encode(userDict)
  209. let jsonString = String(data: userJson, encoding: .utf8)
  210. queryItems.append(URLQueryItem(name: kUserKey, value: jsonString))
  211. } catch {
  212. fatalError("Auth Internal error: failed to serialize dictionary to json: \(error)")
  213. }
  214. }
  215. components.queryItems = queryItems
  216. var body: [String: AnyHashable] = [
  217. kRequestURIKey: requestURI ?? "http://localhost", // Unused by server, but required
  218. ]
  219. if let query = components.query {
  220. body[kPostBodyKey] = query
  221. }
  222. if let pendingToken = pendingToken {
  223. body[kPendingTokenKey] = pendingToken
  224. }
  225. if let accessToken = accessToken {
  226. body[kIDTokenKey] = accessToken
  227. }
  228. if returnSecureToken {
  229. body[kReturnSecureTokenKey] = true
  230. }
  231. if returnIDPCredential {
  232. body[kReturnIDPCredentialKey] = true
  233. }
  234. if let sessionID = sessionID {
  235. body[kSessionIDKey] = sessionID
  236. }
  237. if let tenantID = tenantID {
  238. body[kTenantIDKey] = tenantID
  239. }
  240. body[kAutoCreateKey] = autoCreate
  241. return body
  242. }
  243. }