Skip to content

Commit ee1587c

Browse files
authored
Merge cfe6f4e into c105a0d
2 parents c105a0d + cfe6f4e commit ee1587c

File tree

10 files changed

+239
-1
lines changed

10 files changed

+239
-1
lines changed

FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ - (instancetype)initWithProviderID:(NSString *)providerID
4545
rawNonce:(nullable NSString *)rawNonce
4646
accessToken:(nullable NSString *)accessToken
4747
secret:(nullable NSString *)secret
48+
displayName:(nullable NSString *)displayName
4849
pendingToken:(nullable NSString *)pendingToken {
4950
self = [super initWithProvider:providerID];
5051
if (self) {
@@ -53,6 +54,7 @@ - (instancetype)initWithProviderID:(NSString *)providerID
5354
_accessToken = accessToken;
5455
_pendingToken = pendingToken;
5556
_secret = secret;
57+
_displayName = displayName;
5658
}
5759
return self;
5860
}
@@ -65,6 +67,7 @@ - (instancetype)initWithProviderID:(NSString *)providerID
6567
rawNonce:nil
6668
accessToken:nil
6769
secret:nil
70+
displayName:nil
6871
pendingToken:nil];
6972
if (self) {
7073
_OAuthResponseURLString = OAuthResponseURLString;
@@ -81,6 +84,7 @@ - (nullable instancetype)initWithVerifyAssertionResponse:(FIRVerifyAssertionResp
8184
rawNonce:nil
8285
accessToken:response.oauthAccessToken
8386
secret:response.oauthSecretToken
87+
displayName:nil
8488
pendingToken:response.pendingToken];
8589
}
8690
return nil;
@@ -94,6 +98,7 @@ - (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
9498
request.sessionID = _sessionID;
9599
request.providerOAuthTokenSecret = _secret;
96100
request.pendingToken = _pendingToken;
101+
request.displayName = _displayName;
97102
}
98103

99104
#pragma mark - NSSecureCoding
@@ -108,11 +113,13 @@ - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
108113
NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"accessToken"];
109114
NSString *pendingToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"pendingToken"];
110115
NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"secret"];
116+
NSString *displayName = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"displayName"];
111117
self = [self initWithProviderID:self.provider
112118
IDToken:IDToken
113119
rawNonce:rawNonce
114120
accessToken:accessToken
115121
secret:secret
122+
displayName:displayName
116123
pendingToken:pendingToken];
117124
return self;
118125
}
@@ -123,6 +130,7 @@ - (void)encodeWithCoder:(NSCoder *)aCoder {
123130
[aCoder encodeObject:self.accessToken forKey:@"accessToken"];
124131
[aCoder encodeObject:self.pendingToken forKey:@"pendingToken"];
125132
[aCoder encodeObject:self.secret forKey:@"secret"];
133+
[aCoder encodeObject:self.displayName forKey:@"displayName"];
126134
}
127135

128136
@end

FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ NS_ASSUME_NONNULL_BEGIN
4949
@param accessToken The access token associated with the credential being created.
5050
@param secret The secret associated with the credential being created.
5151
@param pendingToken The pending token associated with the credential being created.
52+
@param displayName The displayName associated with the credential being created.
5253
*/
5354
- (instancetype)initWithProviderID:(NSString *)providerID
5455
IDToken:(nullable NSString *)IDToken
5556
rawNonce:(nullable NSString *)rawNonce
5657
accessToken:(nullable NSString *)accessToken
5758
secret:(nullable NSString *)secret
59+
displayName:(nullable NSString *)displayName
5860
pendingToken:(nullable NSString *)pendingToken NS_DESIGNATED_INITIALIZER;
5961

6062
/** @fn initWithProviderId:sessionID:OAuthResponseURLString:

FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ + (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
8888
rawNonce:nil
8989
accessToken:accessToken
9090
secret:nil
91+
displayName:nil
9192
pendingToken:nil];
9293
}
9394

@@ -98,6 +99,7 @@ + (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
9899
rawNonce:nil
99100
accessToken:accessToken
100101
secret:nil
102+
displayName:nil
101103
pendingToken:nil];
102104
}
103105

@@ -110,6 +112,7 @@ + (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
110112
rawNonce:rawNonce
111113
accessToken:accessToken
112114
secret:nil
115+
displayName:nil
113116
pendingToken:nil];
114117
}
115118

@@ -121,6 +124,21 @@ + (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
121124
rawNonce:rawNonce
122125
accessToken:nil
123126
secret:nil
127+
displayName:nil
128+
pendingToken:nil];
129+
}
130+
131+
+ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
132+
IDToken:(NSString *)IDToken
133+
rawNonce:(nullable NSString *)rawNonce
134+
accessToken:(nullable NSString *)accessToken
135+
displayName:(nonnull NSString *)displayName {
136+
return [[FIROAuthCredential alloc] initWithProviderID:providerID
137+
IDToken:IDToken
138+
rawNonce:rawNonce
139+
accessToken:accessToken
140+
secret:nil
141+
displayName:displayName
124142
pendingToken:nil];
125143
}
126144

FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ NS_ASSUME_NONNULL_BEGIN
9696
*/
9797
@property(nonatomic, assign) BOOL autoCreate;
9898

99+
/** @property displayName
100+
@brief A displayName linked to its provider
101+
*/
102+
@property(nonatomic, copy, nullable) NSString *displayName;
103+
99104
/** @fn initWithEndpoint:requestConfiguration:
100105
@brief Please use initWithProviderID:requestConfifuration instead.
101106
*/

FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@
8484
*/
8585
static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
8686

87+
/** @var kDisplayName
88+
@brief The key for the "displayName" value in the request.
89+
*/
90+
static NSString *const kDisplayNameKey = @"displayName";
91+
8792
/** @var kReturnIDPCredentialKey
8893
@brief The key for the "returnIdpCredential" value in the request.
8994
*/
@@ -171,6 +176,11 @@ - (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)
171176
if (_sessionID) {
172177
body[kSessionIDKey] = _sessionID;
173178
}
179+
180+
if (_displayName) {
181+
body[kDisplayNameKey] = _displayName;
182+
}
183+
174184
if (self.tenantID) {
175185
body[kTenantIDKey] = self.tenantID;
176186
}

FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ NS_SWIFT_NAME(OAuthCredential)
4343
*/
4444
@property(nonatomic, readonly, nullable) NSString *secret;
4545

46+
/** @property displayName
47+
@brief The displayName associated with this credential.
48+
*/
49+
@property(nonatomic, readonly, nullable) NSString *displayName;
50+
4651
/** @fn init
4752
@brief This class is not supposed to be instantiated directly.
4853
*/

FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,24 @@ NS_SWIFT_NAME(OAuthProvider)
114114
IDToken:(NSString *)IDToken
115115
rawNonce:(nullable NSString *)rawNonce;
116116

117+
/** @fn credentialWithProviderID:IDToken:rawNonce:accessToken:
118+
@brief Creates an `AuthCredential` for that OAuth 2 provider identified by provider ID, ID
119+
token, raw nonce, and access token.
120+
121+
@param providerID The provider ID associated with the Auth credential being created.
122+
@param IDToken The IDToken associated with the Auth credential being created.
123+
@param rawNonce The raw nonce associated with the Auth credential being created.
124+
@param accessToken The access token associated with the Auth credential be created, if
125+
available.
126+
@param displayName The displayName associated with the Auth credential being created.
127+
@return A `AuthCredential` for the specified provider ID, ID token and access token.
128+
*/
129+
+ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
130+
IDToken:(NSString *)IDToken
131+
rawNonce:(nullable NSString *)rawNonce
132+
accessToken:(nullable NSString *)accessToken
133+
displayName:(NSString *)displayName;
134+
117135
/** @fn init
118136
@brief This class is not meant to be initialized.
119137
*/

FirebaseAuth/Tests/Sample/Sample/MainViewController+OAuth.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,10 +410,12 @@ - (void)reauthenticateWithApple {
410410
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
411411
ASAuthorizationAppleIDCredential* appleIDCredential = authorization.credential;
412412
NSString *IDToken = [NSString stringWithUTF8String:[appleIDCredential.identityToken bytes]];
413+
NSString *displayName = [appleIDCredential.fullName.givenName stringByAppendingFormat:@" %@", appleIDCredential.fullName.familyName];
413414
FIROAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com"
414415
IDToken:IDToken
415416
rawNonce:self.appleRawNonce
416-
accessToken:nil];
417+
accessToken:nil
418+
displayName:displayName];
417419

418420
if ([appleIDCredential.state isEqualToString:@"signIn"]) {
419421
[FIRAuth.auth signInWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {

FirebaseAuth/Tests/Unit/FIRAuthTests.m

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,36 @@
160160
*/
161161
static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";
162162

163+
/** @var kAppleAuthProviderID
164+
@brief The provider ID for Apple Sign-In.
165+
*/
166+
static NSString *const kAppleAuthProviderID = @"apple.com";
167+
168+
/** @var kAppleUD
169+
@brief The fake user ID under Apple Sign-In.
170+
*/
171+
static NSString *const kAppleID = @"APPLE_ID";
172+
173+
/** @var kAppleEmail
174+
@brief The fake user email under Apple Sign-In.
175+
*/
176+
static NSString *const kAppleEmail = @"user@icloud.com";
177+
178+
/** @var kAppleDisplayName
179+
@brief The fake user display name under Apple Sign-In.
180+
*/
181+
static NSString *const kAppleDisplayName = @"Apple Doe";
182+
183+
/** @var kAppleAccessToken
184+
@brief The fake access token from Apple Sign-In.
185+
*/
186+
static NSString *const kAppleAccessToken = @"Apple_ACCESS_TOKEN";
187+
188+
/** @var kAppleIDToken
189+
@brief The fake ID token from Apple Sign-In.
190+
*/
191+
static NSString *const kAppleIDToken = @"APPLE_ID_TOKEN";
192+
163193
/** @var kCustomToken
164194
@brief The fake custom token to sign in.
165195
*/
@@ -321,6 +351,23 @@ + (NSDictionary *)googleProfile {
321351
return kGoogleProfile;
322352
}
323353

354+
/** @fn appleProfile
355+
@brief The fake user profile under additional user data in @c FIRVerifyAssertionResponse.
356+
*/
357+
+ (NSDictionary *)appleProfile {
358+
static NSDictionary *kAppleProfile = nil;
359+
static dispatch_once_t onceToken;
360+
dispatch_once(&onceToken, ^{
361+
kAppleProfile = @{
362+
@"iss" : @"https://accounts.apple.com\\",
363+
@"email" : kAppleEmail,
364+
@"given_name" : @"User",
365+
@"family_name" : @"Doe"
366+
};
367+
});
368+
return kAppleProfile;
369+
}
370+
324371
- (void)setUp {
325372
[super setUp];
326373

@@ -1374,6 +1421,60 @@ - (void)testSignInWithGoogleCredentialFailure {
13741421
OCMVerifyAll(_mockBackend);
13751422
}
13761423

1424+
/** @fn testSignInWithOAuthCredentialWithDisplayNameSuccess
1425+
@brief Tests the flow of a successful @c signInWithCredential:completion: call
1426+
with an Apple Sign-In credential.
1427+
This method differntiates the testSignInWithCredentialSuccess only in verifying displayName
1428+
*/
1429+
- (void)testSignInWithOAuthCredentialWithDisplayNameSuccess {
1430+
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
1431+
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
1432+
FIRVerifyAssertionResponseCallback callback) {
1433+
XCTAssertEqualObjects(request.APIKey, kAPIKey);
1434+
XCTAssertEqualObjects(request.providerID, kAppleAuthProviderID);
1435+
XCTAssertEqualObjects(request.providerIDToken, kAppleIDToken);
1436+
XCTAssertEqualObjects(request.providerAccessToken, kAppleAccessToken);
1437+
XCTAssertEqualObjects(request.displayName, kAppleDisplayName);
1438+
XCTAssertTrue(request.returnSecureToken);
1439+
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
1440+
id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
1441+
OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kAppleID);
1442+
OCMStub([mockVerifyAssertionResponse providerID]).andReturn(kAppleAuthProviderID);
1443+
OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
1444+
OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kAppleDisplayName);
1445+
OCMStub([mockVerifyAssertionResponse profile]).andReturn([[self class] appleProfile]);
1446+
OCMStub([mockVerifyAssertionResponse username]).andReturn(kDisplayName);
1447+
[self stubTokensWithMockResponse:mockVerifyAssertionResponse];
1448+
callback(mockVerifyAssertionResponse, nil);
1449+
});
1450+
});
1451+
[self expectGetAccountInfoApple];
1452+
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
1453+
[[FIRAuth auth] signOut:NULL];
1454+
FIRAuthCredential *appleCredential =
1455+
[FIROAuthProvider credentialWithProviderID:kAppleAuthProviderID
1456+
IDToken:kAppleIDToken
1457+
rawNonce:nil
1458+
accessToken:kAppleAccessToken
1459+
displayName:kAppleDisplayName];
1460+
[[FIRAuth auth]
1461+
signInWithCredential:appleCredential
1462+
completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
1463+
XCTAssertTrue([NSThread isMainThread]);
1464+
[self assertUserApple:authResult.user];
1465+
XCTAssertEqualObjects(authResult.additionalUserInfo.profile,
1466+
[[self class] appleProfile]);
1467+
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kDisplayName);
1468+
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID,
1469+
kAppleAuthProviderID);
1470+
XCTAssertNil(error);
1471+
[expectation fulfill];
1472+
}];
1473+
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
1474+
[self assertUserApple:[FIRAuth auth].currentUser];
1475+
OCMVerifyAll(_mockBackend);
1476+
}
1477+
13771478
/** @fn testSignInAnonymouslySuccess
13781479
@brief Tests the flow of a successful @c signInAnonymouslyWithCompletion: call.
13791480
*/
@@ -2584,6 +2685,53 @@ - (void)assertUserGoogle:(FIRUser *)user {
25842685
XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
25852686
}
25862687

2688+
/** @fn expectGetAccountInfoApple
2689+
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
2690+
data for a Apple Sign-In user.
2691+
*/
2692+
- (void)expectGetAccountInfoApple {
2693+
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
2694+
.andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
2695+
FIRGetAccountInfoResponseCallback callback) {
2696+
XCTAssertEqualObjects(request.APIKey, kAPIKey);
2697+
XCTAssertEqualObjects(request.accessToken, kAccessToken);
2698+
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
2699+
id mockAppleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
2700+
OCMStub([mockAppleUserInfo providerID]).andReturn(kAppleAuthProviderID);
2701+
OCMStub([mockAppleUserInfo displayName]).andReturn(kAppleDisplayName);
2702+
OCMStub([mockAppleUserInfo federatedID]).andReturn(kAppleID);
2703+
OCMStub([mockAppleUserInfo email]).andReturn(kAppleEmail);
2704+
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
2705+
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
2706+
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
2707+
OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
2708+
.andReturn((@[ mockAppleUserInfo ]));
2709+
id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
2710+
OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
2711+
mockGetAccountInfoResponseUser
2712+
]);
2713+
callback(mockGetAccountInfoResponse, nil);
2714+
});
2715+
});
2716+
}
2717+
2718+
/** @fn assertUserApple
2719+
@brief Asserts the given FIRUser matching the fake data returned by
2720+
@c expectGetAccountInfoApple.
2721+
@param user The user object to be verified.
2722+
*/
2723+
- (void)assertUserApple:(FIRUser *)user {
2724+
XCTAssertNotNil(user);
2725+
XCTAssertEqualObjects(user.uid, kLocalID);
2726+
XCTAssertEqualObjects(user.displayName, kDisplayName);
2727+
XCTAssertEqual(user.providerData.count, 1u);
2728+
id<FIRUserInfo> appleUserInfo = user.providerData[0];
2729+
XCTAssertEqualObjects(appleUserInfo.providerID, kAppleAuthProviderID);
2730+
XCTAssertEqualObjects(appleUserInfo.uid, kAppleID);
2731+
XCTAssertEqualObjects(appleUserInfo.displayName, kAppleDisplayName);
2732+
XCTAssertEqualObjects(appleUserInfo.email, kAppleEmail);
2733+
}
2734+
25872735
/** @fn expectGetAccountInfoAnonymous
25882736
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake anonymous
25892737
account data.

0 commit comments

Comments
 (0)