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 47269ff..5a69186 100644
--- a/src/Controller/Component/CRUDComponent.php
+++ b/src/Controller/Component/CRUDComponent.php
@@ -102,7 +102,7 @@ class CRUDComponent extends Component
if (!$this->Controller->ParamHandler->isRest()) {
$this->setRequestedEntryAmount();
- } else if (!empty($this->request->getQuery('limit'))) {
+ } else if (empty($this->request->getQuery('limit'))) {
$this->Controller->paginate['limit'] = PHP_INT_MAX; // Make sure to download the entire filtered table
}
$data = $this->Controller->paginate($query, $this->Controller->paginate ?? []);
@@ -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/templates/Broods/index.php b/templates/Broods/index.php
index a78cf5a..d26db0d 100644
--- a/templates/Broods/index.php
+++ b/templates/Broods/index.php
@@ -61,6 +61,7 @@ echo $this->element('genericElements/IndexTable/index_table', [
],
'title' => __('Broods Index'),
'description' => __('Cerebrate can connect to other Cerebrate instances to exchange trust information and to instrument interconnectivity between connected local tools. Each such Cerebrate instance with its connected tools is considered to be a brood.'),
+ 'includeAllPagination' => true,
'pull' => 'right',
'actions' => [
[
diff --git a/templates/Individuals/index.php b/templates/Individuals/index.php
index d7d228f..463f4de 100644
--- a/templates/Individuals/index.php
+++ b/templates/Individuals/index.php
@@ -78,6 +78,7 @@ echo $this->element('genericElements/IndexTable/index_table', [
],
'title' => __('ContactDB Individuals Index'),
'description' => __('A list of individuals known by your Cerebrate instance. This list can get populated either directly, by adding new individuals or by fetching them from trusted remote sources. Additionally, users created for the platform will always have an individual identity.'),
+ 'includeAllPagination' => true,
'actions' => [
[
'url' => '/individuals/view',
diff --git a/templates/MetaTemplates/index.php b/templates/MetaTemplates/index.php
index 1ac384f..0c3acfc 100644
--- a/templates/MetaTemplates/index.php
+++ b/templates/MetaTemplates/index.php
@@ -169,6 +169,7 @@ echo $this->element('genericElements/IndexTable/index_table', [
],
'title' => __('Meta Field Templates'),
'description' => __('The various templates used to enrich certain objects by a set of standardised fields.'),
+ 'includeAllPagination' => true,
'actions' => [
[
'url' => '/metaTemplates/view',
diff --git a/templates/OrgGroups/index.php b/templates/OrgGroups/index.php
index 33569ad..ad714bf 100644
--- a/templates/OrgGroups/index.php
+++ b/templates/OrgGroups/index.php
@@ -62,6 +62,7 @@ echo $this->element('genericElements/IndexTable/index_table', [
],
'title' => __('Organisation Groups Index'),
'description' => __('OrgGroups are an administrative concept, multiple organisations can belong to a grouping that allows common management by so called "GroupAdmins". This helps grouping organisations by sector, country or other commonalities into co-managed sub-communities.'),
+ 'includeAllPagination' => true,
'actions' => [
[
'url' => '/orgGroups/view',
diff --git a/templates/Organisations/index.php b/templates/Organisations/index.php
index 2cf96de..c3fb2ae 100644
--- a/templates/Organisations/index.php
+++ b/templates/Organisations/index.php
@@ -97,6 +97,7 @@ echo $this->element('genericElements/IndexTable/index_table', [
],
'title' => __('ContactDB Organisation Index'),
'description' => __('A list of organisations known by your Cerebrate instance. This list can get populated either directly, by adding new organisations or by fetching them from trusted remote sources.'),
+ 'includeAllPagination' => true,
'actions' => [
[
'url' => '/organisations/view',
diff --git a/templates/Roles/index.php b/templates/Roles/index.php
index 8e12ed9..a5f2ffb 100644
--- a/templates/Roles/index.php
+++ b/templates/Roles/index.php
@@ -77,6 +77,7 @@ echo $this->element('genericElements/IndexTable/index_table', [
],
'title' => __('Roles Index'),
'description' => __('A list of configurable user roles. Create or modify user access roles based on the settings below.'),
+ 'includeAllPagination' => true,
'pull' => 'right',
'actions' => [
[
diff --git a/templates/SharingGroups/index.php b/templates/SharingGroups/index.php
index 0162c23..bb4843e 100644
--- a/templates/SharingGroups/index.php
+++ b/templates/SharingGroups/index.php
@@ -57,6 +57,7 @@ echo $this->element('genericElements/IndexTable/index_table', [
],
'title' => __('Sharing Groups Index'),
'description' => __('Sharing groups are distribution lists usable by tools that can exchange information with a list of trusted partners. Create recurring or ad hoc sharing groups and share them with the members of the sharing group.'),
+ 'includeAllPagination' => true,
'pull' => 'right',
'actions' => [
[
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()
+ ]
+ ]
+ )))
+ );
+ }
+}