From c220cd608a3068da364ad9a9c30cb8006ce5786c Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Mon, 16 Sep 2024 15:24:54 -0600 Subject: [PATCH 1/7] @W-16362973: [iOS] Add QR Code Login Support in MSDK (iOS P.O.C) --- .../SFLoginViewController+QrCodeLogin.swift | 156 ++++++++++++++++++ .../Classes/Login/SFLoginViewController.h | 3 + .../Classes/Login/SFLoginViewController.m | 2 +- .../Login/SFSDKLoginViewControllerConfig.h | 2 +- 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift new file mode 100644 index 0000000000..aac233386f --- /dev/null +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift @@ -0,0 +1,156 @@ +// +// SFLoginViewController+QrCodeLogin.swift +// SalesforceSDKCore +// +// Created by Eric Johnson on 9/5/24. +// + +import Foundation + +public extension SalesforceLoginViewController { + + // MARK: QR Code Login Via UI Bridge API Public Implementation + + /** + * Automatically log in with a UI Bridge API login QR code. + * - Parameters + * - loginQrCodeContent: The login QR code content. This should be either a URL or URL + * query containing the UI Bridge API JSON parameter. The UI Bridge API JSON parameter + * should contain URL-encoded JSON with two values: + * - frontdoor_bridge_url + * - pkce_code_verifier + * If pkce_code_verifier is not specified then the user agent flow is used + * - Returns: Boolean true if a log in attempt is possible using the provided QR code content, false + * otherwise + */ + func loginFromQrCode( + loginQrCodeContent: String? + ) -> Bool { + if let uiBridgeApiParameters = uiBridgeApiParametersFromLoginQrCodeContent( + loginQrCodeContent + ) { + loginWithFrontdoorBridgeUrl( + uiBridgeApiParameters.frontdoorBridgeUrl, + pkceCodeVerifier: uiBridgeApiParameters.pkceCodeVerifier + ) + return true + } else { + return false + } + } + + /** + * Automatically log in with a UI Bridge API front door bridge URL and PKCE code verifier. + * - Parameters + * - frontdoorBridgeUrl: The UI Bridge API front door bridge URL + * - pkceCodeVerifier: The PKCE code verifier + */ + func loginWithFrontdoorBridgeUrl( + _ frontdoorBridgeUrlString: String, + pkceCodeVerifier: String? + ) { + print("Login With Frontdoor Bridge URL: '\(frontdoorBridgeUrlString)'/'\(String(describing: pkceCodeVerifier))'.") + + // TODO: W-16171402: Integrate With Existing Login Logic And Resolve Use Of PKCE Code Verifier. ECJ20240912 + + guard let frontdoorBridgeUrl = URL(string: frontdoorBridgeUrlString) else { return } + guard let webView = oauthView as? WKWebView else { return } + webView.load(URLRequest(url: frontdoorBridgeUrl)) + } + + // MARK: QR Code Login Via UI Bridge API Private Implementation + +// /** +// * Determines if QR code login is enabled for the provided intent. +// * @param intent The intent to determine QR code login enablement for +// * @return Boolean true if QR code login is enabled for the the intent or +// * false otherwise +// */ +// private fun isDeepLinkedQrCodeLogin( +// intent: Intent +// ) = SalesforceSDKManager.getInstance().isQrCodeLoginEnabled +// && intent.data?.path?.contains(LOGIN_QR_PATH) == true +// + /** + * Parses UI Bridge API parameters from the provided login QR code content. + * - Parameters + * - loginQrCodeContent: The login QR code content string + * - UiBridgeApiParameters: The UI Bridge API parameters or null if the QR code content cannot + * provide them for any reason + */ + private func uiBridgeApiParametersFromLoginQrCodeContent( + _ loginQrCodeContent: String? + ) -> UiBridgeApiParameters? { + guard let loginQrCodeContentUnwrapped = loginQrCodeContent else { return nil } + guard let uiBridgeApiJson = uiBridgeApiJsonFromQrCodeContent(loginQrCodeContentUnwrapped) else { return nil } + return uiBridgeApiParametersFromUiBridgeApiJson(uiBridgeApiJson) + } + + /** + * Parses UI Bridge API parameters JSON from the provided string, which may be formatted to match + * either QR code content provided by app's QR code library or a custom app deep link from an external + * QR code reader. + * + * TODO: W-16171402: Verify this after developing template app's external QR code deep-link support. ECJ20240912 + * + * 1. From external QR reader: ?bridgeJson={...} + * 2. From the app's QR reader: ?bridgeJson=%7B...%7D + * + * - Parameters + * - qrCodeContent: The QR code content string + * - Returns: String: The UI Bridge API parameter JSON or null if the string cannot provide the + * JSON for any reason + */ + private func uiBridgeApiJsonFromQrCodeContent( + _ qrCodeContent: String + ) -> String? { + return try? NSRegularExpression( + pattern: "^.*\\?bridgeJson=").stringByReplacingMatches( + in: qrCodeContent, + range: NSRange( + location: 0, + length: qrCodeContent.utf16.count), + withTemplate: "").removingPercentEncoding + } + + /** + * Creates UI Bridge API parameters from the provided JSON string. + * - Parameters + * - uiBridgeApiParameterJsonString: The UI Bridge API parameters JSON string + * - Returns: The UI Bridge API parameters + */ + private func uiBridgeApiParametersFromUiBridgeApiJson( + _ uiBridgeApiParameterJsonString: String + ) -> UiBridgeApiParameters? { + guard let uiBridgeApiParameterJsonData = uiBridgeApiParameterJsonString.data( + using: .utf8 + ) else { return nil } + + do { return try JSONDecoder().decode( + UiBridgeApiParameters.self, + from: uiBridgeApiParameterJsonData) + } catch let error { + SFSDKCoreLogger().e( + classForCoder, + message: "Cannot JSON encode start password reset request body due to an encoding error with description '\(error.localizedDescription)'.") + return nil + } + } + + /** + * A struct representing UI Bridge API parameters provided by a login QR code. + */ + private struct UiBridgeApiParameters: Codable { + + /** The front door bridge URL provided by the login QR code */ + let frontdoorBridgeUrl: String + + /** The PKCE code verifier provided by the login QR code */ + let pkceCodeVerifier: String? + + enum CodingKeys: String, CodingKey { + case frontdoorBridgeUrl = "frontdoor_bridge_url" + case pkceCodeVerifier = "pkce_code_verifier" + } + } +} diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h index 9cd9b5bc59..a279f638cc 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h @@ -66,6 +66,9 @@ NS_SWIFT_NAME(SalesforceLoginViewController) */ @property (nonatomic, strong, nullable) IBOutlet UIView *oauthView; +/** The biometric log in button */ +@property (nonatomic, strong, readonly, nullable) UIButton *biometricButton; + /** Specify the font to use for navigation bar header text.*/ @property (nonatomic, strong, nullable) UIFont * navBarFont NS_SWIFT_NAME(navigationBarFont); diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.m index 81b572cd4f..2eca6a0876 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.m @@ -336,7 +336,7 @@ - (SFSDKLoginHostListViewController *)loginHostListViewController { return _loginHostListViewController; } -#pragma mark - Properties` +#pragma mark - Properties - (void)setOauthView:(UIView *)oauthView { if (![oauthView isEqual:_oauthView]) { diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFSDKLoginViewControllerConfig.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFSDKLoginViewControllerConfig.h index d5b7726485..524613b142 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFSDKLoginViewControllerConfig.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFSDKLoginViewControllerConfig.h @@ -53,6 +53,6 @@ NS_SWIFT_NAME(SalesforceLoginViewControllerConfig) /** Specifiy a delegate for LoginViewController. */ @property (nonatomic, weak, nullable) id delegate; -@property (nonatomic, copy, nullable) SFLoginViewControllerCreationBlock loginViewControllerCreationBlock; +@property (nonatomic, copy, nullable) SFLoginViewControllerCreationBlock loginViewControllerCreationBlock; @end From 38ba3b021c69079e319d248f4fec156e10d8dfc1 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Fri, 20 Sep 2024 12:35:06 -0600 Subject: [PATCH 2/7] @W-16362973: [iOS] Add QR Code Login Support in MSDK (Introduce `isQrCodeLoginEnabled`. Functional P.O.C.) --- .../Classes/Common/SalesforceSDKManager.h | 3 +++ .../Classes/Login/SFLoginViewController+QrCodeLogin.swift | 7 ++++--- .../SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.h index 743ee41d27..eaeb63071f 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.h @@ -225,6 +225,9 @@ NS_SWIFT_NAME(SalesforceManager) */ @property (nonatomic, assign) BOOL isLoginWebviewInspectable; +/*** Indicates if login via QR Code and UI bridge API is enabled */ +@property (nonatomic, assign) BOOL isQrCodeLoginEnabled; + /** The type of cache used for the shared URL cache, defaults to kSFURLCacheTypeEncrypted. */ @property (nonatomic, assign) SFURLCacheType URLCacheType; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift index aac233386f..afebf321ec 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift @@ -51,11 +51,12 @@ public extension SalesforceLoginViewController { ) { print("Login With Frontdoor Bridge URL: '\(frontdoorBridgeUrlString)'/'\(String(describing: pkceCodeVerifier))'.") - // TODO: W-16171402: Integrate With Existing Login Logic And Resolve Use Of PKCE Code Verifier. ECJ20240912 - guard let frontdoorBridgeUrl = URL(string: frontdoorBridgeUrlString) else { return } guard let webView = oauthView as? WKWebView else { return } - webView.load(URLRequest(url: frontdoorBridgeUrl)) + + DispatchQueue.main.async { + webView.load(URLRequest(url: frontdoorBridgeUrl)) + } } // MARK: QR Code Login Via UI Bridge API Private Implementation diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m index 00d317a99f..ea01b90791 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m @@ -791,7 +791,7 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati NSURL *url = navigationAction.request.URL; NSString *requestUrl = [url absoluteString]; if ([self isRedirectURL:requestUrl]) { - if ([[SalesforceSDKManager sharedManager] useWebServerAuthentication]) { + if ([[SalesforceSDKManager sharedManager] useWebServerAuthentication] && ![[SalesforceSDKManager sharedManager] isQrCodeLoginEnabled]) { [self handleWebServerResponse:url]; } else { [self handleUserAgentResponse:url]; From 98c20f04792905f4097e53d245e5d7c74eb968e1 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Fri, 20 Sep 2024 15:30:16 -0600 Subject: [PATCH 3/7] @W-16362973: [iOS] Add QR Code Login Support in MSDK (Self Review Cleanup) --- .../SFLoginViewController+QrCodeLogin.swift | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift index afebf321ec..3e912e4ef5 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift @@ -3,13 +3,33 @@ // SalesforceSDKCore // // Created by Eric Johnson on 9/5/24. +// Copyright (c) 2024-present, salesforce.com, inc. All rights reserved. // +// Redistribution and use of this software in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, this list of conditions +// and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of salesforce.com, inc. nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission of salesforce.com, inc. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY +// WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import Foundation public extension SalesforceLoginViewController { - // MARK: QR Code Login Via UI Bridge API Public Implementation + // MARK: - QR Code Login Via UI Bridge API Public Implementation /** * Automatically log in with a UI Bridge API login QR code. @@ -49,7 +69,6 @@ public extension SalesforceLoginViewController { _ frontdoorBridgeUrlString: String, pkceCodeVerifier: String? ) { - print("Login With Frontdoor Bridge URL: '\(frontdoorBridgeUrlString)'/'\(String(describing: pkceCodeVerifier))'.") guard let frontdoorBridgeUrl = URL(string: frontdoorBridgeUrlString) else { return } guard let webView = oauthView as? WKWebView else { return } @@ -59,19 +78,8 @@ public extension SalesforceLoginViewController { } } - // MARK: QR Code Login Via UI Bridge API Private Implementation + // MARK: - QR Code Login Via UI Bridge API Private Implementation -// /** -// * Determines if QR code login is enabled for the provided intent. -// * @param intent The intent to determine QR code login enablement for -// * @return Boolean true if QR code login is enabled for the the intent or -// * false otherwise -// */ -// private fun isDeepLinkedQrCodeLogin( -// intent: Intent -// ) = SalesforceSDKManager.getInstance().isQrCodeLoginEnabled -// && intent.data?.path?.contains(LOGIN_QR_PATH) == true -// /** * Parses UI Bridge API parameters from the provided login QR code content. * - Parameters @@ -92,8 +100,6 @@ public extension SalesforceLoginViewController { * either QR code content provided by app's QR code library or a custom app deep link from an external * QR code reader. * - * TODO: W-16171402: Verify this after developing template app's external QR code deep-link support. ECJ20240912 - * * 1. From external QR reader: ?bridgeJson={...} * 2. From the app's QR reader: ?bridgeJson=%7B...%7D * @@ -133,7 +139,7 @@ public extension SalesforceLoginViewController { } catch let error { SFSDKCoreLogger().e( classForCoder, - message: "Cannot JSON encode start password reset request body due to an encoding error with description '\(error.localizedDescription)'.") + message: "Cannot JSON decode UI bridge API parameters due to a decoding error with description '\(error.localizedDescription)'.") return nil } } From 90b0be6507cfedce1f7bdcd25714fa68b04f23c1 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Mon, 23 Sep 2024 13:51:17 -0600 Subject: [PATCH 4/7] @W-16362973: [iOS] Add QR Code Login Support in MSDK (Prototype Dynamic Handling Of Query String Vs. Fragment) --- .../Classes/OAuth/SFOAuthCoordinator.m | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m index ea01b90791..eeed68e49b 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m @@ -791,10 +791,15 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati NSURL *url = navigationAction.request.URL; NSString *requestUrl = [url absoluteString]; if ([self isRedirectURL:requestUrl]) { - if ([[SalesforceSDKManager sharedManager] useWebServerAuthentication] && ![[SalesforceSDKManager sharedManager] isQrCodeLoginEnabled]) { - [self handleWebServerResponse:url]; + if ([url query]) { + [self handleWebServerResponse:url]; // Handles URLs with query string parameter. + } else if ([url fragment]) { + [self handleUserAgentResponse:url]; // Handles URLs with the fragment component. } else { - [self handleUserAgentResponse:url]; + [SFSDKCoreLogger + i:[self class] + format:@"Web view cannot decide navigation action policy for callback URL without query or fragment. Bailing."]; + return; } decisionHandler(WKNavigationActionPolicyCancel); } else if ([self isSPAppRedirectURL:requestUrl]){ From f5ea72c70dcd9e3b4a094173b5c21a123fdc84f3 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Thu, 26 Sep 2024 14:20:28 -0600 Subject: [PATCH 5/7] @W-16362973: [iOS] Add QR Code Login Support in MSDK (Update `SFSDKAuthHelper` With QR Code Log In Parameters) --- .../SFLoginViewController+QrCodeLogin.swift | 14 +++- .../OAuth/SFOAuthCoordinator+Internal.h | 6 ++ .../Classes/OAuth/SFOAuthCoordinator.m | 29 +++---- .../SFUserAccountManager+Internal.h | 12 ++- .../UserAccount/SFUserAccountManager.m | 75 +++++++++++++++++-- .../Classes/Util/SFSDKAuthHelper.h | 23 ++++++ .../Classes/Util/SFSDKAuthHelper.m | 39 ++++++++-- 7 files changed, 167 insertions(+), 31 deletions(-) diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift index 3e912e4ef5..7b3714adf3 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController+QrCodeLogin.swift @@ -69,12 +69,18 @@ public extension SalesforceLoginViewController { _ frontdoorBridgeUrlString: String, pkceCodeVerifier: String? ) { - guard let frontdoorBridgeUrl = URL(string: frontdoorBridgeUrlString) else { return } - guard let webView = oauthView as? WKWebView else { return } - DispatchQueue.main.async { - webView.load(URLRequest(url: frontdoorBridgeUrl)) + // Stop current authentication attempt, if applicable, before starting the new one. + UserAccountManager.shared.stopCurrentAuthentication { result in + + DispatchQueue.main.async { + // Login using front door bridge URL and PKCE code verifier provided by the QR code. + AuthHelper.loginIfRequired(nil, + frontDoorBridgeUrl: frontdoorBridgeUrl, + codeVerifier: pkceCodeVerifier) { + } + } } } diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator+Internal.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator+Internal.h index e841b7d83a..1acc1995f1 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator+Internal.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator+Internal.h @@ -48,6 +48,12 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong ,nullable) SFOAuthCredentials *spAppCredentials; @property (nonatomic, weak, nullable) SFSDKAuthSession *authSession; +/// For Salesforce Identity UI Bridge API support, an overriding front door bridge URL to use in place of the default inital URL. +@property (nonatomic, strong, nullable) NSURL *overrideWithfrontDoorBridgeUrl; + +/// For Salesforce Identity UI Bridge API support, the optional web server flow code verififer accompaning the front door bridge URL. This can only be used with `overrideWithfrontDoorBridgeUrl`. +@property (nonatomic, strong, nullable) NSString *overrideWithCodeVerifier; + - (instancetype)initWithAuthSession:(SFSDKAuthSession *)authSession; /** UpdateCredentials and record changes to instanceUrl,accessToken,communityId diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m index eeed68e49b..c61f738636 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m @@ -547,7 +547,13 @@ - (void)loadWebViewWithUrlString:(NSString *)urlString cookie:(BOOL)enableCookie [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; // don't use cache [SFSDKCoreLogger d:[self class] format:@"%@ Loading web view for '%@' auth flow, with URL: %@", NSStringFromSelector(_cmd), self.authInfo.authTypeDescription, [urlToLoad sfsdk_redactedAbsoluteString:@[ @"sid" ]]]; dispatch_async(dispatch_get_main_queue(), ^{ - [self.view loadRequest:request]; + // If an overriding Salesforce Identity API UI Bridge front door bridge is present, load it. + if (self.overrideWithfrontDoorBridgeUrl) { + [self.view loadRequest:[NSURLRequest requestWithURL:self.overrideWithfrontDoorBridgeUrl]]; + + } else { + [self.view loadRequest:request]; + } }); } - (void)updateCredentials:(NSDictionary *) params { @@ -568,8 +574,8 @@ - (void)beginTokenEndpointFlow { if (self.approvalCode) { [SFSDKCoreLogger i:[self class] format:@"%@: Initiating authorization code flow.", NSStringFromSelector(_cmd)]; request.approvalCode = self.approvalCode; - request.codeVerifier = self.codeVerifier; - + // Choose either the default generated code verifier or the code verifier matching the overriding Salesforce Identity API UI Bridge front door bridge. + request.codeVerifier = self.overrideWithCodeVerifier ? self.overrideWithCodeVerifier : self.codeVerifier; [self.authClient accessTokenForApprovalCode:request completion:^(SFSDKOAuthTokenEndpointResponse * response) { __strong typeof (weakSelf) strongSelf = weakSelf; [strongSelf handleResponse:response]; @@ -750,8 +756,8 @@ - (NSString *)approvalURLForEndpoint:(NSString *)authorizeEndpoint if (!codeChallenge) { // Code verifier challenge: - // - self.codeVerifier is a base64url-encoded random data string - // - The code challenge sent here is an SHA-256 hash of self.codeVerifier, also base64url-encoded + // - self.codeVerifier is a Base64 URL-Safe encoded (Note, not URL encoded) random data string + // - The code challenge sent here is an SHA-256 hash of self.codeVerifier, also Base64 URL-Safe encoded // - Later, self.codeVerifier will be sent to the service, to be used to compare against the initial code challenge sent here. self.codeVerifier = [[SFSDKCryptoUtils randomByteDataWithLength:kSFOAuthCodeVerifierByteLength] sfsdk_base64UrlString]; codeChallenge = [[[self.codeVerifier dataUsingEncoding:NSUTF8StringEncoding] sfsdk_sha256Data] sfsdk_base64UrlString]; @@ -791,15 +797,12 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati NSURL *url = navigationAction.request.URL; NSString *requestUrl = [url absoluteString]; if ([self isRedirectURL:requestUrl]) { - if ([url query]) { - [self handleWebServerResponse:url]; // Handles URLs with query string parameter. - } else if ([url fragment]) { - [self handleUserAgentResponse:url]; // Handles URLs with the fragment component. + // Determine if presence of override parameters requiring the user agent flow. + BOOL overrideWithUserAgentFlow = self.overrideWithfrontDoorBridgeUrl && !self.overrideWithCodeVerifier; + if ( [[SalesforceSDKManager sharedManager] useWebServerAuthentication] && !overrideWithUserAgentFlow) { + [self handleWebServerResponse:url]; // Web server flow/URLs with query string parameters. } else { - [SFSDKCoreLogger - i:[self class] - format:@"Web view cannot decide navigation action policy for callback URL without query or fragment. Bailing."]; - return; + [self handleUserAgentResponse:url]; // User agent flow/URLs with the fragment component. } decisionHandler(WKNavigationActionPolicyCancel); } else if ([self isSPAppRedirectURL:requestUrl]){ diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager+Internal.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager+Internal.h index e084b2b4f9..2d10dfa94d 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager+Internal.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager+Internal.h @@ -192,7 +192,11 @@ Set this block to handle presentation of the Authentication View Controller. - (BOOL)authenticateUsingIDP:(SFSDKAuthRequest *)request completion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock; -- (BOOL)authenticateWithRequest:(SFSDKAuthRequest *)request completion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock; +- (BOOL)authenticateWithRequest:(SFSDKAuthRequest *)request + completion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock + failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock + frontDoorBridgeUrl:(nullable NSURL * )frontDoorBridgeUrl + codeVerifier:(nullable NSString *)codeVerifier; - (SFSDKAuthRequest *)defaultAuthRequest; @@ -200,6 +204,12 @@ Set this block to handle presentation of the Authentication View Controller. failure:(nullable SFUserAccountManagerFailureCallbackBlock)failureBlock scene:(nullable UIScene *)scene; +- (BOOL)loginWithCompletion:(nullable SFUserAccountManagerSuccessCallbackBlock)completionBlock + failure:(nullable SFUserAccountManagerFailureCallbackBlock)failureBlock + scene:(UIScene *)scene + frontDoorBridgeUrl:(nullable NSURL * )frontDoorBridgeUrl + codeVerifier:(nullable NSString *)codeVerifier; + @end NS_ASSUME_NONNULL_END diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m index 6745e21938..23ed04ac81 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m @@ -405,8 +405,28 @@ - (BOOL)loginWithCompletion:(SFUserAccountManagerSuccessCallbackBlock)completion return result; } -- (BOOL)loginWithCompletion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock scene:(UIScene *)scene { - return [self authenticateWithCompletion:completionBlock failure:failureBlock scene:scene]; +- (BOOL)loginWithCompletion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock + failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock + scene:(UIScene *)scene +{ + return [self loginWithCompletion:completionBlock + failure:failureBlock + scene:scene + frontDoorBridgeUrl:nil + codeVerifier:nil]; +} + +- (BOOL)loginWithCompletion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock + failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock + scene:(UIScene *)scene + frontDoorBridgeUrl:(nullable NSURL * )frontDoorBridgeUrl + codeVerifier:(nullable NSString *)codeVerifier +{ + return [self authenticateWithCompletion:completionBlock + failure:failureBlock + scene:scene + frontDoorBridgeUrl:frontDoorBridgeUrl + codeVerifier:codeVerifier]; } - (BOOL)refreshCredentials:(SFOAuthCredentials *)credentials completion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock { @@ -478,7 +498,23 @@ - (void)stopCurrentAuthentication:(void (^)(BOOL))completionBlock { } } -- (BOOL)authenticateWithCompletion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock scene:(UIScene *)scene { +- (BOOL)authenticateWithCompletion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock + failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock + scene:(UIScene *)scene +{ + return [self authenticateWithCompletion:completionBlock + failure:failureBlock + scene:scene + frontDoorBridgeUrl:nil + codeVerifier:nil]; +} + +- (BOOL)authenticateWithCompletion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock + failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock + scene:(UIScene *)scene + frontDoorBridgeUrl:(NSURL * )frontDoorBridgeUrl + codeVerifier:(NSString *)codeVerifier +{ SFSDKAuthSession *authSession = self.authSessions[scene.session.persistentIdentifier]; if (authSession && authSession.isAuthenticating) { [SFSDKCoreLogger e:[self class] format:@"Login has already been called. Stop current authentication using SFUserAccountManager::stopCurrentAuthentication and then retry."]; @@ -499,7 +535,11 @@ - (BOOL)authenticateWithCompletion:(SFUserAccountManagerSuccessCallbackBlock)com if (request.idpEnabled) { return [self authenticateUsingIDP:request completion:completionBlock failure:failureBlock]; } - return [self authenticateWithRequest:request completion:completionBlock failure:failureBlock]; + return [self authenticateWithRequest:request + completion:completionBlock + failure:failureBlock + frontDoorBridgeUrl:frontDoorBridgeUrl + codeVerifier:codeVerifier]; } -(SFSDKAuthRequest *)defaultAuthRequest { @@ -530,12 +570,19 @@ -(SFSDKAuthRequest *)nativeLoginAuthRequest { return request; } -- (BOOL)authenticateWithRequest:(SFSDKAuthRequest *)request completion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock { +- (BOOL)authenticateWithRequest:(SFSDKAuthRequest *)request + completion:(SFUserAccountManagerSuccessCallbackBlock)completionBlock + failure:(SFUserAccountManagerFailureCallbackBlock)failureBlock + frontDoorBridgeUrl:(NSURL * )frontDoorBridgeUrl + codeVerifier:(NSString *)codeVerifier +{ SFSDKAuthSession *authSession = [[SFSDKAuthSession alloc] initWith:request credentials:nil]; authSession.isAuthenticating = YES; authSession.authFailureCallback = failureBlock; authSession.authSuccessCallback = completionBlock; authSession.oauthCoordinator.delegate = self; + authSession.oauthCoordinator.overrideWithCodeVerifier = codeVerifier; + authSession.oauthCoordinator.overrideWithfrontDoorBridgeUrl = frontDoorBridgeUrl; NSString *sceneId = authSession.sceneId; self.authSessions[sceneId] = authSession; @@ -568,7 +615,11 @@ - (BOOL)loginWithJwtToken:(NSString *)jwtToken completion:(SFUserAccountManagerS NSAssert(jwtToken.length > 0, @"JWT token value required."); SFSDKAuthRequest *request = [self defaultAuthRequest]; request.jwtToken = jwtToken; - return [self authenticateWithRequest:request completion:completionBlock failure:failureBlock]; + return [self authenticateWithRequest:request + completion:completionBlock + failure:failureBlock + frontDoorBridgeUrl:nil + codeVerifier:nil]; } - (void)logout { @@ -612,7 +663,11 @@ - (void)restartAuthentication:(SFSDKAuthSession *)session { [self dismissAuthViewControllerIfPresentForScene:scene completion:^{ __strong typeof(weakSelf) strongSelf = weakSelf; strongSelf.authSessions[scene.session.persistentIdentifier].isAuthenticating = NO; - [strongSelf authenticateWithRequest:session.oauthRequest completion:session.authSuccessCallback failure:session.authFailureCallback]; + [strongSelf authenticateWithRequest:session.oauthRequest + completion:session.authSuccessCallback + failure:session.authFailureCallback + frontDoorBridgeUrl:nil + codeVerifier:nil]; }]; } @@ -995,7 +1050,11 @@ -(void)loginFlowSelectionLocalLoginSelected:(UIViewController *)controller optio NSString *sceneId = scene.session.persistentIdentifier; [self dismissAuthViewControllerIfPresentForScene:scene completion:^{ __strong typeof(weakSelf) strongSelf = weakSelf; - [strongSelf authenticateWithRequest:strongSelf.authSessions[sceneId].oauthRequest completion:strongSelf.authSessions[sceneId].authSuccessCallback failure:strongSelf.authSessions[sceneId].authFailureCallback]; + [strongSelf authenticateWithRequest:strongSelf.authSessions[sceneId].oauthRequest + completion:strongSelf.authSessions[sceneId].authSuccessCallback + failure:strongSelf.authSessions[sceneId].authFailureCallback + frontDoorBridgeUrl:nil + codeVerifier:nil]; }]; } diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.h index 99f1d1c670..e066b2a43a 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.h @@ -49,6 +49,29 @@ NS_SWIFT_NAME(AuthHelper) */ + (void)loginIfRequired:(UIScene *)scene completion:(nullable void (^)(void))completionBlock; +/** + Initiate a login flow if the user is not already logged in to Salesforce and if the app config's + `shouldAuthenticate` flag is set to false. + + Parameters here include support for an optional overriding Salesforce Identity UI Bridge API front door bridge + URL with an optional overriding code verifier. These override the default login URL to load and the default + code verifier that would be generated for it when web server authentication is enabled. One use case for this + is automatic login from a front door bridge URL provided as part of a QR code log in set up. + + @param scene Scene that login is initiated for. + @param completionBlock Block that executes immediately if the user is already logged in or if the app + config's `shouldAuthenticate` is set to false. Otherwise, this block executes after the user logs in successfully + if login is required. + @param frontDoorBridgeUrl Optionally, a Salesforce Identity API front door bridge URL to use in place + of the default log in URL + @param codeVerifier Optionally and only with the front door bridge URL parameter, a code verifier to use + when the front door bridge URL is using web server authentication + */ ++ (void)loginIfRequired:(nullable UIScene *)scene + frontDoorBridgeUrl:(nullable NSURL * )frontDoorBridgeUrl + codeVerifier:(nullable NSString *)codeVerifier + completion:(void (^)(void))completionBlock; + + (void)handleLogout:(nullable void (^)(void))completionBlock; + (void)handleLogout:(UIScene *)scene completion:(nullable void (^)(void))completionBlock; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.m index f8b89c35e9..cf07634568 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Util/SFSDKAuthHelper.m @@ -40,11 +40,30 @@ @implementation SFSDKAuthHelper + (void)loginIfRequired:(void (^)(void))completionBlock { - UIScene *scene = [[SFSDKWindowManager sharedManager] defaultScene]; - [SFSDKAuthHelper loginIfRequired:scene completion:completionBlock]; + [SFSDKAuthHelper + loginIfRequired:[[SFSDKWindowManager sharedManager] defaultScene] + completion:completionBlock]; +} + ++ (void)loginIfRequired:(UIScene *)scene + completion:(void (^)(void))completionBlock +{ + [SFSDKAuthHelper + loginIfRequired:scene + frontDoorBridgeUrl:nil + codeVerifier:nil + completion:completionBlock]; } -+ (void)loginIfRequired:(UIScene *)scene completion:(void (^)(void))completionBlock { ++ (void)loginIfRequired:(UIScene *)scene + frontDoorBridgeUrl:(NSURL * )frontDoorBridgeUrl + codeVerifier:(NSString *)codeVerifier + completion:(void (^)(void))completionBlock +{ + if (!scene) { + scene = [[SFSDKWindowManager sharedManager] defaultScene]; + } + [SFSDKAuthHelper registerBlockForLoginNotification:^{ if (completionBlock) { completionBlock(); @@ -55,10 +74,20 @@ + (void)loginIfRequired:(UIScene *)scene completion:(void (^)(void))completionBl SFUserAccountManagerFailureCallbackBlock failureBlock = ^(SFOAuthInfo *authInfo, NSError *authError) { [SFSDKCoreLogger e:[self class] format:@"Authentication failed: %@.", [authError localizedDescription]]; }; - BOOL result = [[SFUserAccountManager sharedInstance] loginWithCompletion:nil failure:failureBlock scene:scene]; + BOOL result = [[SFUserAccountManager sharedInstance] + loginWithCompletion:nil + failure:failureBlock + scene:scene + frontDoorBridgeUrl:frontDoorBridgeUrl + codeVerifier:codeVerifier]; if (!result) { [[SFUserAccountManager sharedInstance] stopCurrentAuthentication:^(BOOL result) { - [[SFUserAccountManager sharedInstance] loginWithCompletion:nil failure:failureBlock scene:scene]; + [[SFUserAccountManager sharedInstance] + loginWithCompletion:nil + failure:failureBlock + scene:scene + frontDoorBridgeUrl:frontDoorBridgeUrl + codeVerifier:codeVerifier]; }]; } } else { From 79b49d73bcb346f7f0ceb9b9a4314e531e3c70a3 Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Sun, 29 Sep 2024 11:29:38 -0600 Subject: [PATCH 6/7] @W-16362973: [iOS] Add QR Code Login Support in MSDK (Cosmetic Code Cleanup) --- .../Classes/OAuth/SFOAuthCoordinator+Internal.h | 6 +++--- .../SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m | 8 ++++---- .../Classes/UserAccount/SFUserAccountManager.m | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator+Internal.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator+Internal.h index 1acc1995f1..4c60accbc1 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator+Internal.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator+Internal.h @@ -48,10 +48,10 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong ,nullable) SFOAuthCredentials *spAppCredentials; @property (nonatomic, weak, nullable) SFSDKAuthSession *authSession; -/// For Salesforce Identity UI Bridge API support, an overriding front door bridge URL to use in place of the default inital URL. -@property (nonatomic, strong, nullable) NSURL *overrideWithfrontDoorBridgeUrl; +/// For Salesforce Identity UI Bridge API support, an overriding front door bridge URL to use in place of the default initial URL. +@property (nonatomic, strong, nullable) NSURL *overrideWithFrontDoorBridgeUrl; -/// For Salesforce Identity UI Bridge API support, the optional web server flow code verififer accompaning the front door bridge URL. This can only be used with `overrideWithfrontDoorBridgeUrl`. +/// For Salesforce Identity UI Bridge API support, the optional web server flow code verififer accompaning the front door bridge URL. This can only be used with `overrideWithfrontDoorBridgeUrl`. @property (nonatomic, strong, nullable) NSString *overrideWithCodeVerifier; - (instancetype)initWithAuthSession:(SFSDKAuthSession *)authSession; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m index c61f738636..baaa7b194f 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m @@ -548,8 +548,8 @@ - (void)loadWebViewWithUrlString:(NSString *)urlString cookie:(BOOL)enableCookie [SFSDKCoreLogger d:[self class] format:@"%@ Loading web view for '%@' auth flow, with URL: %@", NSStringFromSelector(_cmd), self.authInfo.authTypeDescription, [urlToLoad sfsdk_redactedAbsoluteString:@[ @"sid" ]]]; dispatch_async(dispatch_get_main_queue(), ^{ // If an overriding Salesforce Identity API UI Bridge front door bridge is present, load it. - if (self.overrideWithfrontDoorBridgeUrl) { - [self.view loadRequest:[NSURLRequest requestWithURL:self.overrideWithfrontDoorBridgeUrl]]; + if (self.overrideWithFrontDoorBridgeUrl) { + [self.view loadRequest:[NSURLRequest requestWithURL:self.overrideWithFrontDoorBridgeUrl]]; } else { [self.view loadRequest:request]; @@ -797,8 +797,8 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati NSURL *url = navigationAction.request.URL; NSString *requestUrl = [url absoluteString]; if ([self isRedirectURL:requestUrl]) { - // Determine if presence of override parameters requiring the user agent flow. - BOOL overrideWithUserAgentFlow = self.overrideWithfrontDoorBridgeUrl && !self.overrideWithCodeVerifier; + // Determine if presence of override parameters require the user agent flow. + BOOL overrideWithUserAgentFlow = self.overrideWithFrontDoorBridgeUrl && !self.overrideWithCodeVerifier; if ( [[SalesforceSDKManager sharedManager] useWebServerAuthentication] && !overrideWithUserAgentFlow) { [self handleWebServerResponse:url]; // Web server flow/URLs with query string parameters. } else { diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m index 23ed04ac81..a8d50ed84a 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m @@ -582,7 +582,7 @@ - (BOOL)authenticateWithRequest:(SFSDKAuthRequest *)request authSession.authSuccessCallback = completionBlock; authSession.oauthCoordinator.delegate = self; authSession.oauthCoordinator.overrideWithCodeVerifier = codeVerifier; - authSession.oauthCoordinator.overrideWithfrontDoorBridgeUrl = frontDoorBridgeUrl; + authSession.oauthCoordinator.overrideWithFrontDoorBridgeUrl = frontDoorBridgeUrl; NSString *sceneId = authSession.sceneId; self.authSessions[sceneId] = authSession; From 1b6787d18ae4be090e8778ae0598f7730e85daed Mon Sep 17 00:00:00 2001 From: "Eric C. Johnson" Date: Wed, 2 Oct 2024 13:47:43 -0600 Subject: [PATCH 7/7] @W-16362973: [iOS] Add QR Code Login Support in MSDK (Reset Front Door Bridge Parameters On Authorization Failure) --- .../Classes/OAuth/SFOAuthCoordinator.m | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m index baaa7b194f..e59268961a 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m @@ -344,6 +344,7 @@ - (void)notifyDelegateOfFailure:(NSError*)error authInfo:(SFOAuthInfo *)info }); } self.authInfo = nil; + [self resetFrontDoorBridgeUrl]; } - (void)notifyDelegateOfSuccess:(SFOAuthInfo *)authInfo @@ -353,6 +354,7 @@ - (void)notifyDelegateOfSuccess:(SFOAuthInfo *)authInfo [self.delegate oauthCoordinatorDidAuthenticate:self authInfo:authInfo]; } self.authInfo = nil; + [self resetFrontDoorBridgeUrl]; } - (void)notifyDelegateOfBeginAuthentication @@ -776,6 +778,15 @@ - (NSString *)approvalURLForEndpoint:(NSString *)authorizeEndpoint return approvalUrlString; } +/** + * Resets all state related to Salesforce Identity API UI Bridge front door bridge URL log in to its default + * inactive state. + */ +-(void) resetFrontDoorBridgeUrl { + self.overrideWithFrontDoorBridgeUrl = nil; + self.overrideWithCodeVerifier = nil; +} + - (NSString *)scopeQueryParamString { NSMutableSet *scopes = (self.scopes.count > 0 ? [NSMutableSet setWithSet:self.scopes] : [NSMutableSet set]); [scopes addObject:kSFOAuthRefreshToken];