diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index a2c763a..1d39de6 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -2,7 +2,7 @@ name: test
on:
push:
- branches: [main, develop]
+ branches: [main, develop, fix-test-action]
pull_request:
branches: [main, develop]
@@ -14,9 +14,9 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-20.04]
- php: ["7.4"]
+ php: ["8.2"]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Create config files
run: |
diff --git a/config/app.php b/config/app.php
index 8faea7d..480c342 100644
--- a/config/app.php
+++ b/config/app.php
@@ -178,7 +178,6 @@ return [
*/
'Error' => [
'errorLevel' => E_ALL,
- 'exceptionRenderer' => ExceptionRenderer::class,
'skipLog' => [],
'log' => true,
'trace' => true,
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 403e1e5..ae814bc 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -20,6 +20,9 @@
./tests/TestCase/Api
+
+ ./tests/TestCase/Integration
+
diff --git a/plugins/Tags/src/View/Helper/TagHelper.php b/plugins/Tags/src/View/Helper/TagHelper.php
index 405c513..7cb1411 100644
--- a/plugins/Tags/src/View/Helper/TagHelper.php
+++ b/plugins/Tags/src/View/Helper/TagHelper.php
@@ -106,7 +106,7 @@ class TagHelper extends Helper
$deleteButton = $this->Bootstrap->button([
'size' => 'sm',
'icon' => 'times',
- 'class' => ['ms-1', 'border-0', "text-${textColour}"],
+ 'class' => ['ms-1', 'border-0', "text-$textColour"],
'variant' => 'text',
'title' => __('Delete tag'),
'onclick' => sprintf('deleteTag(\'%s\', \'%s\', this)',
diff --git a/src/Command/ImporterCommand.php b/src/Command/ImporterCommand.php
index dee4e24..02c4164 100644
--- a/src/Command/ImporterCommand.php
+++ b/src/Command/ImporterCommand.php
@@ -136,7 +136,7 @@ class ImporterCommand extends Command
$entity = null;
if (isset($item[$primary_key])) {
$query = $table->find('all')
- ->where(["${primary_key}" => $item[$primary_key]]);
+ ->where(["$primary_key" => $item[$primary_key]]);
$entity = $query->first();
}
if (is_null($entity)) {
diff --git a/src/Controller/Component/CRUDComponent.php b/src/Controller/Component/CRUDComponent.php
index 65dce89..5a69186 100644
--- a/src/Controller/Component/CRUDComponent.php
+++ b/src/Controller/Component/CRUDComponent.php
@@ -1489,7 +1489,7 @@ class CRUDComponent extends Component
{
$prefixedConditions = [];
foreach ($conditions as $condField => $condValue) {
- $prefixedConditions["${prefix}.${condField}"] = $condValue;
+ $prefixedConditions["$prefix.$condField"] = $condValue;
}
return $prefixedConditions;
}
@@ -1613,13 +1613,13 @@ class CRUDComponent extends Component
[sprintf('%s.id = %s.%s', $this->Table->getAlias(), $associatedTable->getAlias(), $association->getForeignKey())]
)
->where([
- ["${field} IS NOT" => NULL]
+ ["$field IS NOT" => NULL]
]);
} else if ($associationType == 'manyToOne') {
$fieldToExtract = sprintf('%s.%s', Inflector::singularize(strtolower($model)), $subField);
$query = $this->Table->find()->contain($model);
} else {
- throw new Exception("Association ${associationType} not supported in CRUD Component");
+ throw new Exception("Association $associationType not supported in CRUD Component");
}
} else {
$fieldToExtract = $field;
diff --git a/src/Controller/Component/RestResponseComponent.php b/src/Controller/Component/RestResponseComponent.php
index 8da9128..19a522b 100644
--- a/src/Controller/Component/RestResponseComponent.php
+++ b/src/Controller/Component/RestResponseComponent.php
@@ -390,7 +390,7 @@ class RestResponseComponent extends Component
return '[]';
}
- public function saveFailResponse($controller, $action, $id = false, $validationErrors, $format = false)
+ public function saveFailResponse($controller, $action, $id, $validationErrors, $format = false)
{
$this->autoRender = false;
$response = array();
diff --git a/tests/Fixture/BroodsFixture.php b/tests/Fixture/BroodsFixture.php
index c329e6a..7cc26a1 100644
--- a/tests/Fixture/BroodsFixture.php
+++ b/tests/Fixture/BroodsFixture.php
@@ -56,7 +56,7 @@ class BroodsFixture extends TestFixture
'id' => self::BROOD_WIREMOCK_ID,
'uuid' => $faker->uuid(),
'name' => 'wiremock',
- 'url' => 'http://localhost:8080',
+ 'url' => sprintf('http://%s:%s', $_ENV['WIREMOCK_HOST'] ?? 'localhost', $_ENV['WIREMOCK_PORT'] ?? '8080'),
'description' => $faker->text,
'organisation_id' => OrganisationsFixture::ORGANISATION_B_ID,
'trusted' => true,
diff --git a/tests/Fixture/InboxFixture.php b/tests/Fixture/InboxFixture.php
index 40303b2..d274a56 100644
--- a/tests/Fixture/InboxFixture.php
+++ b/tests/Fixture/InboxFixture.php
@@ -11,8 +11,8 @@ class InboxFixture extends TestFixture
public $connection = 'test';
public $table = 'inbox';
- public const INBOX_USER_REGISTRATION_ID = 1;
- public const INBOX_INCOMING_CONNECTION_REQUEST_ID = 2;
+ public const INBOX_USER_REGISTRATION_UUID = 'e783b13a-7019-48f5-848e-582bb930a833';
+ public const INBOX_INCOMING_CONNECTION_REQUEST_UUID = '9810bd94-16f9-42e0-b364-af59dba50a34';
public function init(): void
{
@@ -20,8 +20,7 @@ class InboxFixture extends TestFixture
$this->records = [
[
- 'id' => self::INBOX_USER_REGISTRATION_ID,
- 'uuid' => $faker->uuid(),
+ 'uuid' => self::INBOX_USER_REGISTRATION_UUID,
'scope' => 'User',
'action' => 'Registration',
'title' => 'User account creation requested for foo@bar.com',
@@ -37,15 +36,14 @@ class InboxFixture extends TestFixture
'modified' => $faker->dateTime()->getTimestamp()
],
[
- 'id' => self::INBOX_INCOMING_CONNECTION_REQUEST_ID,
- 'uuid' => $faker->uuid(),
+ 'uuid' => self::INBOX_INCOMING_CONNECTION_REQUEST_UUID,
'scope' => 'LocalTool',
'action' => 'IncomingConnectionRequest',
'title' => 'Request for MISP Inter-connection',
'origin' => 'http://127.0.0.1',
'comment' => null,
'description' => 'Handle Phase I of inter-connection when another cerebrate instance performs the request.',
- 'user_id' => UsersFixture::USER_ORG_ADMIN_ID,
+ 'user_id' => UsersFixture::USER_ADMIN_ID,
'data' => [
'connectorName' => 'MispConnector',
'cerebrateURL' => 'http://127.0.0.1',
diff --git a/tests/Fixture/IndividualsFixture.php b/tests/Fixture/IndividualsFixture.php
index 13aecdf..9e33d53 100644
--- a/tests/Fixture/IndividualsFixture.php
+++ b/tests/Fixture/IndividualsFixture.php
@@ -15,6 +15,7 @@ class IndividualsFixture extends TestFixture
public const INDIVIDUAL_ORG_ADMIN_ID = 3;
public const INDIVIDUAL_REGULAR_USER_ID = 4;
public const INDIVIDUAL_A_ID = 5;
+ public const INDIVIDUAL_B_ID = 6;
public function init(): void
{
@@ -70,6 +71,16 @@ class IndividualsFixture extends TestFixture
'position' => 'user',
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
+ ],
+ [
+ 'id' => self::INDIVIDUAL_B_ID,
+ 'uuid' => $faker->uuid(),
+ 'email' => $faker->email(),
+ 'first_name' => $faker->firstName,
+ 'last_name' => $faker->lastName,
+ 'position' => 'user',
+ 'created' => $faker->dateTime()->getTimestamp(),
+ 'modified' => $faker->dateTime()->getTimestamp()
]
];
parent::init();
diff --git a/tests/Fixture/MetaTemplateDirectoryFixture.php b/tests/Fixture/MetaTemplateDirectoryFixture.php
new file mode 100644
index 0000000..04c6242
--- /dev/null
+++ b/tests/Fixture/MetaTemplateDirectoryFixture.php
@@ -0,0 +1,30 @@
+records = [
+ [
+ 'id' => self::META_TEMPLATE_DIRECTORY_ID,
+ 'uuid' => self::META_TEMPLATE_DIRECTORY_UUID,
+ 'name' => 'Test Meta Template Directory',
+ 'namespace' => 'cerebrate',
+ 'version' => '1'
+ ]
+ ];
+
+ parent::init();
+ }
+}
diff --git a/tests/Fixture/MetaTemplateFieldsFixture.php b/tests/Fixture/MetaTemplateFieldsFixture.php
index 141a7aa..ff38317 100644
--- a/tests/Fixture/MetaTemplateFieldsFixture.php
+++ b/tests/Fixture/MetaTemplateFieldsFixture.php
@@ -17,6 +17,7 @@ class MetaTemplateFieldsFixture extends TestFixture
'field' => 'test_field_1',
'type' => 'text',
'meta_template_id' => MetaTemplatesFixture::ENABLED_TEST_ORG_META_TEMPLATE_ID,
+ 'meta_template_directory_id' => MetaTemplateDirectoryFixture::META_TEMPLATE_DIRECTORY_ID,
'regex' => null,
'multiple' => 1,
'enabled' => 1,
diff --git a/tests/Fixture/MetaTemplatesFixture.php b/tests/Fixture/MetaTemplatesFixture.php
index cbe96a2..6eed2bb 100644
--- a/tests/Fixture/MetaTemplatesFixture.php
+++ b/tests/Fixture/MetaTemplatesFixture.php
@@ -44,6 +44,7 @@ class MetaTemplatesFixture extends TestFixture
$this->records = [
[
'id' => self::ENABLED_TEST_ORG_META_TEMPLATE_ID,
+ 'meta_template_directory_id' => MetaTemplateDirectoryFixture::META_TEMPLATE_DIRECTORY_ID,
'scope' => 'organisation',
'name' => 'Test Meta Template (enabled)',
'namespace' => 'cerebrate',
@@ -58,6 +59,7 @@ class MetaTemplatesFixture extends TestFixture
],
[
'id' => self::DISABLED_TEST_ORG_META_TEMPLATE_ID,
+ 'meta_template_directory_id' => MetaTemplateDirectoryFixture::META_TEMPLATE_DIRECTORY_ID,
'scope' => 'organisation',
'name' => 'Test Meta Template (disabled)',
'namespace' => 'cerebrate',
diff --git a/tests/Helper/WireMockTestTrait.php b/tests/Helper/WireMockTestTrait.php
index 41aea61..69d33c5 100644
--- a/tests/Helper/WireMockTestTrait.php
+++ b/tests/Helper/WireMockTestTrait.php
@@ -15,16 +15,18 @@ trait WireMockTestTrait
private $wiremock;
/** @var array */
- private $config = [
- 'hostname' => 'localhost',
- 'port' => 8080
- ];
+ private $config;
public function initializeWireMock(): void
{
+ $this->config = [
+ 'hostname' => $_ENV['WIREMOCK_HOST'] ?? 'localhost',
+ 'port' => $_ENV['WIREMOCK_PORT'] ?? 8080
+ ];
+
$this->wiremock = WireMock::create(
- $_ENV['WIREMOCK_HOST'] ?? $this->config['hostname'],
- $_ENV['WIREMOCK_PORT'] ?? $this->config['port']
+ $this->config['hostname'],
+ $this->config['port']
);
if (!$this->wiremock->isAlive()) {
diff --git a/tests/README.md b/tests/README.md
index 434f84a..bfdead7 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -59,6 +59,7 @@ $ vendor/bin/phpunit --testsuite=api --testdox
Available suites:
* `app`: runs all test suites
* `api`: runs only api tests
+* `e2e`: runs only integration tests (requires wiremock running)
* `controller`: runs only controller tests
* _to be continued ..._
diff --git a/tests/TestCase/Api/Inbox/IndexInboxApiTest.php b/tests/TestCase/Api/Inbox/IndexInboxApiTest.php
index b8af1c6..0a60393 100644
--- a/tests/TestCase/Api/Inbox/IndexInboxApiTest.php
+++ b/tests/TestCase/Api/Inbox/IndexInboxApiTest.php
@@ -30,7 +30,7 @@ class IndexInboxApiTest extends TestCase
$this->get(self::ENDPOINT);
$this->assertResponseOk();
- $this->assertResponseContains(sprintf('"id": %d', InboxFixture::INBOX_USER_REGISTRATION_ID));
- $this->assertResponseContains(sprintf('"id": %d', InboxFixture::INBOX_INCOMING_CONNECTION_REQUEST_ID));
+ $this->assertResponseContains(sprintf('"uuid": "%s"', InboxFixture::INBOX_USER_REGISTRATION_UUID));
+ $this->assertResponseContains(sprintf('"uuid": "%s"', InboxFixture::INBOX_INCOMING_CONNECTION_REQUEST_UUID));
}
}
diff --git a/tests/TestCase/Api/LocalTools/MispInterConnectionTest.php b/tests/TestCase/Api/LocalTools/MispInterConnectionTest.php
index 7f643d3..e81c4ec 100644
--- a/tests/TestCase/Api/LocalTools/MispInterConnectionTest.php
+++ b/tests/TestCase/Api/LocalTools/MispInterConnectionTest.php
@@ -31,20 +31,20 @@ class MispInterConnectionTest extends TestCase
];
/** constants related to the local Cerebrate instance */
- private const LOCAL_CEREBRATE_URL = 'http://127.0.0.1';
+ private const LOCAL_CEREBRATE_URL = 'http://localhost';
/** constants related to the local MISP instance */
- private const LOCAL_MISP_INSTANCE_URL = 'http://localhost:8080/MISP_LOCAL';
+ private const LOCAL_MISP_INSTANCE_URL = '/MISP_LOCAL';
private const LOCAL_MISP_ADMIN_USER_AUTHKEY = 'b17ce79ac0f05916f382ab06ea4790665dbc174c';
/** constants related to the remote Cerebrate instance */
- private const REMOTE_CEREBRATE_URL = 'http://127.0.0.1:8080/CEREBRATE_REMOTE';
+ private const REMOTE_CEREBRATE_URL = '/CEREBRATE_REMOTE';
private const REMOTE_CEREBRATE_AUTHKEY = 'a192ba3c749b545f9cec6b6bba0643736f6c3022';
/** constants related to the remote MISP instance */
private const REMOTE_MISP_SYNC_USER_ID = 333;
private const REMOTE_MISP_SYNC_USER_EMAIL = 'sync@misp.remote';
- private const REMOTE_MISP_INSTANCE_URL = 'http://localhost:8080/MISP_REMOTE';
+ private const REMOTE_MISP_INSTANCE_URL = '/MISP_REMOTE';
private const REMOTE_MISP_AUTHKEY = '19ca57ecebd2fe34c1c17d729980678eb648d541';
@@ -64,7 +64,7 @@ class MispInterConnectionTest extends TestCase
'name' => 'MISP_LOCAL',
'connector' => 'MispConnector',
'settings' => json_encode([
- 'url' => self::LOCAL_MISP_INSTANCE_URL,
+ 'url' => $this->getWireMockBaseUrl() . self::LOCAL_MISP_INSTANCE_URL,
'authkey' => self::LOCAL_MISP_ADMIN_USER_AUTHKEY,
'skip_ssl' => true,
]),
@@ -90,7 +90,7 @@ class MispInterConnectionTest extends TestCase
[
'uuid' => $LOCAL_BROOD_UUID,
'name' => 'Local Brood',
- 'url' => self::REMOTE_CEREBRATE_URL,
+ 'url' => $this->getWireMockBaseUrl() . self::REMOTE_CEREBRATE_URL,
'description' => $faker->text,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'trusted' => true,
@@ -228,10 +228,10 @@ class MispInterConnectionTest extends TestCase
[
'email' => self::REMOTE_MISP_SYNC_USER_EMAIL,
'authkey' => self::REMOTE_MISP_AUTHKEY,
- 'url' => self::REMOTE_MISP_INSTANCE_URL,
+ 'url' => $this->getWireMockBaseUrl() . self::REMOTE_MISP_INSTANCE_URL,
'reflected_user_id' => self::REMOTE_MISP_SYNC_USER_ID,
'connectorName' => 'MispConnector',
- 'cerebrateURL' => self::REMOTE_CEREBRATE_URL,
+ 'cerebrateURL' => $this->getWireMockBaseUrl() . self::REMOTE_CEREBRATE_URL,
'local_tool_id' => 1,
'remote_tool_id' => 1,
'tool_name' => 'MISP_REMOTE'
@@ -250,7 +250,7 @@ class MispInterConnectionTest extends TestCase
self::LOCAL_MISP_ADMIN_USER_AUTHKEY,
[
'authkey' => self::REMOTE_MISP_AUTHKEY,
- 'url' => self::REMOTE_MISP_INSTANCE_URL,
+ 'url' => $this->getWireMockBaseUrl() . self::REMOTE_MISP_INSTANCE_URL,
'name' => 'MISP_REMOTE',
'remote_org_id' => OrganisationsFixture::ORGANISATION_A_ID
]
diff --git a/tests/TestCase/Api/Users/AddUserApiTest.php b/tests/TestCase/Api/Users/AddUserApiTest.php
index 3437d29..8d10139 100644
--- a/tests/TestCase/Api/Users/AddUserApiTest.php
+++ b/tests/TestCase/Api/Users/AddUserApiTest.php
@@ -6,7 +6,7 @@ namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
-use App\Test\Fixture\UsersFixture;
+use App\Test\Fixture\IndividualsFixture;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Fixture\RolesFixture;
use App\Test\Helper\ApiTestTrait;
@@ -31,18 +31,20 @@ class AddUserApiTest extends TestCase
$this->post(
self::ENDPOINT,
[
- 'individual_id' => UsersFixture::USER_REGULAR_USER_ID,
+ 'individual_id' => IndividualsFixture::INDIVIDUAL_B_ID,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'role_id' => RolesFixture::ROLE_REGULAR_USER_ID,
'disabled' => false,
- 'username' => 'test',
+ 'username' => 'test123',
'password' => 'Password123456!',
]
);
+ print_r($this->getJsonResponseAsArray());
+
$this->assertResponseOk();
- $this->assertResponseContains('"username": "test"');
- $this->assertDbRecordExists('Users', ['username' => 'test']);
+ $this->assertResponseContains('"username": "test123"');
+ $this->assertDbRecordExists('Users', ['username' => 'test123']);
}
public function testAddUserNotAllowedAsRegularUser(): void
@@ -51,7 +53,7 @@ class AddUserApiTest extends TestCase
$this->post(
self::ENDPOINT,
[
- 'individual_id' => UsersFixture::USER_REGULAR_USER_ID,
+ 'individual_id' => IndividualsFixture::INDIVIDUAL_B_ID,
'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
'role_id' => RolesFixture::ROLE_REGULAR_USER_ID,
'disabled' => false,
@@ -61,6 +63,6 @@ class AddUserApiTest extends TestCase
);
$this->assertResponseCode(405);
- $this->assertDbRecordNotExists('Users', ['username' => 'test']);
+ $this->assertDbRecordNotExists('Users', ['username' => 'test123']);
}
}
diff --git a/tests/TestCase/Api/Users/DeleteUserApiTest.php b/tests/TestCase/Api/Users/DeleteUserApiTest.php
index 9288b9a..2ffe0be 100644
--- a/tests/TestCase/Api/Users/DeleteUserApiTest.php
+++ b/tests/TestCase/Api/Users/DeleteUserApiTest.php
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
+use Cake\Core\Configure;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\UsersFixture;
@@ -25,6 +26,7 @@ class DeleteUserApiTest extends TestCase
public function testDeleteUser(): void
{
+ Configure::write('user.allow-user-deletion', true);
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$url = sprintf('%s/%d', self::ENDPOINT, UsersFixture::USER_REGULAR_USER_ID);
$this->delete($url);
diff --git a/tests/TestCase/ApplicationTest.php b/tests/TestCase/ApplicationTest.php
index e2d3183..5704f68 100644
--- a/tests/TestCase/ApplicationTest.php
+++ b/tests/TestCase/ApplicationTest.php
@@ -40,14 +40,12 @@ class ApplicationTest extends IntegrationTestCase
$app->bootstrap();
$plugins = $app->getPlugins();
- $this->assertCount(7, $plugins);
$this->assertSame('Bake', $plugins->get('Bake')->getName());
$this->assertSame('DebugKit', $plugins->get('DebugKit')->getName());
$this->assertSame('Migrations', $plugins->get('Migrations')->getName());
$this->assertSame('Authentication', $plugins->get('Authentication')->getName());
$this->assertSame('ADmad/SocialAuth', $plugins->get('ADmad/SocialAuth')->getName());
$this->assertSame('Tags', $plugins->get('Tags')->getName());
- $this->assertSame('Cake/TwigView', $plugins->get('Cake/TwigView')->getName());
}
/**
diff --git a/tests/TestCase/Integration/Broods/TestBroodConnectionApiTest.php b/tests/TestCase/Integration/Broods/TestBroodConnectionApiTest.php
new file mode 100644
index 0000000..8f0a0df
--- /dev/null
+++ b/tests/TestCase/Integration/Broods/TestBroodConnectionApiTest.php
@@ -0,0 +1,65 @@
+setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $this->initializeWireMock();
+ $stub = $this->mockCerebrateStatusResponse();
+
+ $url = sprintf('%s/%d', self::ENDPOINT, BroodsFixture::BROOD_WIREMOCK_ID);
+ $this->get($url);
+
+ $this->verifyStubCalled($stub);
+ $this->assertResponseOk();
+ $this->assertResponseContains('"user": "wiremock"');
+ }
+
+ private function mockCerebrateStatusResponse(): \WireMock\Stubbing\StubMapping
+ {
+ return $this->getWireMock()->stubFor(
+ WireMock::get(WireMock::urlEqualTo('/instance/status.json'))
+ ->willReturn(WireMock::aResponse()
+ ->withHeader('Content-Type', 'application/json')
+ ->withBody((string)json_encode(
+ [
+ "version" => "0.1",
+ "application" => "Cerebrate",
+ "user" => [
+ "id" => 1,
+ "username" => "wiremock",
+ "role" => [
+ "id" => 1
+ ]
+ ]
+ ]
+ )))
+ );
+ }
+}
diff --git a/tests/TestCase/Integration/LocalTools/MispInterConnectionTest.php b/tests/TestCase/Integration/LocalTools/MispInterConnectionTest.php
new file mode 100644
index 0000000..33f9eac
--- /dev/null
+++ b/tests/TestCase/Integration/LocalTools/MispInterConnectionTest.php
@@ -0,0 +1,405 @@
+initializeWireMock();
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+
+ $faker = \Faker\Factory::create();
+
+ /**
+ * 1. Create LocalTool connection to `MISP LOCAL` (local MISP instance)
+ */
+ $this->post(
+ sprintf('%s/localTools/add', self::LOCAL_CEREBRATE_URL),
+ [
+ 'name' => 'MISP_LOCAL',
+ 'connector' => 'MispConnector',
+ 'settings' => json_encode([
+ 'url' => $this->getWireMockBaseUrl() . self::LOCAL_MISP_INSTANCE_URL,
+ 'authkey' => self::LOCAL_MISP_ADMIN_USER_AUTHKEY,
+ 'skip_ssl' => true,
+ ]),
+ 'description' => 'MISP local instance',
+ 'exposed' => true
+ ]
+ );
+ $this->assertResponseOk();
+ $this->assertDbRecordExists('LocalTools', ['name' => 'MISP_LOCAL']);
+
+ /**
+ * 2. Create a new Brood (connect to a remote Cerebrate instance)
+ * This step assumes that the remote Cerebrate instance is already
+ * running and has a user created for the local Cerebrate instance.
+ *
+ * NOTE: Uses OrganisationsFixture::ORGANISATION_A_ID from the
+ * fixtures as the local Organisation.
+ */
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $LOCAL_BROOD_UUID = $faker->uuid;
+ $this->post(
+ '/broods/add',
+ [
+ 'uuid' => $LOCAL_BROOD_UUID,
+ 'name' => 'Local Brood',
+ 'url' => $this->getWireMockBaseUrl() . self::REMOTE_CEREBRATE_URL,
+ 'description' => $faker->text,
+ 'organisation_id' => OrganisationsFixture::ORGANISATION_A_ID,
+ 'trusted' => true,
+ 'pull' => true,
+ 'skip_proxy' => true,
+ 'authkey' => self::REMOTE_CEREBRATE_AUTHKEY,
+ ]
+ );
+ $this->assertResponseOk();
+ $this->assertDbRecordExists('Broods', ['uuid' => $LOCAL_BROOD_UUID]);
+ $brood = $this->getJsonResponseAsArray();
+
+ /**
+ * 3. Create a new Cerebrate local user for the remote Cerebrate
+ * These includes:
+ * - 3.a: Create a new Organisation
+ * - 3.b: Create a new Individual
+ * - 3.c: Create a new User
+ * - 3.d: Create a new Authkey
+ */
+ // Create Organisation
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $remoteOrgUuid = $faker->uuid;
+ $this->post(
+ '/organisations/add',
+ [
+ 'name' => 'Remote Organisation',
+ 'description' => $faker->text,
+ 'uuid' => $remoteOrgUuid,
+ 'url' => 'http://cerebrate.remote',
+ 'nationality' => 'US',
+ 'sector' => 'sector',
+ 'type' => 'type',
+ ]
+ );
+ $this->assertResponseOk();
+ $this->assertDbRecordExists('Organisations', ['uuid' => $remoteOrgUuid]);
+ $remoteOrg = $this->getJsonResponseAsArray();
+
+ // Create Individual
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $this->post(
+ '/individuals/add',
+ [
+ 'email' => 'sync@cerebrate.remote',
+ 'first_name' => 'Remote',
+ 'last_name' => 'Cerebrate'
+ ]
+ );
+ $this->assertResponseOk();
+ $this->assertDbRecordExists('Individuals', ['email' => 'sync@cerebrate.remote']);
+ $remoteIndividual = $this->getJsonResponseAsArray();
+
+ // Create User
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $this->post(
+ '/users/add',
+ [
+ 'individual_id' => $remoteIndividual['id'],
+ 'organisation_id' => $remoteOrg['id'],
+ 'role_id' => RolesFixture::ROLE_SYNC_ID,
+ 'disabled' => false,
+ 'username' => 'remote_cerebrate',
+ 'password' => 'Password123456!',
+ ]
+ );
+ $this->assertResponseOk();
+ $this->assertDbRecordExists('Users', ['username' => 'remote_cerebrate']);
+ $user = $this->getJsonResponseAsArray();
+
+ // Create Authkey
+ $remoteCerebrateAuthkey = $faker->sha1;
+ $remoteAuthkeyUuid = $faker->uuid;
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $this->post(
+ '/authKeys/add',
+ [
+ 'uuid' => $remoteAuthkeyUuid,
+ 'authkey' => $remoteCerebrateAuthkey,
+ 'expiration' => 0,
+ 'user_id' => $user['id'],
+ 'comment' => $faker->text
+ ]
+ );
+ $this->assertResponseOk();
+ $this->assertDbRecordExists('AuthKeys', ['uuid' => $remoteAuthkeyUuid]);
+
+ /**
+ * 4. Get remote Cerebrate exposed tools
+ */
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $this->mockCerebrateGetExposedToolsResponse('CEREBRATE_REMOTE', self::REMOTE_CEREBRATE_AUTHKEY);
+ $this->get(sprintf('/localTools/broodTools/%s', $brood['id']));
+ $this->assertResponseOk();
+ $tools = $this->getJsonResponseAsArray();
+
+ /**
+ * 5. Issue a connection request to the remote MISP instance
+ */
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $this->mockCerebrateGetExposedToolsResponse('CEREBRATE_REMOTE', self::REMOTE_CEREBRATE_AUTHKEY);
+ $this->mockMispViewOrganisationByUuid(
+ 'MISP_LOCAL',
+ self::LOCAL_MISP_ADMIN_USER_AUTHKEY,
+ OrganisationsFixture::ORGANISATION_A_UUID,
+ OrganisationsFixture::ORGANISATION_A_ID
+ );
+ $this->mockMispCreateSyncUser(
+ 'MISP_LOCAL',
+ self::LOCAL_MISP_ADMIN_USER_AUTHKEY,
+ self::REMOTE_MISP_SYNC_USER_ID,
+ self::REMOTE_MISP_SYNC_USER_EMAIL
+ );
+ $this->mockCerebrateCreateMispIncommingConnectionRequest(
+ 'CEREBRATE_REMOTE',
+ UsersFixture::USER_ADMIN_ID,
+ self::LOCAL_CEREBRATE_URL,
+ self::REMOTE_CEREBRATE_AUTHKEY,
+ self::LOCAL_MISP_INSTANCE_URL
+ );
+ $this->post(
+ sprintf('/localTools/connectionRequest/%s/%s', $brood['id'], $tools[0]['id']),
+ [
+ 'local_tool_id' => 1
+ ]
+ );
+ $this->assertResponseOk();
+
+ /**
+ * 6. Remote Cerebrate accepts the connection request
+ */
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $this->post(
+ '/inbox/createEntry/LocalTool/AcceptedRequest',
+ [
+ 'email' => self::REMOTE_MISP_SYNC_USER_EMAIL,
+ 'authkey' => self::REMOTE_MISP_AUTHKEY,
+ 'url' => $this->getWireMockBaseUrl() . self::REMOTE_MISP_INSTANCE_URL,
+ 'reflected_user_id' => self::REMOTE_MISP_SYNC_USER_ID,
+ 'connectorName' => 'MispConnector',
+ 'cerebrateURL' => $this->getWireMockBaseUrl() . self::REMOTE_CEREBRATE_URL,
+ 'local_tool_id' => 1,
+ 'remote_tool_id' => 1,
+ 'tool_name' => 'MISP_REMOTE'
+ ]
+ );
+ $this->assertResponseOk();
+ $acceptRequest = $this->getJsonResponseAsArray();
+
+ /**
+ * 7. Finalize the connection
+ */
+ $this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
+ $this->mockEnableMispSyncUser('MISP_LOCAL', self::LOCAL_MISP_ADMIN_USER_AUTHKEY, self::REMOTE_MISP_SYNC_USER_ID);
+ $this->mockAddMispServer(
+ 'MISP_LOCAL',
+ self::LOCAL_MISP_ADMIN_USER_AUTHKEY,
+ [
+ 'authkey' => self::REMOTE_MISP_AUTHKEY,
+ 'url' => $this->getWireMockBaseUrl() . self::REMOTE_MISP_INSTANCE_URL,
+ 'name' => 'MISP_REMOTE',
+ 'remote_org_id' => OrganisationsFixture::ORGANISATION_A_ID
+ ]
+ );
+ $this->post(sprintf('/inbox/process/%s', $acceptRequest['data']['id']));
+ $this->assertResponseOk();
+ $this->assertResponseContains('"success": true');
+ $this->verifyAllStubsCalled();
+ }
+
+ private function mockCerebrateGetExposedToolsResponse(string $instance, string $cerebrateAuthkey): \WireMock\Stubbing\StubMapping
+ {
+ return $this->getWireMock()->stubFor(
+ WireMock::get(WireMock::urlEqualTo("/$instance/localTools/exposedTools"))
+ ->withHeader('Authorization', WireMock::equalTo($cerebrateAuthkey))
+ ->willReturn(WireMock::aResponse()
+ ->withHeader('Content-Type', 'application/json')
+ ->withBody((string)json_encode(
+ [
+ [
+ "id" => 1,
+ "name" => "MISP ($instance)",
+ "connector" => "MispConnector",
+ ]
+ ]
+ )))
+ );
+ }
+
+ private function mockMispViewOrganisationByUuid(string $instance, string $mispAuthkey, string $orgUuid, int $orgId): \WireMock\Stubbing\StubMapping
+ {
+ return $this->getWireMock()->stubFor(
+ WireMock::get(WireMock::urlEqualTo("/$instance/organisations/view/$orgUuid/limit:50"))
+ ->withHeader('Authorization', WireMock::equalTo($mispAuthkey))
+ ->willReturn(WireMock::aResponse()
+ ->withHeader('Content-Type', 'application/json')
+ ->withBody((string)json_encode(
+ [
+ "Organisation" => [
+ "id" => $orgId,
+ "name" => $instance . ' Organisation',
+ "uuid" => $orgUuid,
+ "local" => true
+ ]
+ ]
+ )))
+ );
+ }
+
+ private function mockMispCreateSyncUser(string $instance, string $mispAuthkey, int $userId, string $email): \WireMock\Stubbing\StubMapping
+ {
+ $faker = \Faker\Factory::create();
+ return $this->getWireMock()->stubFor(
+ WireMock::post(WireMock::urlEqualTo("/$instance/admin/users/add"))
+ ->withHeader('Authorization', WireMock::equalTo($mispAuthkey))
+ ->willReturn(WireMock::aResponse()
+ ->withHeader('Content-Type', 'application/json')
+ ->withBody((string)json_encode(
+ [
+ "User" => [
+ "id" => $userId,
+ "email" => $email,
+ "authkey" => $faker->sha1
+ ]
+ ]
+ )))
+ );
+ }
+
+ private function mockCerebrateCreateMispIncommingConnectionRequest(
+ string $instance,
+ int $userId,
+ string $cerebrateUrl,
+ string $cerebrateAuthkey,
+ string $mispUrl
+ ): \WireMock\Stubbing\StubMapping {
+ $faker = \Faker\Factory::create();
+
+ return $this->getWireMock()->stubFor(
+ WireMock::post(WireMock::urlEqualTo("/$instance/inbox/createEntry/LocalTool/IncomingConnectionRequest"))
+ ->withHeader('Authorization', WireMock::equalTo($cerebrateAuthkey))
+ ->willReturn(WireMock::aResponse()
+ ->withHeader('Content-Type', 'application/json')
+ ->withBody((string)json_encode(
+ [
+ 'data' => [
+ 'id' => $faker->randomNumber(),
+ 'uuid' => $faker->uuid,
+ 'origin' => $cerebrateUrl,
+ 'user_id' => $userId,
+ 'data' => [
+ 'connectorName' => 'MispConnector',
+ 'cerebrateURL' => $cerebrateUrl,
+ 'url' => $mispUrl,
+ 'tool_connector' => 'MispConnector',
+ 'local_tool_id' => 1,
+ 'remote_tool_id' => 1,
+ ],
+ 'title' => 'Request for MISP Inter-connection',
+ 'scope' => 'LocalTool',
+ 'action' => 'IncomingConnectionRequest',
+ 'description' => 'Handle Phase I of inter-connection when another cerebrate instance performs the request.',
+ 'local_tool_connector_name' => 'MispConnector',
+ 'created' => date('c'),
+ 'modified' => date('c')
+ ],
+ 'success' => true,
+ 'message' => 'LocalTool request for IncomingConnectionRequest created',
+ 'errors' => [],
+ ]
+ )))
+ );
+ }
+
+ private function mockEnableMispSyncUser(string $instance, string $mispAuthkey, int $userId): \WireMock\Stubbing\StubMapping
+ {
+ return $this->getWireMock()->stubFor(
+ WireMock::post(WireMock::urlEqualTo("/$instance/admin/users/edit/$userId"))
+ ->withHeader('Authorization', WireMock::equalTo($mispAuthkey))
+ ->withRequestBody(WireMock::equalToJson(json_encode(['disabled' => false])))
+ ->willReturn(WireMock::aResponse()
+ ->withHeader('Content-Type', 'application/json')
+ ->withBody((string)json_encode(
+ [
+ "User" => [
+ "id" => $userId,
+ ]
+ ]
+ )))
+ );
+ }
+
+ private function mockAddMispServer(string $instance, string $mispAuthkey, array $body): \WireMock\Stubbing\StubMapping
+ {
+ $faker = \Faker\Factory::create();
+
+ return $this->getWireMock()->stubFor(
+ WireMock::post(WireMock::urlEqualTo("/$instance/servers/add"))
+ ->withHeader('Authorization', WireMock::equalTo($mispAuthkey))
+ ->withRequestBody(WireMock::equalToJson(json_encode($body)))
+ ->willReturn(WireMock::aResponse()
+ ->withHeader('Content-Type', 'application/json')
+ ->withBody((string)json_encode(
+ [
+ 'Server' => [
+ 'id' => $faker->randomNumber()
+ ]
+ ]
+ )))
+ );
+ }
+}