Commit 9f6a4bd6 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Implemented rejected join persistence

parent 6f493c2f
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -83,4 +83,6 @@ interface UserDAO {
    function findJoinableUsersByEmail(string $email): array;

    function findJoinableUsersByUserId(string $userId): array;

    function insertRejectedJoin(string $userId1, string $userId2): void;
}
+18 −4
Original line number Diff line number Diff line
@@ -351,4 +351,18 @@ class MySQLUserDAO extends BaseMySQLDAO implements UserDAO {
        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();
    }

}
+27 −12
Original line number Diff line number Diff line
@@ -78,11 +78,6 @@ class LoginHandler {

        $this->joinUsers();

        $autoJoinStep = $this->checkAutoJoin();
        if ($autoJoinStep !== null) {
            return $autoJoinStep;
        }

        return $this->getAfterLoginRedirect();
    }

@@ -105,6 +100,7 @@ class LoginHandler {
            return $this->showConfirmJoin($userToJoin);
        }

        $session->setAutojoin(false);
        return null;
    }

@@ -120,8 +116,9 @@ class LoginHandler {
        $session->setJoinRejected(true);

        if ($session->getUser()->id === null) {
            return $this->redirectToTOUCheck($session->getUser()->identities[0]);
            return $this->redirectToTOUCheck();
        } else {
            $this->saveRejectedJoinIfPossible();
            return $this->getAfterLoginRedirect();
        }
    }
@@ -158,12 +155,8 @@ class LoginHandler {
        $user = $session->getUser();
        $userToJoin = $session->getUserToJoin();

        if ($user === null) {
            $session->setUser($userToJoin);
        } else {
        $joinedUser = $this->locator->getUserHandler()->joinUsers($userToJoin, $user);
        $session->setUser($joinedUser);
        }

        if ($session->getAction() === 'join') {
            $session->setAction('account');
@@ -174,7 +167,15 @@ class LoginHandler {

    private function getAfterLoginRedirect(): string {

        $autoJoinStep = $this->checkAutoJoin();
        if ($autoJoinStep !== null) {
            return $autoJoinStep;
        }

        $session = $this->locator->getSession();

        $this->saveRejectedJoinIfPossible();

        $this->locator->getAuditLogger()->info("LOGIN," . $session->getLoginIdentityType() . "," . $session->getUser()->id);

        if ($session->getOAuth2RequestData() !== null) {
@@ -193,4 +194,18 @@ class LoginHandler {
        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);
            }
        }
    }

}
+150 −19
Original line number Diff line number Diff line
@@ -99,10 +99,16 @@ final class LoginFlowTest extends TestCase {
    public function testNewIdentityAutojoin(): void {

        $this->oAuth2RequestHandler->method('getRedirectResponseUrl')->willReturn('http://redirect-url');
        $this->sessionData->setOAuth2RequestData(new \RAP\OAuth2RequestData());

        $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());

        $this->assertTrue($this->sessionData->isAutojoin());
@@ -110,8 +116,9 @@ final class LoginFlowTest extends TestCase {
        $this->assertNotNull($this->sessionData->getUserToJoin());
        $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();

        $this->assertEquals('1', $this->sessionData->getUser()->id);
@@ -122,6 +129,7 @@ final class LoginFlowTest extends TestCase {
        $this->gmsClientStub->expects($this->once())
                ->method('joinGroups')->with($this->anything());

        // Second confirm join, then redirect to caller application
        $redirect3 = $this->loginHandler->confirmJoin();

        $this->assertEquals('2', $this->sessionData->getUser()->id);
@@ -141,6 +149,129 @@ final class LoginFlowTest extends TestCase {
        $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 {

        $user = new \RAP\User();
+17 −7
Original line number Diff line number Diff line
@@ -12,7 +12,6 @@ final class LoginHandlerTest extends TestCase {
    private $userDaoStub;
    private $sessionStub;
    private $userHandlerStub;
    private $oAuth2RequestHandler;
    private $auditLogger;
    private $loginHandler;

@@ -29,9 +28,6 @@ final class LoginHandlerTest extends TestCase {
        $this->userHandlerStub = $this->createMock(\RAP\UserHandler::class);
        $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->locatorStub->method('getAuditLogger')->willReturn($this->auditLogger);

@@ -44,14 +40,13 @@ final class LoginHandlerTest extends TestCase {

        $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);

        $redirect = $this->loginHandler->onIdentityDataReceived($this->getFakeIdentity1());

        $this->assertEquals('http://redirect-url', $redirect);
        $this->assertEquals('http://rap-ia2/account', $redirect);
    }

    public function testShowConfirmJoinNewIdentity(): void {
@@ -85,6 +80,21 @@ final class LoginHandlerTest extends TestCase {
        $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 {

        $user = new \RAP\User();