Skip to content

Commit e8a07ac

Browse files
authored
Merge pull request #3959 from wmathurin/auth_ui_tests
UI Tests for auth flows
2 parents d124a37 + 33074eb commit e8a07ac

30 files changed

+3629
-285
lines changed

libs/SalesforceSDKCore/SalesforceSDKCore.xcodeproj/xcshareddata/xcschemes/SalesforceSDKCore.xcscheme

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29-
shouldUseLaunchSchemeArgsEnv = "YES">
29+
shouldUseLaunchSchemeArgsEnv = "YES"
30+
codeCoverageEnabled = "YES">
3031
<MacroExpansion>
3132
<BuildableReference
3233
BuildableIdentifier = "primary"

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ - (NSString *)devInfoTitleString
493493
[presentedViewController dismissViewControllerAnimated:YES completion:^{
494494
// Restart authentication with the updated configuration
495495
if ([presentedViewController isKindOfClass:[SFLoginViewController class]]) {
496-
[[SFUserAccountManager sharedInstance] restartAuthenticationForViewController:(SFLoginViewController *)presentedViewController];
496+
[[SFUserAccountManager sharedInstance] restartAuthenticationForViewController:(SFLoginViewController *)presentedViewController recreateAuthRequest:YES];
497497
}
498498
// TODO support advanced auth case
499499
}];

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/DevConfig/BootConfigEditor.swift

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@
2727

2828
import SwiftUI
2929

30+
// MARK: - JSON Import Labels
31+
public struct BootConfigJSONKeys {
32+
public static let consumerKey = "remoteAccessConsumerKey"
33+
public static let redirectUri = "oauthRedirectURI"
34+
public static let scopes = "scopes"
35+
}
36+
3037
public struct BootConfigEditor: View {
3138
let title: String
3239
let buttonLabel: String
@@ -38,6 +45,8 @@ public struct BootConfigEditor: View {
3845
let onUseConfig: () -> Void
3946
let initiallyExpanded: Bool
4047
@State private var isExpanded: Bool = false
48+
@State private var showImportAlert: Bool = false
49+
@State private var importJSONText: String = ""
4150

4251
public init(
4352
title: String,
@@ -63,21 +72,32 @@ public struct BootConfigEditor: View {
6372

6473
public var body: some View {
6574
VStack(alignment: .leading, spacing: 12) {
66-
Button(action: {
67-
withAnimation {
68-
isExpanded.toggle()
75+
HStack {
76+
Button(action: {
77+
withAnimation {
78+
isExpanded.toggle()
79+
}
80+
}) {
81+
HStack {
82+
Text(title)
83+
.font(.headline)
84+
.foregroundColor(.primary)
85+
Spacer()
86+
Image(systemName: isExpanded ? "chevron.up" : "chevron.down")
87+
.foregroundColor(.secondary)
88+
}
6989
}
70-
}) {
71-
HStack {
72-
Text(title)
73-
.font(.headline)
74-
.foregroundColor(.primary)
75-
Spacer()
76-
Image(systemName: isExpanded ? "chevron.up" : "chevron.down")
77-
.foregroundColor(.secondary)
90+
Button(action: {
91+
importJSONText = ""
92+
showImportAlert = true
93+
}) {
94+
Image(systemName: "square.and.arrow.down")
95+
.font(.subheadline)
96+
.foregroundColor(.blue)
7897
}
79-
.padding(.horizontal)
98+
.accessibilityIdentifier("importConfigButton")
8099
}
100+
.padding(.horizontal)
81101

82102
if isExpanded {
83103
VStack(alignment: .leading, spacing: 8) {
@@ -130,6 +150,34 @@ public struct BootConfigEditor: View {
130150
.onAppear {
131151
isExpanded = initiallyExpanded
132152
}
153+
.alert("Import Configuration", isPresented: $showImportAlert) {
154+
TextField("Paste JSON here", text: $importJSONText)
155+
Button("Import") {
156+
importConfigFromJSON()
157+
}
158+
Button("Cancel", role: .cancel) { }
159+
} message: {
160+
Text("Paste JSON with remoteAccessConsumerKey, oauthRedirectURI, and scopes")
161+
}
162+
}
163+
164+
// MARK: - Helper Methods
165+
166+
private func importConfigFromJSON() {
167+
guard let jsonData = importJSONText.data(using: .utf8),
168+
let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] else {
169+
return
170+
}
171+
172+
if let key = json[BootConfigJSONKeys.consumerKey] as? String {
173+
consumerKey = key
174+
}
175+
if let uri = json[BootConfigJSONKeys.redirectUri] as? String {
176+
callbackUrl = uri
177+
}
178+
if let scopesValue = json[BootConfigJSONKeys.scopes] as? String {
179+
scopes = scopesValue
180+
}
133181
}
134182
}
135183

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ NS_SWIFT_NAME(SalesforceLoginViewControllerDelegate)
5454

5555
- (void)loginViewControllerDidReload:(nonnull SFLoginViewController *)loginViewController;
5656

57+
- (void)loginViewControllerDidChangeLoginOptions:(nonnull SFLoginViewController *)loginViewController;
58+
59+
5760
@end
5861

5962
/** The Salesforce login screen view.

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Login/SFLoginViewController.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,8 @@ - (UIBarButtonItem *)createSettingsButton {
317317
handler:^(__kindof UIAction* _Nonnull action) {
318318
UIViewController *configPicker = [BootConfigPickerViewController makeViewControllerOnConfigurationCompleted:^{
319319
[self dismissViewControllerAnimated:YES completion:^{
320-
if ([self.delegate respondsToSelector:@selector(loginViewControllerDidReload:)]) {
321-
[self.delegate loginViewControllerDidReload:self];
320+
if ([self.delegate respondsToSelector:@selector(loginViewControllerDidChangeLoginOptions:)]) {
321+
[self.delegate loginViewControllerDidChangeLoginOptions:self];
322322
}
323323
}];
324324
}];

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ NS_ASSUME_NONNULL_BEGIN
8181
* Returns the scope query parameter string for OAuth requests.
8282
* @return A properly formatted scope parameter string, or empty string if no scopes provided.
8383
*/
84-
- (NSString *)scopeQueryParamString;
84+
- (NSString *)scopeQueryParamString:(NSArray<NSString*>*)scopes;
8585

8686
/**
8787
Migrates the refresh token for a user to a new app configuration.

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ - (NSString *)approvalURLForEndpoint:(NSString *)authorizeEndpoint
821821
}
822822

823823
// OAuth scopes
824-
NSString *scopeString = [self scopeQueryParamString];
824+
NSString *scopeString = [self scopeQueryParamString:credentials.scopes];
825825
if (scopeString.length > 0) {
826826
[approvalUrlString appendString:scopeString];
827827
}
@@ -842,9 +842,9 @@ -(void) clearFrontDoorBridgeLoginOverride {
842842
self.frontdoorBridgeLoginOverride = nil;
843843
}
844844

845-
- (NSString *)scopeQueryParamString {
846-
if (self.scopes.count > 0) {
847-
NSString *scopeStr = [SFScopeParser computeScopeParameterWithURLEncodingWithScopes:self.scopes];
845+
- (NSString *)scopeQueryParamString:(NSArray<NSString*>*)scopes {
846+
if (scopes.count > 0) {
847+
NSString *scopeStr = [SFScopeParser computeScopeParameterWithURLEncodingWithScopes:[NSSet setWithArray:scopes]];
848848
return [NSString stringWithFormat:@"&%@=%@", kSFOAuthScope, scopeStr];
849849
} else {
850850
return @"";

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFSDKAuthSession.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ - (SFOAuthCredentials *)newClientCredentials {
7373
creds.clientId = self.oauthRequest.oauthClientId;
7474
creds.redirectUri = self.oauthRequest.oauthCompletionUrl;
7575
creds.domain = self.oauthRequest.loginHost;
76+
creds.scopes = [self.oauthRequest.scopes allObjects];
7677
creds.accessToken = nil;
7778
return creds;
7879
}

libs/SalesforceSDKCore/SalesforceSDKCore/Classes/UserAccount/SFUserAccountManager+Internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ Set this block to handle presentation of the Authentication View Controller.
218218

219219
- (void)restartAuthenticationForViewController:(SFLoginViewController *)loginViewController;
220220

221+
- (void)restartAuthenticationForViewController:(SFLoginViewController *)loginViewController recreateAuthRequest:(BOOL)recreateAuthRequest;
222+
223+
221224
@end
222225

223226
NS_ASSUME_NONNULL_END

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ -(SFSDKAuthRequest *)migrateRefreshAuthRequest:(SFSDKAppConfig *)newAppConfig {
579579
request.additionalOAuthParameterKeys = self.additionalOAuthParameterKeys;
580580
request.oauthClientId = newAppConfig.remoteAccessConsumerKey;
581581
request.oauthCompletionUrl = newAppConfig.oauthRedirectURI;
582+
request.scopes = newAppConfig.oauthScopes;
582583
request.scene = [[SFSDKWindowManager sharedManager] defaultScene];
583584
return request;
584585
}
@@ -1119,9 +1120,26 @@ - (void)loginViewControllerDidReload:(SFLoginViewController *)loginViewControlle
11191120
[self restartAuthenticationForViewController:loginViewController];
11201121
}
11211122

1123+
- (void)loginViewControllerDidChangeLoginOptions:(SFLoginViewController *)loginViewController {
1124+
[self restartAuthenticationForViewController:loginViewController recreateAuthRequest:YES];
1125+
}
1126+
11221127
- (void)restartAuthenticationForViewController:(SFLoginViewController *)loginViewController {
1128+
[self restartAuthenticationForViewController:loginViewController recreateAuthRequest:NO];
1129+
}
1130+
1131+
- (void)restartAuthenticationForViewController:(SFLoginViewController *)loginViewController recreateAuthRequest:(BOOL)recreateAuthRequest {
11231132
NSString *sceneId = loginViewController.view.window.windowScene.session.persistentIdentifier;
1124-
[self restartAuthentication:self.authSessions[sceneId]];
1133+
1134+
SFSDKAuthSession* session = self.authSessions[sceneId];
1135+
1136+
// Recreate the oauth request
1137+
// Otherwise changes to consumer key / callback url or scopes will not get picked up
1138+
if (recreateAuthRequest) {
1139+
session.oauthRequest = [self defaultAuthRequestWithLoginHost:session.oauthRequest.loginHost];
1140+
}
1141+
1142+
[self restartAuthentication:session];
11251143
}
11261144

11271145
#pragma mark - SFSDKLoginHostDelegate

0 commit comments

Comments
 (0)