VerifyAssertionRequest.swift 7.4 KB

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