Skip to content

Commit 80e3c77

Browse files
@W-18777800: [qr code scan][ios] we should prevent a successful login of client A by scanning QR code of client B (Code Review Updates)
1 parent 5307c18 commit 80e3c77

4 files changed

Lines changed: 64 additions & 46 deletions

File tree

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator+Internal.h

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@ typedef NS_ENUM(NSUInteger, SFOAuthTokenEndpointFlow) {
3333
};
3434
NS_ASSUME_NONNULL_BEGIN
3535

36+
@interface SFOAuthCoordinatorFrontdoorBridge: NSObject
37+
38+
/// For Salesforce Identity UI Bridge API support, an overriding front door bridge URL to use in place of the default initial URL.
39+
@property (nonatomic, strong, nullable) NSURL *overrideWithFrontDoorBridgeUrl;
40+
41+
/// 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`.
42+
@property (nonatomic, strong, nullable) NSString *overrideWithCodeVerifier;
43+
44+
/// For Salesforce Identity UI Bridge API support, indicates if overriding front door bridge URL has a consumer key value that matches the app config, which is also known as the boot config.
45+
@property (nonatomic, assign) BOOL overridingFrontDoorBridgeUrlMatchesConsumerKey;
46+
47+
- initWithFrontdoorBridgeUrl:(NSURL *)frontdoorBridgeUrl codeVerifier:(NSString *)codeVerifier;
48+
49+
@end
50+
3651
@interface SFOAuthCoordinator ()
3752

3853
@property (assign) BOOL authenticating;
@@ -48,14 +63,7 @@ NS_ASSUME_NONNULL_BEGIN
4863
@property (nonatomic, strong ,nullable) SFOAuthCredentials *spAppCredentials;
4964
@property (nonatomic, weak, nullable) SFSDKAuthSession *authSession;
5065

51-
/// For Salesforce Identity UI Bridge API support, an overriding front door bridge URL to use in place of the default initial URL.
52-
@property (nonatomic, strong, nullable) NSURL *overrideWithFrontDoorBridgeUrl;
53-
54-
/// 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`.
55-
@property (nonatomic, strong, nullable) NSString *overrideWithCodeVerifier;
56-
57-
/// For Salesforce Identity UI Bridge API support, indicates if overriding front door bridge URL has a consumer key value that matches the app config, which is also known as the boot config.
58-
@property (nonatomic, assign) BOOL overridingFrontDoorBridgeUrlMatchesConsumerKey;
66+
@property (nonatomic, strong, nullable) SFOAuthCoordinatorFrontdoorBridge *frontdoorBridge;
5967

6068
@property (nonatomic, strong, nullable) NSString *loginHint;
6169

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCoordinator.m

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ - (void)notifyDelegateOfFailure:(NSError*)error authInfo:(SFOAuthInfo *)info
347347
});
348348
}
349349
self.authInfo = nil;
350-
[self resetFrontDoorBridgeUrl];
350+
[self resetFrontDoorBridge];
351351
}
352352

353353
- (void)notifyDelegateOfSuccess:(SFOAuthInfo *)authInfo
@@ -357,7 +357,7 @@ - (void)notifyDelegateOfSuccess:(SFOAuthInfo *)authInfo
357357
[self.delegate oauthCoordinatorDidAuthenticate:self authInfo:authInfo];
358358
}
359359
self.authInfo = nil;
360-
[self resetFrontDoorBridgeUrl];
360+
[self resetFrontDoorBridge];
361361
}
362362

363363
- (void)notifyDelegateOfBeginAuthentication
@@ -553,8 +553,8 @@ - (void)loadWebViewWithUrlString:(NSString *)urlString cookie:(BOOL)enableCookie
553553
[SFSDKCoreLogger d:[self class] format:@"%@ Loading web view for '%@' auth flow, with URL: %@", NSStringFromSelector(_cmd), self.authInfo.authTypeDescription, [urlToLoad sfsdk_redactedAbsoluteString:@[ @"sid" ]]];
554554
dispatch_async(dispatch_get_main_queue(), ^{
555555
// If a valid overriding Salesforce Identity API UI Bridge front door bridge is present, load it.
556-
if (self.overrideWithFrontDoorBridgeUrl) {
557-
[self.view loadRequest:[NSURLRequest requestWithURL:self.overrideWithFrontDoorBridgeUrl]];
556+
if (self.frontdoorBridge.overrideWithFrontDoorBridgeUrl) {
557+
[self.view loadRequest:[NSURLRequest requestWithURL:self.frontdoorBridge.overrideWithFrontDoorBridgeUrl]];
558558

559559
} else {
560560
[self.view loadRequest:request];
@@ -580,7 +580,7 @@ - (void)beginTokenEndpointFlow {
580580
[SFSDKCoreLogger i:[self class] format:@"%@: Initiating authorization code flow.", NSStringFromSelector(_cmd)];
581581
request.approvalCode = self.approvalCode;
582582
// Choose either the default generated code verifier or the code verifier matching the overriding Salesforce Identity API UI Bridge front door bridge.
583-
request.codeVerifier = self.overrideWithCodeVerifier ? self.overrideWithCodeVerifier : self.codeVerifier;
583+
request.codeVerifier = self.frontdoorBridge.overrideWithCodeVerifier ? self.frontdoorBridge.overrideWithCodeVerifier : self.codeVerifier;
584584
[self.authClient accessTokenForApprovalCode:request completion:^(SFSDKOAuthTokenEndpointResponse * response) {
585585
__strong typeof (weakSelf) strongSelf = weakSelf;
586586
[strongSelf handleResponse:response];
@@ -791,10 +791,8 @@ - (NSString *)approvalURLForEndpoint:(NSString *)authorizeEndpoint
791791
* Resets all state related to Salesforce Identity API UI Bridge front door bridge URL log in to its default
792792
* inactive state.
793793
*/
794-
-(void) resetFrontDoorBridgeUrl {
795-
self.overridingFrontDoorBridgeUrlMatchesConsumerKey = YES;
796-
self.overrideWithFrontDoorBridgeUrl = nil;
797-
self.overrideWithCodeVerifier = nil;
794+
-(void) resetFrontDoorBridge {
795+
self.frontdoorBridge = nil;
798796
}
799797

800798
- (NSString *)scopeQueryParamString {
@@ -819,7 +817,7 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati
819817
NSString *requestUrl = [url absoluteString];
820818
if ([self isRedirectURL:requestUrl]) {
821819
// Determine if presence of override parameters require the user agent flow.
822-
BOOL overrideWithUserAgentFlow = self.overrideWithFrontDoorBridgeUrl && !self.overrideWithCodeVerifier;
820+
BOOL overrideWithUserAgentFlow = self.frontdoorBridge.overrideWithFrontDoorBridgeUrl && !self.frontdoorBridge.overrideWithCodeVerifier;
823821
if ( [[SalesforceSDKManager sharedManager] useWebServerAuthentication] && !overrideWithUserAgentFlow) {
824822
[self handleWebServerResponse:url]; // Web server flow/URLs with query string parameters.
825823
} else {
@@ -983,3 +981,30 @@ - (NSString *)brandedAuthorizeURL{
983981
}
984982

985983
@end
984+
985+
@implementation SFOAuthCoordinatorFrontdoorBridge
986+
987+
- initWithFrontdoorBridgeUrl:(NSURL *)frontdoorBridgeUrl codeVerifier:(NSString *)codeVerifier {
988+
self = [super init];
989+
990+
NSURLComponents * frontdoorBridgeUrlComponents = [NSURLComponents
991+
componentsWithURL: frontdoorBridgeUrl
992+
resolvingAgainstBaseURL:YES];
993+
NSArray<NSURLQueryItem *> * frontdoorBridgeUrlQueryItems = frontdoorBridgeUrlComponents.queryItems;
994+
NSString * startUrlString = [frontdoorBridgeUrlQueryItems filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name == 'startURL'"]][0].value;
995+
NSURL * startUrl = [[NSURL alloc] initWithString:startUrlString];
996+
NSURLComponents * startUrlComponents = [NSURLComponents componentsWithURL: startUrl resolvingAgainstBaseURL: YES];
997+
NSArray<NSURLQueryItem *> * startUrlQueryItems = startUrlComponents.queryItems;
998+
NSString * frontdoorBridgeUrlClientId = [startUrlQueryItems filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name == 'client_id'"]][0].value;
999+
1000+
self.overridingFrontDoorBridgeUrlMatchesConsumerKey = [frontdoorBridgeUrlClientId isEqualToString:[[SalesforceSDKManager sharedManager] appConfig].remoteAccessConsumerKey];
1001+
1002+
if (self.overridingFrontDoorBridgeUrlMatchesConsumerKey) {
1003+
self.overrideWithCodeVerifier = codeVerifier;
1004+
self.overrideWithFrontDoorBridgeUrl = frontdoorBridgeUrl;
1005+
}
1006+
1007+
return self;
1008+
}
1009+
1010+
@end

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager.m

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#import "SFSDKIDPAuthCodeLoginRequestCommand.h"
6969
#import <SalesforceSDKCommon/SFJsonUtils.h>
7070
#import "SFSDKOAuth2+Internal.h"
71+
#import "SFSDKResourceUtils.h"
7172

7273
// Notifications
7374
NSNotificationName SFUserAccountManagerDidChangeUserNotification = @"SFUserAccountManagerDidChangeUserNotification";
@@ -598,11 +599,9 @@ - (BOOL)authenticateWithRequest:(SFSDKAuthRequest *)request
598599

599600
// Only allow use of front door bridge URLs with matching consumer keys.
600601
if (frontDoorBridgeUrl != nil) {
601-
authSession.oauthCoordinator.overridingFrontDoorBridgeUrlMatchesConsumerKey = [self validateBootConfigConsumerKeyMatches:frontDoorBridgeUrl];
602-
if (authSession.oauthCoordinator.overridingFrontDoorBridgeUrlMatchesConsumerKey) {
603-
authSession.oauthCoordinator.overrideWithCodeVerifier = codeVerifier;
604-
authSession.oauthCoordinator.overrideWithFrontDoorBridgeUrl = frontDoorBridgeUrl;
605-
}
602+
authSession.oauthCoordinator.frontdoorBridge = [[SFOAuthCoordinatorFrontdoorBridge alloc]
603+
initWithFrontdoorBridgeUrl:frontDoorBridgeUrl
604+
codeVerifier:codeVerifier];
606605
}
607606
authSession.oauthCoordinator.loginHint = loginHint;
608607
NSString *sceneId = authSession.sceneId;
@@ -922,10 +921,10 @@ - (void)oauthCoordinator:(SFOAuthCoordinator *)coordinator didBeginAuthenticatio
922921
void (^authViewDisplayBlock)(void) = ^{
923922

924923
self.authViewHandler.authViewDisplayBlock(viewHolder);
925-
if (!coordinator.overridingFrontDoorBridgeUrlMatchesConsumerKey) {
924+
if (coordinator.frontdoorBridge && !coordinator.frontdoorBridge.overridingFrontDoorBridgeUrlMatchesConsumerKey) {
926925
UIAlertController* alertController = [UIAlertController
927926
alertControllerWithTitle:@"Error"
928-
message:@"Cannot use another app's login QR Code. Please log in to this app."
927+
message:[SFSDKResourceUtils localizedString:@"frontdoorLoginUrlConsumerKeyMismatchErrorText"]
929928
preferredStyle:UIAlertControllerStyleAlert];
930929
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
931930
[loginViewController
@@ -2128,21 +2127,6 @@ - (void)fireNotificationForSwitchUserFrom:(SFUserAccount *)fromUser to:(SFUserAc
21282127
}];
21292128
}
21302129

2131-
- (BOOL)validateBootConfigConsumerKeyMatches:(NSURL *)frontdoorBridgeUrl {
2132-
2133-
NSURLComponents * frontdoorBridgeUrlComponents = [NSURLComponents
2134-
componentsWithURL: frontdoorBridgeUrl
2135-
resolvingAgainstBaseURL:YES];
2136-
NSArray<NSURLQueryItem *> * frontdoorBridgeUrlQueryItems = frontdoorBridgeUrlComponents.queryItems;
2137-
NSString * startUrlString = [frontdoorBridgeUrlQueryItems filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name == 'startURL'"]][0].value;
2138-
NSURL * startUrl = [[NSURL alloc] initWithString:startUrlString];
2139-
NSURLComponents * startUrlComponents = [NSURLComponents componentsWithURL: startUrl resolvingAgainstBaseURL: YES];
2140-
NSArray<NSURLQueryItem *> * startUrlQueryItems = startUrlComponents.queryItems;
2141-
NSString * frontdoorBridgeUrlClientId = [startUrlQueryItems filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"name == 'client_id'"]][0].value;
2142-
2143-
return [frontdoorBridgeUrlClientId isEqualToString:[[SalesforceSDKManager sharedManager] appConfig].remoteAccessConsumerKey];
2144-
}
2145-
21462130
#pragma mark - User Change Notifications
21472131

21482132
- (void)notifyUserDataChange:(NSString *)notificationName withUser:(SFUserAccount *)user andChange:(SFUserAccountDataChange)change {

shared/resources/SalesforceSDKResources.bundle/en.lproj/Localizable.strings

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,16 @@
4343
"bioPromtpCancel" = "Use Password";
4444

4545
// OAuth flow
46-
"authAlertContinueButton"="Continue";
46+
"authAlertContinueButton" = "Continue";
4747
"authAlertErrorTitle" = "Server Error";
4848
"authAlertOkButton" = "OK";
49-
"authAlertCancelButton"="Cancel";
49+
"authAlertCancelButton" = "Cancel";
5050
"authAlertRetryButton" = "Retry";
5151
"authAlertDismissButton" = "Dismiss";
5252
"authAlertConnectionErrorFormatString" = "Can't connect to the server: %@";
5353
"authAlertVersionMismatchError" = "Your app has been updated, and you will need to log in again to continue using the app.";
54-
"authAlertBrowserFlowTitle"="Log In";
54+
"authAlertBrowserFlowTitle" = "Log In";
55+
"frontdoorLoginUrlConsumerKeyMismatchErrorText" = "Cannot use another app's login QR Code. Please log in to this app.";
5556

5657
// LoginViewController
5758
"TITLE_LOGIN" = "Log In";
@@ -66,7 +67,7 @@
6667
"LOGIN_SERVER_NAME_PLACEHOLDER" = "Optional";
6768
"DONE_BUTTON" = "Done";
6869

69-
//Account Switcher
70+
// Account Switcher
7071
"ACCOUNT_SWITCHER_TITLE" = "Manage Accounts";
7172
"LOG_OUT" = "Log Out";
7273
"ADD_NEW_ACCOUNT" = "Add New Account";
@@ -106,12 +107,12 @@
106107
"devInfoOKKey" = "OK";
107108
"devInfoCancelKey" = "Cancel";
108109

109-
//IDP User Selection Screen
110+
// IDP User Selection Screen
110111
"idpSelectUserLabel" = "Select your account to log in to";
111112
"idpAddNewAccountLabel" = "Add new account";
112113
"idpSelectUserTitleLabel" = "Select user";
113114

114-
//IDP Login Selection Screen
115+
// IDP Login Selection Screen
115116
"idpLoginFlowInfoLabel" = "Select the flow to use for log in";
116117
"idpLoginLocalFlowDescriptionLabel" = "Local - Host App will be used for authentication";
117118
"idpLoginIdpFlowDescriptionLabel" = "IDP - Identity Provider App will be launched for authentication";

0 commit comments

Comments
 (0)