Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for login with additional auth data #1848

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Parse/Parse/Internal/Commands/PFRESTUserCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ NS_ASSUME_NONNULL_BEGIN
password:(NSString *)password
revocableSession:(BOOL)revocableSessionEnabled
error:(NSError **)error;
+ (instancetype)logInUserCommandWithUsername:(NSString *)username
password:(NSString *)password
authData:(NSDictionary *)authData
revocableSession:(BOOL)revocableSessionEnabled
error:(NSError **)error;
+ (instancetype)serviceLoginUserCommandWithAuthenticationType:(NSString *)authenticationType
authenticationData:(NSDictionary *)authenticationData
revocableSession:(BOOL)revocableSessionEnabled
Expand Down
20 changes: 20 additions & 0 deletions Parse/Parse/Internal/Commands/PFRESTUserCommand.m
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,26 @@ + (instancetype)logInUserCommandWithUsername:(NSString *)username
error:error];
}

+ (instancetype)logInUserCommandWithUsername:(NSString *)username
password:(NSString *)password
authData:(NSDictionary *)authData
revocableSession:(BOOL)revocableSessionEnabled
error:(NSError **) error {
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithDictionary:@{
@"username" : username,
@"password" : password,
@"authData" : authData
}];

return [self _commandWithHTTPPath:@"login"
httpMethod:PFHTTPRequestMethodGET
parameters:parameters
sessionToken:nil
revocableSession:revocableSessionEnabled
error:error];
}


+ (instancetype)serviceLoginUserCommandWithAuthenticationType:(NSString *)authenticationType
authenticationData:(NSDictionary *)authenticationData
revocableSession:(BOOL)revocableSessionEnabled
Expand Down
4 changes: 4 additions & 0 deletions Parse/Parse/Internal/User/Controller/PFUserController.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ NS_ASSUME_NONNULL_BEGIN
- (BFTask *)logInCurrentUserAsyncWithUsername:(NSString *)username
password:(NSString *)password
revocableSession:(BOOL)revocableSession;
- (BFTask *)logInCurrentUserAsyncWithUsername:(NSString *)username
password:(NSString *)password
authData:(NSDictionary *)authData
revocableSession:(BOOL)revocableSession;

//TODO: (nlutsenko) Move this method into PFUserAuthenticationController after PFUser is decoupled further.
- (BFTask *)logInCurrentUserAsyncWithAuthType:(NSString *)authType
Expand Down
28 changes: 28 additions & 0 deletions Parse/Parse/Internal/User/Controller/PFUserController.m
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,34 @@ - (BFTask *)logInCurrentUserAsyncWithAuthType:(NSString *)authType
}];
}

- (BFTask *)logInCurrentUserAsyncWithUsername:(NSString *)username
password:(NSString *)password
authData:(NSDictionary *)authData
revocableSession:(BOOL)revocableSession {
@weakify(self);
return [[BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{
@strongify(self);
NSError *error;
PFRESTCommand *command = [PFRESTUserCommand logInUserCommandWithUsername:username
password:password
authData:authData
revocableSession:revocableSession
error:&error];
PFPreconditionReturnFailedTask(command, error);
return [self.commonDataSource.commandRunner runCommandAsync:command
withOptions:PFCommandRunningOptionRetryIfFailed];
}] continueWithSuccessBlock:^id(BFTask *task) {
PFCommandResult *result = task.result;
PFUser *user = [PFUser _objectFromDictionary:result.result
defaultClassName:[PFUser parseClassName]
completeData:YES];
@synchronized ([user lock]) {
[user startSave];
return [user _handleServiceLoginCommandResult:result];
}
}];
}

///--------------------------------------
#pragma mark - Reset Password
///--------------------------------------
Expand Down
33 changes: 33 additions & 0 deletions Parse/Parse/Source/PFUser.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,39 @@ typedef void(^PFUserLogoutResultBlock)(NSError *_Nullable error);
*/
+ (void)logInWithUsernameInBackground:(NSString *)username password:(NSString *)password block:(nullable PFUserResultBlock)block;

/**
Makes an *asynchronous* request to login a user with specified credentials and additional data.

Returns an instance of the successfully logged in `PFUser`.
This also caches the user locally so that calls to `+currentUser` will use the latest logged in user.

@param username The username of the user.
@param password The password of the user.
@param authData Additional data to be sent with the login request.

@return The task, that encapsulates the work being done.
*/
+ (BFTask<__kindof PFUser *> *)logInWithUsernameInBackground:(NSString *)username
password:(NSString *)password
authData:(NSDictionary *)authData;

/**
Makes an *asynchronous* request to log in a user with specified credentials and additional data.

Returns an instance of the successfully logged in `PFUser`.
This also caches the user locally so that calls to `+currentUser` will use the latest logged in user.

@param username The username of the user.
@param password The password of the user.
@param authData Additional data to be sent with the login request.
@param block The block to execute.
It should have the following argument signature: `^(PFUser *user, NSError *error)`.
*/
+ (void)logInWithUsernameInBackground:(NSString *)username
password:(NSString *)password
authData:(NSDictionary *)authData
block:(nullable PFUserResultBlock)block;

///--------------------------------------
#pragma mark - Becoming a User
///--------------------------------------
Expand Down
24 changes: 23 additions & 1 deletion Parse/Parse/Source/PFUser.m
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,13 @@
@synchronized([self lock]) {
NSMutableDictionary *serialized = [super _convertToDictionaryForSaving:changes withObjectEncoder:encoder error:error];
if (self.authData.count > 0) {
serialized[PFUserAuthDataRESTKey] = [self.authData copy];
NSMutableDictionary *authDataCopy = [self.authData mutableCopy];

Check warning on line 187 in Parse/Parse/Source/PFUser.m

View check run for this annotation

Codecov / codecov/patch

Parse/Parse/Source/PFUser.m#L187

Added line #L187 was not covered by tests
// Remove 'mfa' from authData to prevent it from being saved to the server.
// This ensures that MFA setup changes are not unintentionally triggered.
[authDataCopy removeObjectForKey:@"mfa"];
if (authDataCopy.count > 0) {
serialized[PFUserAuthDataRESTKey] = [authDataCopy copy];
}

Check warning on line 193 in Parse/Parse/Source/PFUser.m

View check run for this annotation

Codecov / codecov/patch

Parse/Parse/Source/PFUser.m#L190-L193

Added lines #L190 - L193 were not covered by tests
}
return serialized;
}
Expand Down Expand Up @@ -838,6 +844,22 @@
[[self logInWithUsernameInBackground:username password:password] thenCallBackOnMainThreadAsync:block];
}

+ (BFTask *)logInWithUsernameInBackground:(NSString *)username
password:(NSString *)password
authData:(NSDictionary *)authData {
return [[self userController] logInCurrentUserAsyncWithUsername:username
password:password
authData:authData
revocableSession:[self _isRevocableSessionEnabled]];
}

Check warning on line 854 in Parse/Parse/Source/PFUser.m

View check run for this annotation

Codecov / codecov/patch

Parse/Parse/Source/PFUser.m#L849-L854

Added lines #L849 - L854 were not covered by tests

+ (void)logInWithUsernameInBackground:(NSString *)username
password:(NSString *)password
authData:(NSDictionary *)authData
block:(PFUserResultBlock)block {
[[self logInWithUsernameInBackground:username password:password authData:authData] thenCallBackOnMainThreadAsync:block];
}

Check warning on line 861 in Parse/Parse/Source/PFUser.m

View check run for this annotation

Codecov / codecov/patch

Parse/Parse/Source/PFUser.m#L859-L861

Added lines #L859 - L861 were not covered by tests

///--------------------------------------
#pragma mark - Third-party Authentication
///--------------------------------------
Expand Down
29 changes: 29 additions & 0 deletions Parse/Tests/Unit/UserCommandTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,35 @@ - (void)testLogInCommand {
XCTAssertFalse(command.revocableSessionEnabled);
}

- (void)testLogInCommandWithAuthData {
NSDictionary *authData = @{ @"mfa" : @{ @"token" : @"000000" } };
PFRESTUserCommand *command = [PFRESTUserCommand logInUserCommandWithUsername:@"a"
password:@"b"
authData:authData
revocableSession:YES
error:nil];
XCTAssertNotNil(command);
XCTAssertEqualObjects(command.httpPath, @"login");
XCTAssertEqualObjects(command.httpMethod, PFHTTPRequestMethodGET);
XCTAssertNotNil(command.parameters);
XCTAssertNotNil(command.parameters[@"username"]);
XCTAssertNotNil(command.parameters[@"password"]);
XCTAssertNotNil(command.parameters[@"authData"]);
XCTAssertEqualObjects(command.parameters[@"authData"], authData);
XCTAssertEqual(command.additionalRequestHeaders.count, 1);
XCTAssertTrue(command.revocableSessionEnabled);
XCTAssertNil(command.sessionToken);

command = [PFRESTUserCommand logInUserCommandWithUsername:@"a"
password:@"b"
authData:authData
revocableSession:NO
error:nil];
XCTAssertNotNil(command);
XCTAssertEqual(command.additionalRequestHeaders.count, 0);
XCTAssertFalse(command.revocableSessionEnabled);
}

- (void)testServiceLoginCommandWithAuthTypeData {
PFRESTUserCommand *command = [PFRESTUserCommand serviceLoginUserCommandWithAuthenticationType:@"a"
authenticationData:@{ @"b" : @"c" }
Expand Down
41 changes: 41 additions & 0 deletions Parse/Tests/Unit/UserControllerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,47 @@ - (void)testLogInCurrentUserWithUsernamePasswordNullResult {
OCMVerifyAll(commandRunner);
}

- (void)testLogInCurrentUserWithUsernamePasswordAuthData {
id commonDataSource = [self mockedCommonDataSource];
id coreDataSource = [self mockedCoreDataSource];
id commandRunner = [commonDataSource commandRunner];

NSDictionary *authData = @{ @"mfa" : @{ @"token" : @"000000" } };
id commandResult = @{ @"objectId" : @"a",
@"yarr" : @1 };
[commandRunner mockCommandResult:commandResult forCommandsPassingTest:^BOOL(id obj) {
PFRESTCommand *command = obj;

XCTAssertEqualObjects(command.httpMethod, PFHTTPRequestMethodGET);
XCTAssertNotEqual([command.httpPath rangeOfString:@"login"].location, NSNotFound);
XCTAssertNil(command.sessionToken);
XCTAssertEqualObjects(command.parameters, (@{ @"username" : @"yolo" , @"password" : @"yarr", @"authData" : authData }));
XCTAssertEqualObjects(command.additionalRequestHeaders, @{ @"X-Parse-Revocable-Session" : @"1" });

return YES;
}];

id currentUserController = [coreDataSource currentUserController];
PFUserController *controller = [PFUserController controllerWithCommonDataSource:commonDataSource
coreDataSource:coreDataSource];

XCTestExpectation *expectation = [self currentSelectorTestExpectation];
[[controller logInCurrentUserAsyncWithUsername:@"yolo"
password:@"yarr"
authData:authData
revocableSession:YES] continueWithBlock:^id(BFTask *task) {
PFUser *user = task.result;
XCTAssertNotNil(user);
XCTAssertEqualObjects(user.objectId, @"a");
XCTAssertEqualObjects(user[@"yarr"], @1);
[expectation fulfill];
return nil;
}];
[self waitForTestExpectations];

OCMVerifyAll(currentUserController);
}

- (void)testRequestPasswordReset {
id commonDataSource = [self mockedCommonDataSource];
id coreDataSource = [self mockedCoreDataSource];
Expand Down