diff --git a/CHANGELOG.md b/CHANGELOG.md index d7ceef9c..a46e2d86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Get GroupTypeRoles ([PR197](https://github.com/5pm-HDH/churchtools-api/pull/197)) - PHP coding standard ([PR193](https://github.com/5pm-HDH/churchtools-api/pull/193)) - Added new property 'postsEnabled' to the group type model ([PR204](https://github.com/5pm-HDH/churchtools-api/pull/204)) +- Login with Session Cookie ([PR207](https://github.com/5pm-HDH/churchtools-api/pull/207)) ### Changed diff --git a/src/CTConfig.php b/src/CTConfig.php index 14c97bd4..63e075ea 100644 --- a/src/CTConfig.php +++ b/src/CTConfig.php @@ -10,6 +10,7 @@ use CTApi\Models\Groups\Person\PersonRequest; use CTApi\Utils\CTUtil; use GuzzleHttp\Cookie\CookieJar; +use GuzzleHttp\Cookie\SetCookie; use GuzzleHttp\HandlerStack; use GuzzleHttp\TransferStats; use Kevinrob\GuzzleCache\CacheMiddleware; @@ -133,6 +134,11 @@ public static function authWithLoginToken(string $loginToken): Auth return AuthRequest::authWithLoginToken($loginToken); } + public static function authWithSessionCookie(string $cookieString): Auth + { + return AuthRequest::authWithSessionCookie($cookieString); + } + /** * Auth via undocumented ajax-API. Use authWithLoginToken() instead. * @param string $userId @@ -153,7 +159,19 @@ public static function getSessionCookie(): ?array if (empty($cookieData)) { return null; } - return end($cookieData); + return array_pop($cookieData); + } + + public static function getSessionCookieString(): ?string + { + $cookieData = self::getSessionCookie(); + return $cookieData ? (string) (new SetCookie($cookieData)) : null; + } + + public static function setSessionCookie(string $cookieString): void + { + $cookie = SetCookie::fromString($cookieString); + self::getConfig()->cookieJar->setCookie($cookie); } /** diff --git a/src/Models/Common/Auth/AuthRequest.php b/src/Models/Common/Auth/AuthRequest.php index 665e59bb..36858b6d 100644 --- a/src/Models/Common/Auth/AuthRequest.php +++ b/src/Models/Common/Auth/AuthRequest.php @@ -18,6 +18,12 @@ public static function authWithLoginToken(string $loginToken): Auth return (new AuthRequestBuilder())->authWithLoginToken($loginToken); } + public static function authWithSessionCookie(string $sessionCookie): Auth + { + CTLog::getLog()->info('AuthRequest: Authenticate CTConfig with Session'); + return (new AuthRequestBuilder())->authWithSessionCookie($sessionCookie); + } + public static function authWithUserIdAndLoginToken(string $userId, string $loginToken): bool { CTLog::getLog()->info('AuthRequest: Authenticate CTConfig with UserId and Token.'); diff --git a/src/Models/Common/Auth/AuthRequestBuilder.php b/src/Models/Common/Auth/AuthRequestBuilder.php index d904fe7a..00d02f9c 100644 --- a/src/Models/Common/Auth/AuthRequestBuilder.php +++ b/src/Models/Common/Auth/AuthRequestBuilder.php @@ -7,6 +7,7 @@ use CTApi\Exceptions\CTRequestException; use CTApi\Models\Groups\Person\Person; use CTApi\Utils\CTResponseUtil; +use GuzzleHttp\Cookie\SetCookie; class AuthRequestBuilder { @@ -71,6 +72,29 @@ public function authWithLoginToken(string $loginToken): Auth throw new CTAuthException("Authentication was not successfull."); } + public function authWithSessionCookie(string $cookieString): Auth + { + $client = CTClient::getClient(); + $cookie = SetCookie::fromString($cookieString); + + try { + $response = $client->get('/api/whoami', [ + 'headers' => [ + 'cookie' => $cookie->getName() . '=' . $cookie->getValue(), + ], + ]); + $data = CTResponseUtil::dataAsArray($response); + $person = Person::createModelFromData($data); + } catch (CTRequestException $exception) { + throw new CTAuthException("Authentication was not successfull: " . $exception->getMessage(), $exception->getCode(), $exception); + } + + if ($person->getId() != null && $person->getId() != -1 && $person->getId() != "-1") { + return new Auth($person->getId(), false); + } + throw new CTAuthException("Authentication was not successfull."); + } + public function authWithUserIdAndLoginToken(string $userId, string $loginToken): bool { $client = CTClient::getClient(); diff --git a/tests/Integration/Requests/AuthRequestTest.php b/tests/Integration/Requests/AuthRequestTest.php index 768655b4..8780c517 100644 --- a/tests/Integration/Requests/AuthRequestTest.php +++ b/tests/Integration/Requests/AuthRequestTest.php @@ -28,6 +28,40 @@ public function testAuthWithEmailAndPassword(): void $this->assertNotNull($cookie); } + public function testAuthWithSessionCookie(): void + { + $auth = IntegrationTestData::get()->authenticateUser(); + $userId = $auth->userId; + $this->assertNotNull($userId); + + $cookie = CTConfig::getSessionCookieString(); + $this->assertNotNull($cookie); + + // clear config + CTConfig::clearCookies(); + + // verify that we are not logged in now + CTConfig::setApiUrl(IntegrationTestData::get()->getApiUrl()); + $this->assertFalse(CTConfig::validateAuthentication()); + + // clear again + CTConfig::clearCookies(); + + // login using the cookie + $auth = CTConfig::authWithSessionCookie($cookie); + $this->assertEquals($userId, $auth->userId); + $this->assertTrue(CTConfig::validateAuthentication()); + + // confirm we are still logged in + $authValid = CTConfig::validateAuthentication(); + $this->assertTrue($authValid); + + // confirm the session cookie was updated (but not replaced) + $updatedCookie = CTConfig::getSessionCookieString(); + $this->assertNotNull($updatedCookie); + $this->assertSame(explode(';', $cookie, 2)[0], explode(';', $updatedCookie, 2)[0]); + } + public function testAuthWithUserIdAndLoginToken() { $auth = IntegrationTestData::get()->authenticateUser();