summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorJoas Schilling <213943+nickvergessen@users.noreply.github.com>2022-08-12 16:07:52 +0200
committerGitHub <noreply@github.com>2022-08-12 16:07:52 +0200
commit91d3bd8df8a5288c2abb3badde00c248d974dae8 (patch)
treec90b1ec7d0600f7119959532167c5fbd1f2b0b8f /tests
parentb6c2ad7feef446b992d087d84f0c5101a6ef5000 (diff)
parentad8134738219349269fc4d7191b2a1a205178ca9 (diff)
Merge pull request #7472 from nextcloud/jwt-auth
Implement JWT auth for signaling connections (hello v2)
Diffstat (limited to 'tests')
-rw-r--r--tests/php/CapabilitiesTest.php17
-rw-r--r--tests/php/ConfigTest.php214
-rw-r--r--tests/php/Controller/SignalingControllerTest.php25
-rw-r--r--tests/php/Signaling/BackendNotifierTest.php3
4 files changed, 197 insertions, 62 deletions
diff --git a/tests/php/CapabilitiesTest.php b/tests/php/CapabilitiesTest.php
index 39017081b..3c050c089 100644
--- a/tests/php/CapabilitiesTest.php
+++ b/tests/php/CapabilitiesTest.php
@@ -316,4 +316,21 @@ class CapabilitiesTest extends TestCase {
$this->assertInstanceOf(IPublicCapability::class, $capabilities);
$this->assertSame([], $capabilities->getCapabilities());
}
+
+ public function testCapabilitiesHelloV2Key(): void {
+ $capabilities = new Capabilities(
+ $this->serverConfig,
+ $this->talkConfig,
+ $this->commentsManager,
+ $this->userSession,
+ $this->appManager
+ );
+
+ $this->talkConfig->expects($this->once())
+ ->method('getSignalingTokenPublicKey')
+ ->willReturn('this-is-the-key');
+
+ $data = $capabilities->getCapabilities();
+ $this->assertEquals('this-is-the-key', $data['spreed']['config']['signaling']['hello-v2-token-key']);
+ }
}
diff --git a/tests/php/ConfigTest.php b/tests/php/ConfigTest.php
index 80fed760e..569d89177 100644
--- a/tests/php/ConfigTest.php
+++ b/tests/php/ConfigTest.php
@@ -20,6 +20,9 @@
*/
namespace OCA\Talk\Tests\php;
+use Firebase\JWT\JWT;
+use Firebase\JWT\Key;
+
use OCA\Talk\Config;
use OCA\Talk\Events\GetTurnServersEvent;
use OCA\Talk\Tests\php\Mocks\GetTurnServerListener;
@@ -27,25 +30,38 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IGroupManager;
+use OCP\IURLGenerator;
+use OCP\IUser;
+use OCP\IUserManager;
use OCP\Security\ISecureRandom;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;
class ConfigTest extends TestCase {
- public function testGetStunServers() {
- $servers = [
- 'stun1.example.com:443',
- 'stun2.example.com:129',
- ];
-
+ private function createConfig(IConfig $config) {
/** @var MockObject|ITimeFactory $timeFactory */
$timeFactory = $this->createMock(ITimeFactory::class);
/** @var MockObject|ISecureRandom $secureRandom */
$secureRandom = $this->createMock(ISecureRandom::class);
- /** @var MockObject|IGroupManager $secureRandom */
+ /** @var MockObject|IGroupManager $groupManager */
$groupManager = $this->createMock(IGroupManager::class);
+ /** @var MockObject|IUserManager $userManager */
+ $userManager = $this->createMock(IUserManager::class);
+ /** @var MockObject|IURLGenerator $urlGenerator */
+ $urlGenerator = $this->createMock(IURLGenerator::class);
/** @var MockObject|IEventDispatcher $dispatcher */
$dispatcher = $this->createMock(IEventDispatcher::class);
+
+ $helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
+ return $helper;
+ }
+
+ public function testGetStunServers() {
+ $servers = [
+ 'stun1.example.com:443',
+ 'stun2.example.com:129',
+ ];
+
/** @var MockObject|IConfig $config */
$config = $this->createMock(IConfig::class);
$config
@@ -59,19 +75,11 @@ class ConfigTest extends TestCase {
->with('has_internet_connection', true)
->willReturn(true);
- $helper = new Config($config, $secureRandom, $groupManager, $timeFactory, $dispatcher);
+ $helper = $this->createConfig($config);
$this->assertSame($helper->getStunServers(), $servers);
}
public function testGetDefaultStunServer() {
- /** @var MockObject|ITimeFactory $timeFactory */
- $timeFactory = $this->createMock(ITimeFactory::class);
- /** @var MockObject|ISecureRandom $secureRandom */
- $secureRandom = $this->createMock(ISecureRandom::class);
- /** @var MockObject|IGroupManager $secureRandom */
- $groupManager = $this->createMock(IGroupManager::class);
- /** @var MockObject|IEventDispatcher $dispatcher */
- $dispatcher = $this->createMock(IEventDispatcher::class);
/** @var MockObject|IConfig $config */
$config = $this->createMock(IConfig::class);
$config
@@ -85,19 +93,11 @@ class ConfigTest extends TestCase {
->with('has_internet_connection', true)
->willReturn(true);
- $helper = new Config($config, $secureRandom, $groupManager, $timeFactory, $dispatcher);
+ $helper = $this->createConfig($config);
$this->assertSame(['stun.nextcloud.com:443'], $helper->getStunServers());
}
public function testGetDefaultStunServerNoInternet() {
- /** @var MockObject|ITimeFactory $timeFactory */
- $timeFactory = $this->createMock(ITimeFactory::class);
- /** @var MockObject|ISecureRandom $secureRandom */
- $secureRandom = $this->createMock(ISecureRandom::class);
- /** @var MockObject|IGroupManager $secureRandom */
- $groupManager = $this->createMock(IGroupManager::class);
- /** @var MockObject|IEventDispatcher $dispatcher */
- $dispatcher = $this->createMock(IEventDispatcher::class);
/** @var MockObject|IConfig $config */
$config = $this->createMock(IConfig::class);
$config
@@ -111,7 +111,7 @@ class ConfigTest extends TestCase {
->with('has_internet_connection', true)
->willReturn(false);
- $helper = new Config($config, $secureRandom, $groupManager, $timeFactory, $dispatcher);
+ $helper = $this->createConfig($config);
$this->assertSame([], $helper->getStunServers());
}
@@ -151,8 +151,12 @@ class ConfigTest extends TestCase {
->method('getTime')
->willReturn(1479743025);
- /** @var MockObject|IGroupManager $secureRandom */
+ /** @var MockObject|IGroupManager $groupManager */
$groupManager = $this->createMock(IGroupManager::class);
+ /** @var MockObject|IUserManager $userManager */
+ $userManager = $this->createMock(IUserManager::class);
+ /** @var MockObject|IURLGenerator $urlGenerator */
+ $urlGenerator = $this->createMock(IURLGenerator::class);
/** @var MockObject|IEventDispatcher $dispatcher */
$dispatcher = $this->createMock(IEventDispatcher::class);
@@ -163,7 +167,7 @@ class ConfigTest extends TestCase {
->method('generate')
->with(16)
->willReturn('abcdefghijklmnop');
- $helper = new Config($config, $secureRandom, $groupManager, $timeFactory, $dispatcher);
+ $helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
//
$settings = $helper->getTurnSettings();
@@ -200,19 +204,7 @@ class ConfigTest extends TestCase {
->with('spreed', 'turn_servers', '')
->willReturn(json_encode([]));
- /** @var MockObject|ITimeFactory $timeFactory */
- $timeFactory = $this->createMock(ITimeFactory::class);
-
- /** @var MockObject|IGroupManager $secureRandom */
- $groupManager = $this->createMock(IGroupManager::class);
-
- /** @var MockObject|ISecureRandom $secureRandom */
- $secureRandom = $this->createMock(ISecureRandom::class);
-
- /** @var MockObject|IEventDispatcher $dispatcher */
- $dispatcher = $this->createMock(IEventDispatcher::class);
-
- $helper = new Config($config, $secureRandom, $groupManager, $timeFactory, $dispatcher);
+ $helper = $this->createConfig($config);
$settings = $helper->getTurnSettings();
$this->assertEquals(0, count($settings));
@@ -230,9 +222,15 @@ class ConfigTest extends TestCase {
/** @var MockObject|ITimeFactory $timeFactory */
$timeFactory = $this->createMock(ITimeFactory::class);
- /** @var MockObject|IGroupManager $secureRandom */
+ /** @var MockObject|IGroupManager $groupManager */
$groupManager = $this->createMock(IGroupManager::class);
+ /** @var MockObject|IUserManager $userManager */
+ $userManager = $this->createMock(IUserManager::class);
+
+ /** @var MockObject|IURLGenerator $urlGenerator */
+ $urlGenerator = $this->createMock(IURLGenerator::class);
+
/** @var MockObject|ISecureRandom $secureRandom */
$secureRandom = $this->createMock(ISecureRandom::class);
@@ -258,7 +256,7 @@ class ConfigTest extends TestCase {
$dispatcher->addServiceListener(GetTurnServersEvent::class, GetTurnServerListener::class);
- $helper = new Config($config, $secureRandom, $groupManager, $timeFactory, $dispatcher);
+ $helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
$settings = $helper->getTurnSettings();
$this->assertSame($servers, $settings);
@@ -326,22 +324,136 @@ class ConfigTest extends TestCase {
* @param string $expectedWebSocketDomain
*/
public function testGetWebSocketDomainForSignalingServer($url, $expectedWebSocketDomain) {
+ /** @var MockObject|IConfig $config */
+ $config = $this->createMock(IConfig::class);
+
+ $helper = $this->createConfig($config);
+
+ $this->assertEquals(
+ $expectedWebSocketDomain,
+ self::invokePrivate($helper, 'getWebSocketDomainForSignalingServer', [$url])
+ );
+ }
+
+ public function dataTicketV2Algorithm() {
+ return [
+ ['ES384'],
+ ['ES256'],
+ ['RS256'],
+ ['RS384'],
+ ['RS512'],
+ ['EdDSA'],
+ ];
+ }
+
+ /**
+ * @dataProvider dataTicketV2Algorithm
+ * @param string $algo
+ */
+ public function testSignalingTicketV2User(string $algo): void {
+ /** @var IConfig $config */
+ $config = \OC::$server->getConfig();
/** @var MockObject|ITimeFactory $timeFactory */
$timeFactory = $this->createMock(ITimeFactory::class);
/** @var MockObject|ISecureRandom $secureRandom */
$secureRandom = $this->createMock(ISecureRandom::class);
- /** @var MockObject|IGroupManager $secureRandom */
+ /** @var MockObject|IGroupManager $groupManager */
$groupManager = $this->createMock(IGroupManager::class);
+ /** @var MockObject|IUserManager $userManager */
+ $userManager = $this->createMock(IUserManager::class);
+ /** @var MockObject|IURLGenerator $urlGenerator */
+ $urlGenerator = $this->createMock(IURLGenerator::class);
/** @var MockObject|IEventDispatcher $dispatcher */
$dispatcher = $this->createMock(IEventDispatcher::class);
- /** @var MockObject|IConfig $config */
- $config = $this->createMock(IConfig::class);
+ /** @var MockObject|IUser $user */
+ $user = $this->createMock(IUser::class);
- $helper = new Config($config, $secureRandom, $groupManager, $timeFactory, $dispatcher);
+ $now = time();
+ $timeFactory
+ ->expects($this->once())
+ ->method('getTime')
+ ->willReturn($now);
+ $urlGenerator
+ ->expects($this->once())
+ ->method('getAbsoluteURL')
+ ->with('')
+ ->willReturn('https://domain.invalid/nextcloud');
+ $userManager
+ ->expects($this->once())
+ ->method('get')
+ ->with('user1')
+ ->willReturn($user);
+ $user
+ ->expects($this->once())
+ ->method('getUID')
+ ->willReturn('user1');
+ $user
+ ->expects($this->once())
+ ->method('getDisplayName')
+ ->willReturn('Jane Doe');
- $this->assertEquals(
- $expectedWebSocketDomain,
- self::invokePrivate($helper, 'getWebSocketDomainForSignalingServer', [$url])
- );
+ $helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
+
+ $config->setAppValue('spreed', 'signaling_token_alg', $algo);
+ // Make sure new keys are generated.
+ $config->deleteAppValue('spreed', 'signaling_token_privkey_' . strtolower($algo));
+ $config->deleteAppValue('spreed', 'signaling_token_pubkey_' . strtolower($algo));
+ $ticket = $helper->getSignalingTicket(Config::SIGNALING_TICKET_V2, 'user1');
+ $this->assertNotNull($ticket);
+
+ $key = new Key($config->getAppValue('spreed', 'signaling_token_pubkey_' . strtolower($algo)), $algo);
+ $decoded = JWT::decode($ticket, $key);
+
+ $this->assertEquals($now, $decoded->iat);
+ $this->assertEquals('https://domain.invalid/nextcloud', $decoded->iss);
+ $this->assertEquals('user1', $decoded->sub);
+ $this->assertSame(['displayname' => 'Jane Doe'], (array) $decoded->userdata);
+ }
+
+ /**
+ * @dataProvider dataTicketV2Algorithm
+ * @param string $algo
+ */
+ public function testSignalingTicketV2Anonymous(string $algo): void {
+ /** @var IConfig $config */
+ $config = \OC::$server->getConfig();
+ /** @var MockObject|ITimeFactory $timeFactory */
+ $timeFactory = $this->createMock(ITimeFactory::class);
+ /** @var MockObject|ISecureRandom $secureRandom */
+ $secureRandom = $this->createMock(ISecureRandom::class);
+ /** @var MockObject|IGroupManager $groupManager */
+ $groupManager = $this->createMock(IGroupManager::class);
+ /** @var MockObject|IUserManager $userManager */
+ $userManager = $this->createMock(IUserManager::class);
+ /** @var MockObject|IURLGenerator $urlGenerator */
+ $urlGenerator = $this->createMock(IURLGenerator::class);
+ /** @var MockObject|IEventDispatcher $dispatcher */
+ $dispatcher = $this->createMock(IEventDispatcher::class);
+
+ $now = time();
+ $timeFactory
+ ->expects($this->once())
+ ->method('getTime')
+ ->willReturn($now);
+ $urlGenerator
+ ->expects($this->once())
+ ->method('getAbsoluteURL')
+ ->with('')
+ ->willReturn('https://domain.invalid/nextcloud');
+
+ $helper = new Config($config, $secureRandom, $groupManager, $userManager, $urlGenerator, $timeFactory, $dispatcher);
+
+ $config->setAppValue('spreed', 'signaling_token_alg', $algo);
+ // Make sure new keys are generated.
+ $config->deleteAppValue('spreed', 'signaling_token_privkey_' . strtolower($algo));
+ $config->deleteAppValue('spreed', 'signaling_token_pubkey_' . strtolower($algo));
+ $ticket = $helper->getSignalingTicket(Config::SIGNALING_TICKET_V2, null);
+ $this->assertNotNull($ticket);
+
+ $key = new Key($config->getAppValue('spreed', 'signaling_token_pubkey_' . strtolower($algo)), $algo);
+ $decoded = JWT::decode($ticket, $key);
+
+ $this->assertEquals($now, $decoded->iat);
+ $this->assertEquals('https://domain.invalid/nextcloud', $decoded->iss);
}
}
diff --git a/tests/php/Controller/SignalingControllerTest.php b/tests/php/Controller/SignalingControllerTest.php
index 1b6329d26..e74cddd73 100644
--- a/tests/php/Controller/SignalingControllerTest.php
+++ b/tests/php/Controller/SignalingControllerTest.php
@@ -43,10 +43,12 @@ use OCP\App\IAppManager;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Http\Client\IClientService;
+use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\IRequest;
+use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Security\IHasher;
@@ -71,6 +73,7 @@ class CustomInputSignalingController extends SignalingController {
* @group DB
*/
class SignalingControllerTest extends TestCase {
+ private IConfig $serverConfig;
private ?Config $config = null;
/** @var TalkSession|MockObject */
private $session;
@@ -107,14 +110,16 @@ class SignalingControllerTest extends TestCase {
$this->secureRandom = \OC::$server->getSecureRandom();
$timeFactory = $this->createMock(ITimeFactory::class);
$groupManager = $this->createMock(IGroupManager::class);
- $config = \OC::$server->getConfig();
- $config->setAppValue('spreed', 'signaling_servers', json_encode([
+ $this->serverConfig = \OC::$server->getConfig();
+ $this->serverConfig->setAppValue('spreed', 'signaling_servers', json_encode([
'secret' => 'MySecretValue',
]));
- $config->setAppValue('spreed', 'signaling_ticket_secret', 'the-app-ticket-secret');
- $config->setUserValue($this->userId, 'spreed', 'signaling_ticket_secret', 'the-user-ticket-secret');
+ $this->serverConfig->setAppValue('spreed', 'signaling_ticket_secret', 'the-app-ticket-secret');
+ $this->serverConfig->setUserValue($this->userId, 'spreed', 'signaling_ticket_secret', 'the-user-ticket-secret');
+ $this->userManager = $this->createMock(IUserManager::class);
$this->dispatcher = \OC::$server->get(IEventDispatcher::class);
- $this->config = new Config($config, $this->secureRandom, $groupManager, $timeFactory, $this->dispatcher);
+ $urlGenerator = $this->createMock(IURLGenerator::class);
+ $this->config = new Config($this->serverConfig, $this->secureRandom, $groupManager, $this->userManager, $urlGenerator, $timeFactory, $this->dispatcher);
$this->session = $this->createMock(TalkSession::class);
$this->dbConnection = \OC::$server->getDatabaseConnection();
$this->signalingManager = $this->createMock(\OCA\Talk\Signaling\Manager::class);
@@ -122,7 +127,6 @@ class SignalingControllerTest extends TestCase {
$this->participantService = $this->createMock(ParticipantService::class);
$this->sessionService = $this->createMock(SessionService::class);
$this->messages = $this->createMock(Messages::class);
- $this->userManager = $this->createMock(IUserManager::class);
$this->timeFactory = $this->createMock(ITimeFactory::class);
$this->clientService = $this->createMock(IClientService::class);
$this->logger = $this->createMock(LoggerInterface::class);
@@ -133,6 +137,7 @@ class SignalingControllerTest extends TestCase {
$this->controller = new CustomInputSignalingController(
'spreed',
$this->createMock(IRequest::class),
+ $this->serverConfig,
$this->config,
$this->signalingManager,
$this->session,
@@ -273,7 +278,7 @@ class SignalingControllerTest extends TestCase {
'auth' => [
'params' => [
'userid' => 'invalid-userid',
- 'ticket' => $this->config->getSignalingTicket($this->userId),
+ 'ticket' => $this->config->getSignalingTicket(Config::SIGNALING_TICKET_V1, $this->userId),
],
],
]);
@@ -291,7 +296,7 @@ class SignalingControllerTest extends TestCase {
'auth' => [
'params' => [
'userid' => 'unknown-userid',
- 'ticket' => $this->config->getSignalingTicket('unknown-userid'),
+ 'ticket' => $this->config->getSignalingTicket(Config::SIGNALING_TICKET_V1, 'unknown-userid'),
],
],
]);
@@ -320,7 +325,7 @@ class SignalingControllerTest extends TestCase {
'auth' => [
'params' => [
'userid' => $this->userId,
- 'ticket' => $this->config->getSignalingTicket($this->userId),
+ 'ticket' => $this->config->getSignalingTicket(Config::SIGNALING_TICKET_V1, $this->userId),
],
],
]);
@@ -341,7 +346,7 @@ class SignalingControllerTest extends TestCase {
'auth' => [
'params' => [
'userid' => '',
- 'ticket' => $this->config->getSignalingTicket(''),
+ 'ticket' => $this->config->getSignalingTicket(Config::SIGNALING_TICKET_V1, ''),
],
],
]);
diff --git a/tests/php/Signaling/BackendNotifierTest.php b/tests/php/Signaling/BackendNotifierTest.php
index 4f82ff5e4..cce3251c8 100644
--- a/tests/php/Signaling/BackendNotifierTest.php
+++ b/tests/php/Signaling/BackendNotifierTest.php
@@ -113,6 +113,7 @@ class BackendNotifierTest extends TestCase {
$this->timeFactory = $this->createMock(ITimeFactory::class);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$groupManager = $this->createMock(IGroupManager::class);
+ $userManager = $this->createMock(IUserManager::class);
$config = \OC::$server->getConfig();
$this->signalingSecret = 'the-signaling-secret';
$this->baseUrl = 'https://localhost/signaling';
@@ -132,7 +133,7 @@ class BackendNotifierTest extends TestCase {
->willReturn(['server' => $this->baseUrl]);
$this->dispatcher = \OC::$server->get(IEventDispatcher::class);
- $this->config = new Config($config, $this->secureRandom, $groupManager, $this->timeFactory, $this->dispatcher);
+ $this->config = new Config($config, $this->secureRandom, $groupManager, $userManager, $this->urlGenerator, $this->timeFactory, $this->dispatcher);
$this->recreateBackendNotifier();
$this->overwriteService(BackendNotifier::class, $this->controller);