diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.m index 6ae420a28e..ac7ae05152 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.m @@ -492,6 +492,7 @@ - (NSString *)devInfoTitleString @"IDP Enabled", [self idpEnabled] ? @"YES" : @"NO", @"Identity Provider", [self isIdentityProvider] ? @"YES" : @"NO", @"Current User", [self userToString:userAccountManager.currentUser], + @"Scopes", [userAccountManager.currentUser.credentials.scopes componentsJoinedByString:@" "], @"Access Token Expiration", [self accessTokenExpiration], @"Authenticated Users", [self usersToString:userAccountManager.allUserAccounts], @"User Key-Value Stores", [self safeJoin:[SFSDKKeyValueEncryptedFileStore allStoreNames] separator:@", "], diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials+Internal.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials+Internal.h index b466517296..24169cf1b3 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials+Internal.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials+Internal.h @@ -59,6 +59,7 @@ extern NSException * _Nullable SFOAuthInvalidIdentifierException(void); @property (nonatomic, readwrite, nullable) NSString *organizationId; @property (nonatomic, readwrite, nullable) NSURL *instanceUrl; @property (nonatomic, readwrite, nullable) NSURL *apiInstanceUrl; +@property (nonatomic, readwrite, nullable) NSArray *scopes; @property (nonatomic, readwrite, nullable) NSString *communityId; @property (nonatomic, readwrite, nullable) NSURL *communityUrl; @property (nonatomic, readwrite, nullable) NSDate *issuedAt; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.h index 03f9569ad2..668b03dfc9 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.h @@ -146,7 +146,6 @@ NS_SWIFT_NAME(OAuthCredentials) This property is available after authentication has successfully completed. - @warning The setter for this property is exposed publicly only for unit tests. Client code should not set this property. @exception NSInternalInconsistencyException If accessed while the identifier property is `nil`. */ @property (nonatomic, readonly, nullable) NSString *organizationId; @@ -157,8 +156,6 @@ NS_SWIFT_NAME(OAuthCredentials) This is the URL that client requests should be made to after authentication completes. This property is set by the `SFOAuthCoordinator` after authentication has successfully completed. - - @warning The setter for this property is exposed publicly only for unit tests. Client code should not set this property. */ @property (nonatomic, readonly, nullable) NSURL *instanceUrl; @@ -167,11 +164,16 @@ NS_SWIFT_NAME(OAuthCredentials) This is the URL that client SFAP requests should be made to after authentication completes. This property is set by the `SFOAuthCoordinator` after authentication has successfully completed. This URL is only defined when sfap_api scope is used. - - @warning The setter for this property is exposed publicly only for unit tests. Client code should not set this property. */ @property (nonatomic, readonly, nullable) NSURL *apiInstanceUrl; +/** The OAuth scopes granted for this session. + + This property contains the list of OAuth scopes that were granted during authentication. + This property is set by the `SFOAuthCoordinator` after authentication has successfully completed. + */ +@property (nonatomic, readonly, nullable) NSArray *scopes; + /** The community ID the user choose to log into. This usually happens when the user logs into the app using a community-based login page @@ -189,8 +191,6 @@ NS_SWIFT_NAME(OAuthCredentials) /** The timestamp when the session access token was issued. This property is set by the `SFOAuthCoordinator` after authentication has successfully completed. - - @warning The setter for this property is exposed publicly only for unit tests. Client code should not set this property. */ @property (nonatomic, readonly, nullable) NSDate *issuedAt; @@ -199,8 +199,6 @@ NS_SWIFT_NAME(OAuthCredentials) that the user belongs to, and userID is the Salesforce user ID. This property is set by the `SFOAuthCoordinator` after authentication has successfully completed. - - @warning The setter for this property is exposed publicly only for unit tests. Client code should not set this property. */ @property (nonatomic, readonly, nullable) NSURL *identityUrl; @@ -212,8 +210,6 @@ NS_SWIFT_NAME(OAuthCredentials) component of the identityUrl. This property is available after authentication has successfully completed. - - @warning The setter for this property is exposed publicly only for unit tests. Client code should not set this property. */ @property (nonatomic, readonly, nullable) NSString *userId; diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.m index ed05756a2c..c0dfadbbdb 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/OAuth/SFOAuthCredentials.m @@ -63,6 +63,7 @@ @implementation SFOAuthCredentials @synthesize userId = _userId; // cached user ID derived from identityURL @synthesize instanceUrl = _instanceUrl; @synthesize apiInstanceUrl = _apiInstanceUrl; +@synthesize scopes = _scopes; @synthesize issuedAt = _issuedAt; @synthesize protocol = _protocol; @synthesize encrypted = _encrypted; @@ -93,6 +94,7 @@ - (id)initWithCoder:(NSCoder *)coder { self.identityUrl = [coder decodeObjectOfClass:[NSURL class] forKey:@"SFOAuthIdentityUrl"]; self.instanceUrl = [coder decodeObjectOfClass:[NSURL class] forKey:@"SFOAuthInstanceUrl"]; self.apiInstanceUrl = [coder decodeObjectOfClass:[NSURL class] forKey:@"SFOAuthApiInstanceUrl"]; + self.scopes = [coder decodeObjectOfClasses:[NSSet setWithObjects:[NSArray class], [NSString class], nil] forKey:@"SFOAuthScopes"]; self.communityId = [coder decodeObjectOfClass:[NSString class] forKey:@"SFOAuthCommunityId"]; self.communityUrl = [coder decodeObjectOfClass:[NSURL class] forKey:@"SFOAuthCommunityUrl"]; self.issuedAt = [coder decodeObjectOfClass:[NSDate class] forKey:@"SFOAuthIssuedAt"]; @@ -145,6 +147,7 @@ - (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.identityUrl forKey:@"SFOAuthIdentityUrl"]; [coder encodeObject:self.instanceUrl forKey:@"SFOAuthInstanceUrl"]; [coder encodeObject:self.apiInstanceUrl forKey:@"SFOAuthApiInstanceUrl"]; + [coder encodeObject:self.scopes forKey:@"SFOAuthScopes"]; [coder encodeObject:self.communityId forKey:@"SFOAuthCommunityId"]; [coder encodeObject:self.communityUrl forKey:@"SFOAuthCommunityUrl"]; [coder encodeObject:self.issuedAt forKey:@"SFOAuthIssuedAt"]; @@ -204,6 +207,7 @@ - (id)copyWithZone:(nullable NSZone *)zone { copyCreds.accessToken = self.accessToken; copyCreds.instanceUrl = self.instanceUrl; copyCreds.apiInstanceUrl = self.apiInstanceUrl; + copyCreds.scopes = self.scopes; copyCreds.communityId = self.communityId; copyCreds.communityUrl = self.communityUrl; copyCreds.issuedAt = self.issuedAt; @@ -297,11 +301,11 @@ - (void)setUserId:(NSString *)userId { - (NSString *)description { NSString *format = @"<%@: %p, identifier=\"%@\" clientId=\"%@\" domain=\"%@\" identityUrl=\"%@\" instanceUrl=\"%@\" apiInstanceUrl=\"%@\" " - @"communityId=\"%@\" communityUrl=\"%@\" " + @"communityId=\"%@\" communityUrl=\"%@\" scopes=\"%@\" " @"issuedAt=\"%@\" organizationId=\"%@\" protocol=\"%@\" redirectUri=\"%@\">"; return [NSString stringWithFormat:format, NSStringFromClass(self.class), self, self.identifier, self.clientId, self.domain, self.identityUrl, self.instanceUrl, self.apiInstanceUrl, - self.communityId, self.communityUrl, + self.communityId, self.communityUrl, self.scopes, self.issuedAt, self.organizationId, self.protocol, self.redirectUri]; } @@ -322,6 +326,7 @@ - (void)revokeRefreshToken { self.refreshToken = nil; self.instanceUrl = nil; self.apiInstanceUrl = nil; + self.scopes = nil; self.communityId = nil; self.communityUrl = nil; self.issuedAt = nil; @@ -378,6 +383,7 @@ - (NSURL *)overrideDomainIfNeeded { - issuedAt - instanceUrl - apiInstanceUrl + - scopes - identityUrl - communityId - communityUrl @@ -410,6 +416,11 @@ - (void)updateCredentials:(NSDictionary *) params { if (params[kSFOAuthApiInstanceUrl]) { [self setPropertyForKey:@"apiInstanceUrl" withValue:[NSURL URLWithString:params[kSFOAuthApiInstanceUrl]]]; } + if (params[kSFOAuthScope]) { + NSString *rawScope = params[kSFOAuthScope]; + NSArray *scopesArray = [rawScope componentsSeparatedByString:@" "]; + [self setPropertyForKey:@"scopes" withValue:scopesArray]; + } if (params[kSFOAuthId]) { [self setPropertyForKey:@"identityUrl" withValue:[NSURL URLWithString:params[kSFOAuthId]]]; } diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/SFOAuthCredentialsTests.m b/libs/SalesforceSDKCore/SalesforceSDKCore/SFOAuthCredentialsTests.m index e453525a9a..05b9172b9b 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/SFOAuthCredentialsTests.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/SFOAuthCredentialsTests.m @@ -61,6 +61,7 @@ - (void)tryUpdateCredentials:(BOOL)encrypted storageType:(SFOAuthCredentialsStor [params setObject:@"test-refresh-token" forKey:@"refresh_token"]; [params setObject:@"https://instance.salesforce.com" forKey:@"instance_url"]; [params setObject:@"https://api.salesforce.com" forKey:@"api_instance_url"]; + [params setObject:@"api refresh_token" forKey:@"scope"]; [params setObject:@"https://id.salesforce.com" forKey:@"id"]; [params setObject:@"test-community-id" forKey:@"sfdc_community_id"]; [params setObject:@"https://community.salesforce.com" forKey:@"sfdc_community_url"]; @@ -85,6 +86,7 @@ - (void)tryUpdateCredentials:(BOOL)encrypted storageType:(SFOAuthCredentialsStor XCTAssertEqualObjects(creds.refreshToken, @"test-refresh-token"); XCTAssertEqualObjects(creds.instanceUrl.absoluteString, @"https://instance.salesforce.com"); XCTAssertEqualObjects(creds.apiInstanceUrl.absoluteString, @"https://api.salesforce.com"); + XCTAssertEqualObjects(creds.scopes, (@[@"api", @"refresh_token"])); XCTAssertEqualObjects(creds.identityUrl.absoluteString, @"https://id.salesforce.com"); XCTAssertEqualObjects(creds.communityId, @"test-community-id"); XCTAssertEqualObjects(creds.communityUrl.absoluteString, @"https://community.salesforce.com"); diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/SFSDKOAuthTokenEndpointResponseTests.m b/libs/SalesforceSDKCore/SalesforceSDKCore/SFSDKOAuthTokenEndpointResponseTests.m index d496d35195..b983f376c2 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/SFSDKOAuthTokenEndpointResponseTests.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/SFSDKOAuthTokenEndpointResponseTests.m @@ -47,6 +47,7 @@ - (void)testInitWithDictionary { [params setObject:@"test-refresh-token" forKey:@"refresh_token"]; [params setObject:@"https://instance.salesforce.com" forKey:@"instance_url"]; [params setObject:@"https://api.salesforce.com" forKey:@"api_instance_url"]; + [params setObject:@"api refresh_token" forKey:@"scope"]; [params setObject:@"https://id.salesforce.com" forKey:@"id"]; [params setObject:@"test-community-id" forKey:@"sfdc_community_id"]; [params setObject:@"https://community.salesforce.com" forKey:@"sfdc_community_url"]; @@ -80,6 +81,7 @@ - (void)testInitWithDictionary { XCTAssertEqualObjects(response.refreshToken, @"test-refresh-token"); XCTAssertEqualObjects(response.instanceUrl.absoluteString, @"https://instance.salesforce.com"); XCTAssertEqualObjects(response.apiInstanceUrl.absoluteString, @"https://api.salesforce.com"); + XCTAssertEqualObjects(response.scopes, (@[@"api", @"refresh_token"])); XCTAssertEqualObjects(response.identityUrl.absoluteString, @"https://id.salesforce.com"); XCTAssertEqualObjects(response.communityId, @"test-community-id"); XCTAssertEqualObjects(response.communityUrl.absoluteString, @"https://community.salesforce.com"); diff --git a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceOAuthUnitTests.m b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceOAuthUnitTests.m index 89345722c7..ea4cf1e411 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceOAuthUnitTests.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCoreTests/SalesforceOAuthUnitTests.m @@ -130,6 +130,7 @@ - (void)testCredentialsCoding { credsIn.identityUrl = [NSURL URLWithString:@"https://login.salesforce.com/ID/orgID/eighteenCharUsrXYZ"]; credsIn.instanceUrl = [NSURL URLWithString:@"http://www.salesforce.com"]; credsIn.apiInstanceUrl = [NSURL URLWithString:@"http://api.salesforce.com"]; + credsIn.scopes = @[@"api", @"refresh_token"]; credsIn.issuedAt = [NSDate date]; credsIn.contentDomain = @"mobilesdk.my.salesforce.com"; credsIn.contentSid = @"contentsid"; @@ -173,6 +174,7 @@ - (void)testCredentialsCoding { XCTAssertEqualObjects(expectedUserId, credsOut.userId, @"userId mismatch"); XCTAssertEqualObjects(credsIn.instanceUrl, credsOut.instanceUrl, @"instanceUrl mismatch"); XCTAssertEqualObjects(credsIn.apiInstanceUrl, credsOut.apiInstanceUrl, @"apiInstanceUrl mismatch"); + XCTAssertEqualObjects(credsIn.scopes, credsOut.scopes, @"scopes mismatch"); XCTAssertEqualObjects(credsIn.issuedAt, credsOut.issuedAt, @"issuedAt mismatch"); XCTAssertEqualObjects(credsIn.contentDomain, credsOut.contentDomain, @"contentDomain mismatch"); XCTAssertEqualObjects(credsIn.contentSid, credsOut.contentSid, @"contentSid mismatch"); @@ -202,6 +204,7 @@ - (void)testCredentialsCopying { NSString *orgIdToCheck = @"orgID"; NSURL *instanceUrlToCheck = [NSURL URLWithString:@"https://na1.salesforce.com"]; NSURL *apiInstanceUrlToCheck = [NSURL URLWithString:@"https://api.salesforce.com"]; + NSArray *scopesToCheck = @[@"api", @"refresh_token"]; NSString *communityIdToCheck = @"communityID"; NSURL *communityUrlToCheck = [NSURL URLWithString:@"https://mycomm.my.salesforce.com/customers"]; NSDate *issuedAtToCheck = [NSDate date]; @@ -231,6 +234,7 @@ - (void)testCredentialsCopying { origCreds.accessToken = accessTokenToCheck; origCreds.instanceUrl = instanceUrlToCheck; origCreds.apiInstanceUrl = apiInstanceUrlToCheck; + origCreds.scopes = scopesToCheck; origCreds.communityId = communityIdToCheck; origCreds.communityUrl = communityUrlToCheck; origCreds.issuedAt = issuedAtToCheck; @@ -267,6 +271,7 @@ - (void)testCredentialsCopying { origCreds.organizationId = nil; origCreds.instanceUrl = nil; origCreds.apiInstanceUrl = nil; + origCreds.scopes = nil; origCreds.communityId = nil; origCreds.communityUrl = nil; origCreds.issuedAt = nil; @@ -322,6 +327,8 @@ - (void)testCredentialsCopying { XCTAssertNotEqual(origCreds.instanceUrl, copiedCreds.instanceUrl); XCTAssertEqual(copiedCreds.apiInstanceUrl, apiInstanceUrlToCheck); XCTAssertNotEqual(origCreds.apiInstanceUrl, copiedCreds.apiInstanceUrl); + XCTAssertEqual(copiedCreds.scopes, scopesToCheck); + XCTAssertNotEqual(origCreds.scopes, copiedCreds.scopes); XCTAssertEqual(copiedCreds.communityId, communityIdToCheck); XCTAssertNotEqual(origCreds.communityId, copiedCreds.communityId); XCTAssertEqual(copiedCreds.communityUrl, communityUrlToCheck);