Skip to content

Commit 1229604

Browse files
fix passkey name caching issue (#12681)
1 parent 111f275 commit 1229604

File tree

2 files changed

+134
-5
lines changed

2 files changed

+134
-5
lines changed

FirebaseAuth/Sources/User/FIRUser.m

+8-5
Original file line numberDiff line numberDiff line change
@@ -611,12 +611,19 @@ - (void)startPasskeyEnrollmentWithName:(nullable NSString *)name
611611
callback:^(FIRStartPasskeyEnrollmentResponse *_Nullable response,
612612
NSError *_Nullable error) {
613613
if (error) {
614+
// reset the passkey name cache.
615+
self.passkeyName = nil;
614616
completion(nil, error);
615617
return;
616618
} else {
617619
// cached the passkey name. This is needed when calling
618620
// finalizePasskeyEnrollment
619621
self.passkeyName = name;
622+
// If passkey name is not provided, we will provide a firebase formatted
623+
// default name.
624+
if (self.passkeyName == nil || [self.passkeyName isEqual:@""]) {
625+
self.passkeyName = @"Unnamed account (Apple)";
626+
}
620627
NSData *challengeInData =
621628
[[NSData alloc] initWithBase64EncodedString:response.challenge
622629
options:0];
@@ -629,7 +636,7 @@ - (void)startPasskeyEnrollmentWithName:(nullable NSString *)name
629636
ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest *request =
630637
[provider
631638
createCredentialRegistrationRequestWithChallenge:challengeInData
632-
name:name
639+
name:self.passkeyName
633640
userID:userIdInData];
634641
completion(request, nil);
635642
}
@@ -651,11 +658,7 @@ - (void)finalizePasskeyEnrollmentWithPlatformCredential:
651658
[platformCredential.rawClientDataJSON base64EncodedStringWithOptions:0];
652659
NSString *attestationObject =
653660
[platformCredential.rawAttestationObject base64EncodedStringWithOptions:0];
654-
// If passkey name is not provided, we will provide a firebase formatted default name.
655661

656-
if (self.passkeyName != nil || [self.passkeyName isEqual:@""]) {
657-
self.passkeyName = @"Unnamed account (Apple)";
658-
}
659662
FIRFinalizePasskeyEnrollmentRequest *request =
660663
[[FIRFinalizePasskeyEnrollmentRequest alloc] initWithIDToken:self.rawAccessToken
661664
name:self.passkeyName

FirebaseAuth/Tests/Unit/FIRUserTests.m

+126
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,11 @@
413413
*/
414414
static NSString *const kPasskeyName = @"mockPasskeyName";
415415

416+
/** @var kDefaultPasskeyName
417+
@brief default passkey name.
418+
*/
419+
static NSString *const kDefaultPasskeyName = @"Unnamed account (Apple)";
420+
416421
/** @var kRpId
417422
@brief The fake passkey relying party identifier.
418423
*/
@@ -988,6 +993,125 @@ - (void)testStartPasskeyEnrollmentSuccess {
988993
}
989994
}
990995

996+
/** @fn testStartPasskeyEnrollmentWithNilNameSuccess
997+
@brief Tests the flow of a successful @c startPasskeyEnrollmentWithName:completion: call
998+
*/
999+
- (void)testStartPasskeyEnrollmentWithNilNameSuccess {
1000+
if (@available(iOS 15.0, tvOS 16.0, macOS 12.0, *)) {
1001+
OCMExpect([_mockBackend startPasskeyEnrollment:[OCMArg any] callback:[OCMArg any]])
1002+
.andCallBlock2(^(FIRStartPasskeyEnrollmentRequest *_Nullable request,
1003+
FIRStartPasskeyEnrollmentResponseCallback callback) {
1004+
XCTAssertEqualObjects(request.APIKey, kAPIKey);
1005+
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
1006+
id mockStartPasskeyEnrollmentResponse =
1007+
OCMClassMock([FIRStartPasskeyEnrollmentResponse class]);
1008+
OCMStub([mockStartPasskeyEnrollmentResponse rpID]).andReturn(kRpId);
1009+
OCMStub([mockStartPasskeyEnrollmentResponse challenge]).andReturn(kChallenge);
1010+
OCMStub([mockStartPasskeyEnrollmentResponse userID]).andReturn(kUserID);
1011+
callback(mockStartPasskeyEnrollmentResponse, nil);
1012+
});
1013+
});
1014+
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
1015+
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
1016+
[self
1017+
signInAnonymouslyWithMockGetAccountInfoResponse:mockGetAccountInfoResponseUser
1018+
completion:^(FIRUser *_Nonnull user) {
1019+
[user
1020+
startPasskeyEnrollmentWithName:nil
1021+
completion:^(
1022+
ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest
1023+
*_Nullable request,
1024+
NSError
1025+
*_Nullable error) {
1026+
XCTAssertNil(error);
1027+
XCTAssertEqualObjects(
1028+
user.passkeyName,
1029+
kDefaultPasskeyName);
1030+
XCTAssertEqualObjects(
1031+
request.name,
1032+
kDefaultPasskeyName);
1033+
XCTAssertEqualObjects(
1034+
[[request challenge]
1035+
base64EncodedStringWithOptions:
1036+
0],
1037+
kChallenge);
1038+
XCTAssertEqualObjects(
1039+
[request
1040+
relyingPartyIdentifier],
1041+
kRpId);
1042+
XCTAssertEqualObjects(
1043+
[[request userID]
1044+
base64EncodedStringWithOptions:
1045+
0],
1046+
kUserID);
1047+
[expectation fulfill];
1048+
}];
1049+
}];
1050+
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
1051+
OCMVerifyAll(_mockBackend);
1052+
}
1053+
}
1054+
1055+
/** @fn testStartPasskeyEnrollmentWithEmptyNameSuccess
1056+
@brief Tests the flow of a successful @c startPasskeyEnrollmentWithName:completion: call
1057+
*/
1058+
- (void)testStartPasskeyEnrollmentWithEmptyNameSuccess {
1059+
if (@available(iOS 15.0, tvOS 16.0, macOS 12.0, *)) {
1060+
OCMExpect([_mockBackend startPasskeyEnrollment:[OCMArg any] callback:[OCMArg any]])
1061+
.andCallBlock2(^(FIRStartPasskeyEnrollmentRequest *_Nullable request,
1062+
FIRStartPasskeyEnrollmentResponseCallback callback) {
1063+
XCTAssertEqualObjects(request.APIKey, kAPIKey);
1064+
dispatch_async(FIRAuthGlobalWorkQueue(), ^() {
1065+
id mockStartPasskeyEnrollmentResponse =
1066+
OCMClassMock([FIRStartPasskeyEnrollmentResponse class]);
1067+
OCMStub([mockStartPasskeyEnrollmentResponse rpID]).andReturn(kRpId);
1068+
OCMStub([mockStartPasskeyEnrollmentResponse challenge]).andReturn(kChallenge);
1069+
OCMStub([mockStartPasskeyEnrollmentResponse userID]).andReturn(kUserID);
1070+
callback(mockStartPasskeyEnrollmentResponse, nil);
1071+
});
1072+
});
1073+
XCTestExpectation *expectation = [self expectationWithDescription:@"callback"];
1074+
id mockGetAccountInfoResponseUser = OCMClassMock([FIRGetAccountInfoResponseUser class]);
1075+
[self
1076+
signInAnonymouslyWithMockGetAccountInfoResponse:mockGetAccountInfoResponseUser
1077+
completion:^(FIRUser *_Nonnull user) {
1078+
[user
1079+
startPasskeyEnrollmentWithName:@""
1080+
completion:^(
1081+
ASAuthorizationPlatformPublicKeyCredentialRegistrationRequest
1082+
*_Nullable request,
1083+
NSError
1084+
*_Nullable error) {
1085+
XCTAssertNil(error);
1086+
XCTAssertEqualObjects(
1087+
user.passkeyName,
1088+
kDefaultPasskeyName);
1089+
XCTAssertEqualObjects(
1090+
request.name,
1091+
kDefaultPasskeyName);
1092+
XCTAssertEqualObjects(
1093+
[[request challenge]
1094+
base64EncodedStringWithOptions:
1095+
0],
1096+
kChallenge);
1097+
1098+
XCTAssertEqualObjects(
1099+
[request
1100+
relyingPartyIdentifier],
1101+
kRpId);
1102+
XCTAssertEqualObjects(
1103+
[[request userID]
1104+
base64EncodedStringWithOptions:
1105+
0],
1106+
kUserID);
1107+
[expectation fulfill];
1108+
}];
1109+
}];
1110+
[self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil];
1111+
OCMVerifyAll(_mockBackend);
1112+
}
1113+
}
1114+
9911115
/** @fn testStartPasskeyEnrollmentFailure
9921116
@brief Tests the flow of a failed @c startPasskeyEnrollmentWithName:completion: call
9931117
*/
@@ -1008,6 +1132,8 @@ - (void)testStartPasskeyEnrollmentFailure {
10081132
NSError
10091133
*_Nullable error) {
10101134
XCTAssertNil(request);
1135+
XCTAssertNil(
1136+
user.passkeyName);
10111137
XCTAssertEqual(
10121138
error.code,
10131139
FIRAuthErrorCodeOperationNotAllowed);

0 commit comments

Comments
 (0)