Skip to content

Commit

Permalink
Merge cfe6f4e into c105a0d
Browse files Browse the repository at this point in the history
  • Loading branch information
aiwenisevan authored Aug 12, 2022
2 parents c105a0d + cfe6f4e commit ee1587c
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 1 deletion.
8 changes: 8 additions & 0 deletions FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential.m
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ - (instancetype)initWithProviderID:(NSString *)providerID
rawNonce:(nullable NSString *)rawNonce
accessToken:(nullable NSString *)accessToken
secret:(nullable NSString *)secret
displayName:(nullable NSString *)displayName
pendingToken:(nullable NSString *)pendingToken {
self = [super initWithProvider:providerID];
if (self) {
Expand All @@ -53,6 +54,7 @@ - (instancetype)initWithProviderID:(NSString *)providerID
_accessToken = accessToken;
_pendingToken = pendingToken;
_secret = secret;
_displayName = displayName;
}
return self;
}
Expand All @@ -65,6 +67,7 @@ - (instancetype)initWithProviderID:(NSString *)providerID
rawNonce:nil
accessToken:nil
secret:nil
displayName:nil
pendingToken:nil];
if (self) {
_OAuthResponseURLString = OAuthResponseURLString;
Expand All @@ -81,6 +84,7 @@ - (nullable instancetype)initWithVerifyAssertionResponse:(FIRVerifyAssertionResp
rawNonce:nil
accessToken:response.oauthAccessToken
secret:response.oauthSecretToken
displayName:nil
pendingToken:response.pendingToken];
}
return nil;
Expand All @@ -94,6 +98,7 @@ - (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request {
request.sessionID = _sessionID;
request.providerOAuthTokenSecret = _secret;
request.pendingToken = _pendingToken;
request.displayName = _displayName;
}

#pragma mark - NSSecureCoding
Expand All @@ -108,11 +113,13 @@ - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
NSString *accessToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"accessToken"];
NSString *pendingToken = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"pendingToken"];
NSString *secret = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"secret"];
NSString *displayName = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"displayName"];
self = [self initWithProviderID:self.provider
IDToken:IDToken
rawNonce:rawNonce
accessToken:accessToken
secret:secret
displayName:displayName
pendingToken:pendingToken];
return self;
}
Expand All @@ -123,6 +130,7 @@ - (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.accessToken forKey:@"accessToken"];
[aCoder encodeObject:self.pendingToken forKey:@"pendingToken"];
[aCoder encodeObject:self.secret forKey:@"secret"];
[aCoder encodeObject:self.displayName forKey:@"displayName"];
}

@end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ NS_ASSUME_NONNULL_BEGIN
@param accessToken The access token associated with the credential being created.
@param secret The secret associated with the credential being created.
@param pendingToken The pending token associated with the credential being created.
@param displayName The displayName associated with the credential being created.
*/
- (instancetype)initWithProviderID:(NSString *)providerID
IDToken:(nullable NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce
accessToken:(nullable NSString *)accessToken
secret:(nullable NSString *)secret
displayName:(nullable NSString *)displayName
pendingToken:(nullable NSString *)pendingToken NS_DESIGNATED_INITIALIZER;

/** @fn initWithProviderId:sessionID:OAuthResponseURLString:
Expand Down
18 changes: 18 additions & 0 deletions FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthProvider.m
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ + (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
rawNonce:nil
accessToken:accessToken
secret:nil
displayName:nil
pendingToken:nil];
}

Expand All @@ -98,6 +99,7 @@ + (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
rawNonce:nil
accessToken:accessToken
secret:nil
displayName:nil
pendingToken:nil];
}

Expand All @@ -110,6 +112,7 @@ + (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
rawNonce:rawNonce
accessToken:accessToken
secret:nil
displayName:nil
pendingToken:nil];
}

Expand All @@ -121,6 +124,21 @@ + (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
rawNonce:rawNonce
accessToken:nil
secret:nil
displayName:nil
pendingToken:nil];
}

+ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
IDToken:(NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce
accessToken:(nullable NSString *)accessToken
displayName:(nonnull NSString *)displayName {
return [[FIROAuthCredential alloc] initWithProviderID:providerID
IDToken:IDToken
rawNonce:rawNonce
accessToken:accessToken
secret:nil
displayName:displayName
pendingToken:nil];
}

Expand Down
5 changes: 5 additions & 0 deletions FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property(nonatomic, assign) BOOL autoCreate;

/** @property displayName
@brief A displayName linked to its provider
*/
@property(nonatomic, copy, nullable) NSString *displayName;

/** @fn initWithEndpoint:requestConfiguration:
@brief Please use initWithProviderID:requestConfifuration instead.
*/
Expand Down
10 changes: 10 additions & 0 deletions FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
*/
static NSString *const kReturnSecureTokenKey = @"returnSecureToken";

/** @var kDisplayName
@brief The key for the "displayName" value in the request.
*/
static NSString *const kDisplayNameKey = @"displayName";

/** @var kReturnIDPCredentialKey
@brief The key for the "returnIdpCredential" value in the request.
*/
Expand Down Expand Up @@ -171,6 +176,11 @@ - (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)
if (_sessionID) {
body[kSessionIDKey] = _sessionID;
}

if (_displayName) {
body[kDisplayNameKey] = _displayName;
}

if (self.tenantID) {
body[kTenantIDKey] = self.tenantID;
}
Expand Down
5 changes: 5 additions & 0 deletions FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthCredential.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ NS_SWIFT_NAME(OAuthCredential)
*/
@property(nonatomic, readonly, nullable) NSString *secret;

/** @property displayName
@brief The displayName associated with this credential.
*/
@property(nonatomic, readonly, nullable) NSString *displayName;

/** @fn init
@brief This class is not supposed to be instantiated directly.
*/
Expand Down
18 changes: 18 additions & 0 deletions FirebaseAuth/Sources/Public/FirebaseAuth/FIROAuthProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,24 @@ NS_SWIFT_NAME(OAuthProvider)
IDToken:(NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce;

/** @fn credentialWithProviderID:IDToken:rawNonce:accessToken:
@brief Creates an `AuthCredential` for that OAuth 2 provider identified by provider ID, ID
token, raw nonce, and access token.
@param providerID The provider ID associated with the Auth credential being created.
@param IDToken The IDToken associated with the Auth credential being created.
@param rawNonce The raw nonce associated with the Auth credential being created.
@param accessToken The access token associated with the Auth credential be created, if
available.
@param displayName The displayName associated with the Auth credential being created.
@return A `AuthCredential` for the specified provider ID, ID token and access token.
*/
+ (FIROAuthCredential *)credentialWithProviderID:(NSString *)providerID
IDToken:(NSString *)IDToken
rawNonce:(nullable NSString *)rawNonce
accessToken:(nullable NSString *)accessToken
displayName:(NSString *)displayName;

/** @fn init
@brief This class is not meant to be initialized.
*/
Expand Down
4 changes: 3 additions & 1 deletion FirebaseAuth/Tests/Sample/Sample/MainViewController+OAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,12 @@ - (void)reauthenticateWithApple {
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)) {
ASAuthorizationAppleIDCredential* appleIDCredential = authorization.credential;
NSString *IDToken = [NSString stringWithUTF8String:[appleIDCredential.identityToken bytes]];
NSString *displayName = [appleIDCredential.fullName.givenName stringByAppendingFormat:@" %@", appleIDCredential.fullName.familyName];
FIROAuthCredential *credential = [FIROAuthProvider credentialWithProviderID:@"apple.com"
IDToken:IDToken
rawNonce:self.appleRawNonce
accessToken:nil];
accessToken:nil
displayName:displayName];

if ([appleIDCredential.state isEqualToString:@"signIn"]) {
[FIRAuth.auth signInWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
Expand Down
148 changes: 148 additions & 0 deletions FirebaseAuth/Tests/Unit/FIRAuthTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,36 @@
*/
static NSString *const kGoogleIDToken = @"GOOGLE_ID_TOKEN";

/** @var kAppleAuthProviderID
@brief The provider ID for Apple Sign-In.
*/
static NSString *const kAppleAuthProviderID = @"apple.com";

/** @var kAppleUD
@brief The fake user ID under Apple Sign-In.
*/
static NSString *const kAppleID = @"APPLE_ID";

/** @var kAppleEmail
@brief The fake user email under Apple Sign-In.
*/
static NSString *const kAppleEmail = @"user@icloud.com";

/** @var kAppleDisplayName
@brief The fake user display name under Apple Sign-In.
*/
static NSString *const kAppleDisplayName = @"Apple Doe";

/** @var kAppleAccessToken
@brief The fake access token from Apple Sign-In.
*/
static NSString *const kAppleAccessToken = @"Apple_ACCESS_TOKEN";

/** @var kAppleIDToken
@brief The fake ID token from Apple Sign-In.
*/
static NSString *const kAppleIDToken = @"APPLE_ID_TOKEN";

/** @var kCustomToken
@brief The fake custom token to sign in.
*/
Expand Down Expand Up @@ -321,6 +351,23 @@ + (NSDictionary *)googleProfile {
return kGoogleProfile;
}

/** @fn appleProfile
@brief The fake user profile under additional user data in @c FIRVerifyAssertionResponse.
*/
+ (NSDictionary *)appleProfile {
static NSDictionary *kAppleProfile = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
kAppleProfile = @{
@"iss" : @"https://accounts.apple.com\\",
@"email" : kAppleEmail,
@"given_name" : @"User",
@"family_name" : @"Doe"
};
});
return kAppleProfile;
}

- (void)setUp {
[super setUp];

Expand Down Expand Up @@ -1374,6 +1421,60 @@ - (void)testSignInWithGoogleCredentialFailure {
OCMVerifyAll(_mockBackend);
}

/** @fn testSignInWithOAuthCredentialWithDisplayNameSuccess
@brief Tests the flow of a successful @c signInWithCredential:completion: call
with an Apple Sign-In credential.
This method differntiates the testSignInWithCredentialSuccess only in verifying displayName
*/
- (void)testSignInWithOAuthCredentialWithDisplayNameSuccess {
OCMExpect([_mockBackend verifyAssertion:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRVerifyAssertionRequest *_Nullable request,
FIRVerifyAssertionResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.providerID, kAppleAuthProviderID);
XCTAssertEqualObjects(request.providerIDToken, kAppleIDToken);
XCTAssertEqualObjects(request.providerAccessToken, kAppleAccessToken);
XCTAssertEqualObjects(request.displayName, kAppleDisplayName);
XCTAssertTrue(request.returnSecureToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockVerifyAssertionResponse = OCMClassMock([FIRVerifyAssertionResponse class]);
OCMStub([mockVerifyAssertionResponse federatedID]).andReturn(kAppleID);
OCMStub([mockVerifyAssertionResponse providerID]).andReturn(kAppleAuthProviderID);
OCMStub([mockVerifyAssertionResponse localID]).andReturn(kLocalID);
OCMStub([mockVerifyAssertionResponse displayName]).andReturn(kAppleDisplayName);
OCMStub([mockVerifyAssertionResponse profile]).andReturn([[self class] appleProfile]);
OCMStub([mockVerifyAssertionResponse username]).andReturn(kDisplayName);
[self stubTokensWithMockResponse:mockVerifyAssertionResponse];
callback(mockVerifyAssertionResponse, nil);
});
});
[self expectGetAccountInfoApple];
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
[[FIRAuth auth] signOut:NULL];
FIRAuthCredential *appleCredential =
[FIROAuthProvider credentialWithProviderID:kAppleAuthProviderID
IDToken:kAppleIDToken
rawNonce:nil
accessToken:kAppleAccessToken
displayName:kAppleDisplayName];
[[FIRAuth auth]
signInWithCredential:appleCredential
completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
XCTAssertTrue([NSThread isMainThread]);
[self assertUserApple:authResult.user];
XCTAssertEqualObjects(authResult.additionalUserInfo.profile,
[[self class] appleProfile]);
XCTAssertEqualObjects(authResult.additionalUserInfo.username, kDisplayName);
XCTAssertEqualObjects(authResult.additionalUserInfo.providerID,
kAppleAuthProviderID);
XCTAssertNil(error);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
[self assertUserApple:[FIRAuth auth].currentUser];
OCMVerifyAll(_mockBackend);
}

/** @fn testSignInAnonymouslySuccess
@brief Tests the flow of a successful @c signInAnonymouslyWithCompletion: call.
*/
Expand Down Expand Up @@ -2584,6 +2685,53 @@ - (void)assertUserGoogle:(FIRUser *)user {
XCTAssertEqualObjects(googleUserInfo.email, kGoogleEmail);
}

/** @fn expectGetAccountInfoApple
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake account
data for a Apple Sign-In user.
*/
- (void)expectGetAccountInfoApple {
OCMExpect([_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]])
.andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request,
FIRGetAccountInfoResponseCallback callback) {
XCTAssertEqualObjects(request.APIKey, kAPIKey);
XCTAssertEqualObjects(request.accessToken, kAccessToken);
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
id mockAppleUserInfo = OCMClassMock([FIRGetAccountInfoResponseProviderUserInfo class]);
OCMStub([mockAppleUserInfo providerID]).andReturn(kAppleAuthProviderID);
OCMStub([mockAppleUserInfo displayName]).andReturn(kAppleDisplayName);
OCMStub([mockAppleUserInfo federatedID]).andReturn(kAppleID);
OCMStub([mockAppleUserInfo email]).andReturn(kAppleEmail);
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID);
OCMStub([mockGetAccountInfoResponseUser displayName]).andReturn(kDisplayName);
OCMStub([mockGetAccountInfoResponseUser providerUserInfo])
.andReturn((@[ mockAppleUserInfo ]));
id mockGetAccountInfoResponse = OCMClassMock([FIRGetAccountInfoResponse class]);
OCMStub([mockGetAccountInfoResponse users]).andReturn(@[
mockGetAccountInfoResponseUser
]);
callback(mockGetAccountInfoResponse, nil);
});
});
}

/** @fn assertUserApple
@brief Asserts the given FIRUser matching the fake data returned by
@c expectGetAccountInfoApple.
@param user The user object to be verified.
*/
- (void)assertUserApple:(FIRUser *)user {
XCTAssertNotNil(user);
XCTAssertEqualObjects(user.uid, kLocalID);
XCTAssertEqualObjects(user.displayName, kDisplayName);
XCTAssertEqual(user.providerData.count, 1u);
id<FIRUserInfo> appleUserInfo = user.providerData[0];
XCTAssertEqualObjects(appleUserInfo.providerID, kAppleAuthProviderID);
XCTAssertEqualObjects(appleUserInfo.uid, kAppleID);
XCTAssertEqualObjects(appleUserInfo.displayName, kAppleDisplayName);
XCTAssertEqualObjects(appleUserInfo.email, kAppleEmail);
}

/** @fn expectGetAccountInfoAnonymous
@brief Expects a GetAccountInfo request on the mock backend and calls back with fake anonymous
account data.
Expand Down
Loading

0 comments on commit ee1587c

Please sign in to comment.