Skip to content

Commit

Permalink
start passkey sign in request & response
Browse files Browse the repository at this point in the history
  • Loading branch information
Xiaoshouzi-gh committed Oct 3, 2023
1 parent 1dd888a commit 04efac4
Show file tree
Hide file tree
Showing 8 changed files with 574 additions and 0 deletions.
30 changes: 30 additions & 0 deletions FirebaseAuth/Sources/Backend/FIRAuthBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
@class FIRGetRecaptchaConfigResponse;
@class FIRStartPasskeyEnrollmentRequest;
@class FIRStartPasskeyEnrollmentResponse;
@class FIRStartPasskeySignInRequest;
@class FIRStartPasskeySignInResponse;

@protocol FIRAuthBackendImplementation;
@protocol FIRAuthBackendRPCIssuer;
Expand Down Expand Up @@ -266,6 +268,17 @@ endpoint.
typedef void (^FIRStartPasskeyEnrollmentResponseCallback)(
FIRStartPasskeyEnrollmentResponse *_Nullable response, NSError *_Nullable error);

/**
@typedef FIRStartPasskeySinInResponseCallback
@brief The type of block used to return the result of a call to the StartPasskeySignIn
endpoint.
@param response The received response, if any.
@param error The error which occurred, if any.
@remarks One of response or error will be non-nil.
*/
typedef void (^FIRStartPasskeySignInResponseCallback)(
FIRStartPasskeySignInResponse *_Nullable response, NSError *_Nullable error);

/** @class FIRAuthBackend
@brief Simple static class with methods representing the backend RPCs.
@remarks All callback blocks passed as method parameters are invoked asynchronously on the
Expand Down Expand Up @@ -471,6 +484,15 @@ typedef void (^FIRStartPasskeyEnrollmentResponseCallback)(
*/
+ (void)startPasskeyEnrollment:(FIRStartPasskeyEnrollmentRequest *)request
callback:(FIRStartPasskeyEnrollmentResponseCallback)callback;

/** @fn startPasskeySignInt:callback:
@brief Calls the startPasskeySignIn endpoint, which is responsible for receving the
challenge that will later be consumed for platform key attestation.
@param request The request parameters.
@param callback The callback.
*/
+ (void)startPasskeySignIn:(FIRStartPasskeySignInRequest *)request
callback:(FIRStartPasskeySignInResponseCallback)callback;
#endif

/** @fn revokeToken:callback:
Expand Down Expand Up @@ -656,6 +678,14 @@ typedef void (^FIRStartPasskeyEnrollmentResponseCallback)(
*/
- (void)startPasskeyEnrollment:(FIRStartPasskeyEnrollmentRequest *)request
callback:(FIRStartPasskeyEnrollmentResponseCallback)callback;

/** @fn startPasskeySignIn:callback:
@brief Calls the startPasskeySignIn endpoint, which is responsible for receving the challange.
@param request The request parameters.
@param callback The callback.
*/
- (void)startPasskeySignIn:(FIRStartPasskeySignInRequest *)request
callback:(FIRStartPasskeySignInResponseCallback)callback;
#endif

/** @fn revokeToken:callback:
Expand Down
22 changes: 22 additions & 0 deletions FirebaseAuth/Sources/Backend/FIRAuthBackend.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@
#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeyEnrollmentRequest.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeyEnrollmentResponse.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInRequest.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInResponse.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyClientRequest.h"
Expand Down Expand Up @@ -676,6 +678,11 @@ + (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callb
#endif

#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_OSX || TARGET_OS_MACCATALYST
+ (void)startPasskeySignIn:(FIRStartPasskeySignInRequest *)request
callback:(FIRStartPasskeySignInResponseCallback)callback {
[[self implementation] startPasskeySignIn:request callback:callback];
}

+ (void)startPasskeyEnrollment:(FIRStartPasskeyEnrollmentRequest *)request
callback:(FIRStartPasskeyEnrollmentResponseCallback)callback {
[[self implementation] startPasskeyEnrollment:request callback:callback];
Expand Down Expand Up @@ -1109,6 +1116,21 @@ - (void)verifyClient:(id)request callback:(FIRVerifyClientResponseCallback)callb
#endif

#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_OSX || TARGET_OS_MACCATALYST

- (void)startPasskeySignIn:(FIRStartPasskeySignInRequest *)request
callback:(FIRStartPasskeySignInResponseCallback)callback {
FIRStartPasskeySignInResponse *response = [[FIRStartPasskeySignInResponse alloc] init];
[self callWithRequest:request
response:response
callback:^(NSError *error) {
if (error) {
callback(nil, error);
return;
}
callback(response, nil);
}];
}

- (void)startPasskeyEnrollment:(FIRStartPasskeyEnrollmentRequest *)request
callback:(FIRStartPasskeyEnrollmentResponseCallback)callback {
FIRStartPasskeyEnrollmentResponse *response = [[FIRStartPasskeyEnrollmentResponse alloc] init];
Expand Down
32 changes: 32 additions & 0 deletions FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInRequest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "FirebaseAuth/Sources/Backend/FIRAuthRPCRequest.h"
#import "FirebaseAuth/Sources/Backend/FIRIdentityToolkitRequest.h"

NS_ASSUME_NONNULL_BEGIN

/** @class FIRStartPasskeySignInRequest
@brief Represents the parameters for the startPasskeySignIn endpoint.
*/
@interface FIRStartPasskeySignInRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest>

- (nullable instancetype)initWithRequestConfiguration:
(FIRAuthRequestConfiguration *)requestConfiguration;

@end

NS_ASSUME_NONNULL_END
57 changes: 57 additions & 0 deletions FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInRequest.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInRequest.h"

NS_ASSUME_NONNULL_BEGIN

/**
@var kStartPasskeySignInEndPoint
@brief GCIP endpoint for startPasskeySignIn rpc
*/
static NSString *const kStartPasskeySignInEndPoint = @"accounts/passkeySignIn:start";

/**
@var kTenantIDKey
@brief The key for the tenant id value in the request.
*/
static NSString *const kTenantIDKey = @"tenantId";

@implementation FIRStartPasskeySignInRequest

- (nullable instancetype)initWithRequestConfiguration:
(FIRAuthRequestConfiguration *)requestConfiguration {
self = [super initWithEndpoint:kStartPasskeySignInEndPoint
requestConfiguration:requestConfiguration];

if (self) {
self.useIdentityPlatform = YES;
}

return self;
}

- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *__autoreleasing _Nullable *)error {
NSMutableDictionary *postBody = [NSMutableDictionary dictionary];
if (self.tenantID) {
postBody[kTenantIDKey] = self.tenantID;
}
return [postBody copy];
}

@end

NS_ASSUME_NONNULL_END
41 changes: 41 additions & 0 deletions FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInResponse.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "FirebaseAuth/Sources/Backend/FIRAuthRPCResponse.h"

NS_ASSUME_NONNULL_BEGIN

/**
@class FIRStartPasskeySignInResponse
@brief Represents the response from the startPasskeySignIn endpoint.
*/
@interface FIRStartPasskeySignInResponse : NSObject <FIRAuthRPCResponse>

/**
@property rpID
@brief The RP ID of the FIDO Relying Party.
*/
@property(nonatomic, readonly, copy) NSString *rpID;

/**
@property challenge
@brief The FIDO challenge.
*/
@property(nonatomic, readonly, copy) NSString *challenge;

@end

NS_ASSUME_NONNULL_END
57 changes: 57 additions & 0 deletions FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInResponse.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInResponse.h"

/**
@var kOptionsKey
@brief Parameters specified for the authenticator to sign a challenge.
*/
static const NSString *kOptionsKey = @"credentialRequestOptions";

/**
@var kRpIdKey
@brief // The relying party identifier.
*/
static const NSString *kRpIdKey = @"rpId";

/**
@var kChallengeKey
@brief The name of the field in the response JSON for challenge.
*/
static const NSString *kChallengeKey = @"challenge";

@implementation FIRStartPasskeySignInResponse

- (BOOL)setWithDictionary:(nonnull NSDictionary *)dictionary
error:(NSError *__autoreleasing _Nullable *_Nullable)error {
if (dictionary[kOptionsKey] == nil) {
return NO;
}
if (dictionary[kOptionsKey][kRpIdKey] == nil) {
return NO;
}

if (dictionary[kOptionsKey][kChallengeKey] == nil) {
return NO;
}

_rpID = dictionary[kOptionsKey][kRpIdKey];
_challenge = dictionary[kOptionsKey][kChallengeKey];
return YES;
}

@end
96 changes: 96 additions & 0 deletions FirebaseAuth/Tests/Unit/FIRStartPasskeySignInRequestTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import <TargetConditionals.h>
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_OSX || TARGET_OS_MACCATALYST

#import <XCTest/XCTest.h>

#import "FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInRequest.h"
#import "FirebaseAuth/Sources/Backend/RPC/FIRStartPasskeySignInResponse.h"
#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuthErrors.h"
#import "FirebaseAuth/Tests/Unit/FIRFakeBackendRPCIssuer.h"

/**
@var kTestAPIKey
@brief Fake API key used for testing.
*/
static NSString *const kTestAPIKey = @"APIKey";

/**
@var kTestFirebaseAppID
@brief Fake Firebase app ID used for testing.
*/
static NSString *const kTestFirebaseAppID = @"appID";

/**
@var kExpectedAPIURL
@brief The expected URL for the test calls.
*/
static NSString *const kExpectedAPIURL =
@"https://identitytoolkit.googleapis.com/v2/accounts/passkeySignIn:start?key=APIKey";

/**
@class FIRStartPasskeySignInRequestTests
@brief Tests for @c FIRStartPasskeySignInRequest.
*/
@interface FIRStartPasskeySignInRequestTests : XCTestCase
@end

@implementation FIRStartPasskeySignInRequestTests {
/**
@brief This backend RPC issuer is used to fake network responses for each test in the suite.
In the @c setUp method we initialize this and set @c FIRAuthBackend's RPC issuer to it.
*/
FIRFakeBackendRPCIssuer *_RPCIssuer;

/**
@brief This is the request configuration used for testing.
*/
FIRAuthRequestConfiguration *_requestConfiguration;
}

- (void)setUp {
[super setUp];
FIRFakeBackendRPCIssuer *RPCIssuer = [[FIRFakeBackendRPCIssuer alloc] init];
[FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:RPCIssuer];
_RPCIssuer = RPCIssuer;
_requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:kTestAPIKey
appID:kTestFirebaseAppID];
}

- (void)tearDown {
_RPCIssuer = nil;
_requestConfiguration = nil;
[FIRAuthBackend setDefaultBackendImplementationWithRPCIssuer:nil];
[super tearDown];
}

- (void)testStartPasskeySignInRequest {
FIRStartPasskeySignInRequest *request =
[[FIRStartPasskeySignInRequest alloc] initWithRequestConfiguration:_requestConfiguration];

[FIRAuthBackend startPasskeySignIn:request
callback:^(FIRStartPasskeySignInResponse *_Nullable response,
NSError *_Nullable error){
}];

XCTAssertEqualObjects(_RPCIssuer.requestURL.absoluteString, kExpectedAPIURL);
XCTAssertNotNil(_RPCIssuer.decodedRequest);
}

@end
#endif
Loading

0 comments on commit 04efac4

Please sign in to comment.