Skip to content
Snippets Groups Projects
Commit 9f6a4bd6 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Implemented rejected join persistence

parent 6f493c2f
No related branches found
No related tags found
No related merge requests found
...@@ -83,4 +83,6 @@ interface UserDAO { ...@@ -83,4 +83,6 @@ interface UserDAO {
function findJoinableUsersByEmail(string $email): array; function findJoinableUsersByEmail(string $email): array;
function findJoinableUsersByUserId(string $userId): array; function findJoinableUsersByUserId(string $userId): array;
function insertRejectedJoin(string $userId1, string $userId2): void;
} }
...@@ -351,4 +351,18 @@ class MySQLUserDAO extends BaseMySQLDAO implements UserDAO { ...@@ -351,4 +351,18 @@ class MySQLUserDAO extends BaseMySQLDAO implements UserDAO {
return $results; return $results;
} }
function insertRejectedJoin(string $userId1, string $userId2): void {
$dbh = $this->getDBHandler();
$query = "INSERT INTO keep_separated (user_id1, user_id2) VALUES (:id1, :id2)\n"
. "ON DUPLICATE KEY UPDATE user_id1 = user_id1, user_id2 = user_id2";
$stmt = $dbh->prepare($query);
$stmt->bindParam(':id1', $userId1);
$stmt->bindParam(':id2', $userId2);
$stmt->execute();
}
} }
...@@ -78,11 +78,6 @@ class LoginHandler { ...@@ -78,11 +78,6 @@ class LoginHandler {
$this->joinUsers(); $this->joinUsers();
$autoJoinStep = $this->checkAutoJoin();
if ($autoJoinStep !== null) {
return $autoJoinStep;
}
return $this->getAfterLoginRedirect(); return $this->getAfterLoginRedirect();
} }
...@@ -105,6 +100,7 @@ class LoginHandler { ...@@ -105,6 +100,7 @@ class LoginHandler {
return $this->showConfirmJoin($userToJoin); return $this->showConfirmJoin($userToJoin);
} }
$session->setAutojoin(false);
return null; return null;
} }
...@@ -120,8 +116,9 @@ class LoginHandler { ...@@ -120,8 +116,9 @@ class LoginHandler {
$session->setJoinRejected(true); $session->setJoinRejected(true);
if ($session->getUser()->id === null) { if ($session->getUser()->id === null) {
return $this->redirectToTOUCheck($session->getUser()->identities[0]); return $this->redirectToTOUCheck();
} else { } else {
$this->saveRejectedJoinIfPossible();
return $this->getAfterLoginRedirect(); return $this->getAfterLoginRedirect();
} }
} }
...@@ -158,12 +155,8 @@ class LoginHandler { ...@@ -158,12 +155,8 @@ class LoginHandler {
$user = $session->getUser(); $user = $session->getUser();
$userToJoin = $session->getUserToJoin(); $userToJoin = $session->getUserToJoin();
if ($user === null) {
$session->setUser($userToJoin);
} else {
$joinedUser = $this->locator->getUserHandler()->joinUsers($userToJoin, $user); $joinedUser = $this->locator->getUserHandler()->joinUsers($userToJoin, $user);
$session->setUser($joinedUser); $session->setUser($joinedUser);
}
if ($session->getAction() === 'join') { if ($session->getAction() === 'join') {
$session->setAction('account'); $session->setAction('account');
...@@ -174,7 +167,15 @@ class LoginHandler { ...@@ -174,7 +167,15 @@ class LoginHandler {
private function getAfterLoginRedirect(): string { private function getAfterLoginRedirect(): string {
$autoJoinStep = $this->checkAutoJoin();
if ($autoJoinStep !== null) {
return $autoJoinStep;
}
$session = $this->locator->getSession(); $session = $this->locator->getSession();
$this->saveRejectedJoinIfPossible();
$this->locator->getAuditLogger()->info("LOGIN," . $session->getLoginIdentityType() . "," . $session->getUser()->id); $this->locator->getAuditLogger()->info("LOGIN," . $session->getLoginIdentityType() . "," . $session->getUser()->id);
if ($session->getOAuth2RequestData() !== null) { if ($session->getOAuth2RequestData() !== null) {
...@@ -193,4 +194,18 @@ class LoginHandler { ...@@ -193,4 +194,18 @@ class LoginHandler {
throw new \Exception("Unable to find a proper redirect"); throw new \Exception("Unable to find a proper redirect");
} }
private function saveRejectedJoinIfPossible(): void {
$session = $this->locator->getSession();
if ($session->isJoinRejected() && $session->getUserToJoin() !== null) {
$id1 = $session->getUser()->id;
$id2 = $session->getUserToJoin()->id;
if ($id1 !== null && $id2 !== null) {
$this->locator->getUserDAO()->insertRejectedJoin($id1, $id2);
$session->setJoinRejected(false);
}
}
}
} }
...@@ -99,10 +99,16 @@ final class LoginFlowTest extends TestCase { ...@@ -99,10 +99,16 @@ final class LoginFlowTest extends TestCase {
public function testNewIdentityAutojoin(): void { public function testNewIdentityAutojoin(): void {
$this->oAuth2RequestHandler->method('getRedirectResponseUrl')->willReturn('http://redirect-url'); $this->oAuth2RequestHandler->method('getRedirectResponseUrl')->willReturn('http://redirect-url');
$this->sessionData->setOAuth2RequestData(new \RAP\OAuth2RequestData());
$this->userDaoStub->method('findJoinableUsersByEmail')->willReturn(['1', '2']); $this->userDaoStub->method('findJoinableUsersByEmail')->willReturn(['1', '2']);
$this->userDaoStub->method('findUserById')->willReturn($this->getFakeUser1());
$this->userDaoStub->method('findUserById')->will($this->returnValueMap([
['1', $this->getFakeUser1()],
['2', $this->getFakeUser2()]
]));
// Login: two joinable users detected
$redirect1 = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity3()); $redirect1 = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity3());
$this->assertTrue($this->sessionData->isAutojoin()); $this->assertTrue($this->sessionData->isAutojoin());
...@@ -110,8 +116,9 @@ final class LoginFlowTest extends TestCase { ...@@ -110,8 +116,9 @@ final class LoginFlowTest extends TestCase {
$this->assertNotNull($this->sessionData->getUserToJoin()); $this->assertNotNull($this->sessionData->getUserToJoin());
$this->assertNull($this->sessionData->getUser()->id); $this->assertNull($this->sessionData->getUser()->id);
$this->userDaoStub->method('findJoinableUsersByUserId')->willReturn(['2']); $this->userDaoStub->method('findJoinableUsersByUserId')->will($this->onConsecutiveCalls(['2'], []));
// First confirm join
$redirect2 = $this->loginHandler->confirmJoin(); $redirect2 = $this->loginHandler->confirmJoin();
$this->assertEquals('1', $this->sessionData->getUser()->id); $this->assertEquals('1', $this->sessionData->getUser()->id);
...@@ -122,6 +129,7 @@ final class LoginFlowTest extends TestCase { ...@@ -122,6 +129,7 @@ final class LoginFlowTest extends TestCase {
$this->gmsClientStub->expects($this->once()) $this->gmsClientStub->expects($this->once())
->method('joinGroups')->with($this->anything()); ->method('joinGroups')->with($this->anything());
// Second confirm join, then redirect to caller application
$redirect3 = $this->loginHandler->confirmJoin(); $redirect3 = $this->loginHandler->confirmJoin();
$this->assertEquals('2', $this->sessionData->getUser()->id); $this->assertEquals('2', $this->sessionData->getUser()->id);
...@@ -141,6 +149,129 @@ final class LoginFlowTest extends TestCase { ...@@ -141,6 +149,129 @@ final class LoginFlowTest extends TestCase {
$this->assertEquals('http://rap-ia2/account', $redirect); $this->assertEquals('http://rap-ia2/account', $redirect);
} }
public function testRejectJoinExistingUser(): void {
$this->sessionData->setAction('account');
$this->userDaoStub->method('findUserByIdentity')->willReturn($this->getFakeUser1());
$this->userDaoStub->method('findUserById')->willReturn($this->getFakeUser2());
$this->userDaoStub->method('findJoinableUsersByUserId')->will($this->onConsecutiveCalls(['2'], []));
$redirect1 = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity1());
$this->assertTrue($this->sessionData->isAutojoin());
$this->assertEquals('http://rap-ia2/confirm-join', $redirect1);
$this->userDaoStub->expects($this->once())->method('insertRejectedJoin');
// User rejects join, redirect to account page
$redirect2 = $this->loginHandler->rejectJoin();
$this->assertEquals('http://rap-ia2/account', $redirect2);
}
public function testRejectJoinNewUser(): void {
$this->sessionData->setAction('account');
$this->userDaoStub->method('findJoinableUsersByEmail')->willReturn(['1']);
$this->userDaoStub->method('findUserById')->willReturn($this->getFakeUser1());
// Login: one joinable user detected
$redirect1 = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity3());
$this->assertTrue($this->sessionData->isAutojoin());
$this->assertEquals('http://rap-ia2/confirm-join', $redirect1);
// User rejects join, redirect to TOU check
$redirect2 = $this->loginHandler->rejectJoin();
$this->assertTrue($this->sessionData->isJoinRejected());
$this->assertEquals('http://rap-ia2/tou-check', $redirect2);
$this->userDaoStub->method('createUser')->willReturn('5');
$this->userDaoStub->expects($this->once())->method('insertRejectedJoin');
// User accepts TOU
$redirect3 = $this->loginHandler->register();
$this->assertEquals('http://rap-ia2/account', $redirect3);
}
public function testExplicitJoin(): void {
// First login result
$this->sessionData->setUser($this->getFakeUser2());
$this->sessionData->setAction('join');
$this->userDaoStub->method('findUserById')->willReturn($this->getFakeUser1());
// Second login
$redirect1 = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity1());
$this->assertFalse($this->sessionData->isAutojoin());
$this->assertEquals('http://rap-ia2/confirm-join', $redirect1);
// User confirms the join
$redirect2 = $this->loginHandler->confirmJoin();
$this->assertEquals('http://rap-ia2/account', $redirect2);
}
public function testExplicitJoinAndAutojoin(): void {
// First login result
$this->sessionData->setUser($this->getFakeUser2());
$this->sessionData->setAction('join');
$this->userDaoStub->method('findUserById')->willReturn($this->getFakeUser1());
$this->userDaoStub->method('findJoinableUsersByUserId')->will($this->onConsecutiveCalls(['2'], []));
// Second login
$redirect1 = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity1());
$this->assertFalse($this->sessionData->isAutojoin());
$this->assertEquals('http://rap-ia2/confirm-join', $redirect1);
// User confirms the join, another join is detected
$redirect2 = $this->loginHandler->confirmJoin();
$this->assertTrue($this->sessionData->isAutojoin());
$this->assertEquals('http://rap-ia2/confirm-join', $redirect2);
// User confirm the second join too
$redirect3 = $this->loginHandler->confirmJoin();
$this->assertEquals('http://rap-ia2/account', $redirect3);
}
public function testExplicitJoinAndRejectedAutojoin(): void {
// First login result
$this->sessionData->setUser($this->getFakeUser2());
$this->sessionData->setAction('join');
$this->userDaoStub->method('findUserById')->willReturn($this->getFakeUser1());
$this->userDaoStub->method('findJoinableUsersByUserId')->will($this->onConsecutiveCalls(['2'], []));
// Second login
$redirect1 = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity1());
$this->assertFalse($this->sessionData->isAutojoin());
$this->assertEquals('http://rap-ia2/confirm-join', $redirect1);
// User confirms the join, another join is detected
$redirect2 = $this->loginHandler->confirmJoin();
$this->assertTrue($this->sessionData->isAutojoin());
$this->assertEquals('http://rap-ia2/confirm-join', $redirect2);
$this->userDaoStub->expects($this->once())->method('insertRejectedJoin');
// User reject the second join
$redirect3 = $this->loginHandler->rejectJoin();
$this->assertEquals('http://rap-ia2/account', $redirect3);
}
private function getFakeUser1(): \RAP\User { private function getFakeUser1(): \RAP\User {
$user = new \RAP\User(); $user = new \RAP\User();
......
...@@ -12,7 +12,6 @@ final class LoginHandlerTest extends TestCase { ...@@ -12,7 +12,6 @@ final class LoginHandlerTest extends TestCase {
private $userDaoStub; private $userDaoStub;
private $sessionStub; private $sessionStub;
private $userHandlerStub; private $userHandlerStub;
private $oAuth2RequestHandler;
private $auditLogger; private $auditLogger;
private $loginHandler; private $loginHandler;
...@@ -29,9 +28,6 @@ final class LoginHandlerTest extends TestCase { ...@@ -29,9 +28,6 @@ final class LoginHandlerTest extends TestCase {
$this->userHandlerStub = $this->createMock(\RAP\UserHandler::class); $this->userHandlerStub = $this->createMock(\RAP\UserHandler::class);
$this->locatorStub->method('getUserHandler')->willReturn($this->userHandlerStub); $this->locatorStub->method('getUserHandler')->willReturn($this->userHandlerStub);
$this->oAuth2RequestHandler = $this->createMock(\RAP\OAuth2RequestHandler::class);
$this->locatorStub->method('getOAuth2RequestHandler')->willReturn($this->oAuth2RequestHandler);
$this->auditLogger = $this->createMock(\Monolog\Logger::class); $this->auditLogger = $this->createMock(\Monolog\Logger::class);
$this->locatorStub->method('getAuditLogger')->willReturn($this->auditLogger); $this->locatorStub->method('getAuditLogger')->willReturn($this->auditLogger);
...@@ -44,14 +40,13 @@ final class LoginHandlerTest extends TestCase { ...@@ -44,14 +40,13 @@ final class LoginHandlerTest extends TestCase {
$this->userDaoStub->method('findUserByIdentity')->willReturn($user); $this->userDaoStub->method('findUserByIdentity')->willReturn($user);
$this->oAuth2RequestHandler->method('getRedirectResponseUrl')->willReturn('http://redirect-url'); $this->sessionStub->method('getAction')->willReturn('account');
$this->sessionStub->method('getOAuth2RequestData')->willReturn(new \RAP\OAuth2RequestData());
$this->sessionStub->method('getUser')->willReturn($user); $this->sessionStub->method('getUser')->willReturn($user);
$redirect = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity1()); $redirect = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity1());
$this->assertEquals('http://redirect-url', $redirect); $this->assertEquals('http://rap-ia2/account', $redirect);
} }
public function testShowConfirmJoinNewIdentity(): void { public function testShowConfirmJoinNewIdentity(): void {
...@@ -85,6 +80,21 @@ final class LoginHandlerTest extends TestCase { ...@@ -85,6 +80,21 @@ final class LoginHandlerTest extends TestCase {
$this->assertEquals('http://rap-ia2/confirm-join', $redirect); $this->assertEquals('http://rap-ia2/confirm-join', $redirect);
} }
public function testRegisterFailWithoutSession(): void {
$this->expectException(\RAP\BadRequestException::class);
$this->loginHandler->register();
}
public function testConfirmJoinFailWithoutSession(): void {
$this->expectException(\RAP\BadRequestException::class);
$this->loginHandler->confirmJoin();
}
public function testRejectJoinFailWithoutSession(): void {
$this->expectException(\RAP\BadRequestException::class);
$this->loginHandler->rejectJoin();
}
private function getFakeUser(): \RAP\User { private function getFakeUser(): \RAP\User {
$user = new \RAP\User(); $user = new \RAP\User();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment