1
0
Fork 0
mirror of https://github.com/wallabag/wallabag.git synced 2025-09-30 19:22:12 +00:00
wallabag/tests/Controller/Api/OAuthCodeTest.php
Srijith Nair 173b317ff4 Implement OAuth 2.1 with PKCE authorization code flow
- Add PKCE service with RFC 7636 compliance (S256 and plain methods)
  - Implement OAuth authorization controller with CSRF protection
  - Add comprehensive security testing (SQL injection, XSS, DoS protection)
  - Create 44+ tests across 6 test files with 100% pass rate
  - Implement public/confidential client support with PKCE enforcement
  - Maintain full backward compatibility with existing password grant flow
2025-09-06 07:35:45 +04:00

80 lines
2.8 KiB
PHP

<?php
namespace Tests\Wallabag\Controller\Api;
use Doctrine\ORM\EntityManagerInterface;
use Tests\Wallabag\WallabagTestCase;
use Wallabag\Entity\Api\AuthCode;
use Wallabag\Entity\Api\Client;
use Wallabag\Entity\User;
class OAuthCodeTest extends WallabagTestCase
{
public function testAuthCodeSingleUse()
{
$client = $this->getTestClient();
$apiClient = $this->createApiClientForUser('admin', ['authorization_code']);
$em = $client->getContainer()->get(EntityManagerInterface::class);
$user = $em->getRepository(User::class)->findOneByUsername('admin');
// Create auth code manually
$authCode = new AuthCode();
$authCode->setClient($apiClient);
$authCode->setUser($user);
$authCode->setToken(bin2hex(random_bytes(32)));
$authCode->setRedirectUri('http://example.com/callback');
$authCode->setExpiresAt(time() + 600);
$authCode->setScope('read');
$em->persist($authCode);
$em->flush();
// First use - should succeed
$client->request('POST', '/oauth/v2/token', [
'grant_type' => 'authorization_code',
'client_id' => $apiClient->getPublicId(),
'client_secret' => $apiClient->getSecret(),
'code' => $authCode->getToken(),
'redirect_uri' => 'http://example.com/callback',
]);
$this->assertSame(200, $client->getResponse()->getStatusCode());
$data = json_decode($client->getResponse()->getContent(), true);
$this->assertArrayHasKey('access_token', $data);
// Second use - should fail (code is single-use)
$client->request('POST', '/oauth/v2/token', [
'grant_type' => 'authorization_code',
'client_id' => $apiClient->getPublicId(),
'client_secret' => $apiClient->getSecret(),
'code' => $authCode->getToken(),
'redirect_uri' => 'http://example.com/callback',
]);
$this->assertSame(400, $client->getResponse()->getStatusCode());
$data = json_decode($client->getResponse()->getContent(), true);
$this->assertSame('invalid_grant', $data['error']);
}
private function createApiClientForUser($username, $grantTypes = ['password'])
{
$client = $this->getTestClient();
$em = $client->getContainer()->get(EntityManagerInterface::class);
$userManager = static::getContainer()->get('fos_user.user_manager');
$user = $userManager->findUserBy(['username' => $username]);
\assert($user instanceof User);
$apiClient = new Client($user);
$apiClient->setName('My app');
$apiClient->setAllowedGrantTypes($grantTypes);
$apiClient->setRedirectUris(['http://example.com/callback']);
$em->persist($apiClient);
$em->flush();
return $apiClient;
}
}