diff --git a/src/Controller/LocalToolsController.php b/src/Controller/LocalToolsController.php
index 44d9f4e..61f6e92 100644
--- a/src/Controller/LocalToolsController.php
+++ b/src/Controller/LocalToolsController.php
@@ -205,10 +205,45 @@ class LocalToolsController extends AppController
{
$this->loadModel('Broods');
$tools = $this->Broods->queryLocalTools($id);
+ foreach ($tools as $k => $tool) {
+ $tools[$k]['local_tools'] = $this->LocalTools->appendLocalToolConnections($id, $tool);
+ }
if ($this->ParamHandler->isRest()) {
return $this->RestResponse->viewData($tools, 'json');
}
+ $this->set('id', $id);
$this->set('data', $tools);
$this->set('metaGroup', 'Administration');
}
+
+ public function connectionRequest($cerebrate_id, $remote_tool_id)
+ {
+ $params = [
+ 'cerebrate_id' => $cerebrate_id,
+ 'remote_tool_id' => $remote_tool_id
+ ];
+ if ($this->request->is(['post', 'put'])) {
+ $postParams = $this->ParamHandler->harvestParams(['local_tool_id']);
+ if (empty($postParams['local_tool_id'])) {
+ throw new MethodNotAllowedException(__('No local tool ID supplied.'));
+ }
+ $params['local_tool_id'] = $postParams['local_tool_id'];
+ $result = $this->LocalTools->encodeConnection($params);
+ // Send message to remote inbox
+ debug($result);
+ } else {
+ $this->loadModel('Broods');
+ $remoteCerebrate = $this->Broods->find()->where(['id' => $params['cerebrate_id']])->first();
+ $remoteTool = $this->LocalTools->getRemoteToolById($params);
+ $local_tools = $this->LocalTools->encodeConnectionChoice($params);
+ if (empty($local_tools)) {
+ throw new NotFoundException(__('No local equivalent tool found.'));
+ }
+ $this->set('data', [
+ 'remoteCerebrate' => $remoteCerebrate,
+ 'remoteTool' => $remoteTool,
+ 'local_tools' => $local_tools
+ ]);
+ }
+ }
}
diff --git a/src/Lib/default/local_tool_connectors/CommonConnectorTools.php b/src/Lib/default/local_tool_connectors/CommonConnectorTools.php
index c4ab2ef..acfc2e3 100644
--- a/src/Lib/default/local_tool_connectors/CommonConnectorTools.php
+++ b/src/Lib/default/local_tool_connectors/CommonConnectorTools.php
@@ -12,6 +12,10 @@ class CommonConnectorTools
];
public $version = '???';
+ const STATE_INITIAL = 'Request issued';
+ const STATE_ACCEPT = 'Request accepted';
+ const STATE_CONNECTED = 'Connected';
+
public function addExposedFunction(string $functionName): void
{
$this->exposedFunctions[] = $functionName;
@@ -48,6 +52,57 @@ class CommonConnectorTools
$sharing_groups->captureSharingGroup($input);
return true;
}
+
+ public function remoteToolConnectionStatus(array $params, string $status): void
+ {
+ $remoteToolConnections = \Cake\ORM\TableRegistry::getTableLocator()->get('RemoteToolConnections');
+ $remoteToolConnection = $remoteToolConnections->find()->where(
+ [
+ 'local_tool_id' => $params['connection']['id'],
+ 'remote_tool_id' => $params['remote_tool']['id'],
+ 'brood_id' => $params['remote_cerebrate']['id']
+ ]
+ )->first();
+ if (empty($remoteToolConnection)) {
+ $data = $remoteToolConnections->newEmptyEntity();
+ $entry = [
+ 'local_tool_id' => $params['connection']['id'],
+ 'remote_tool_id' => $params['remote_tool']['id'],
+ 'remote_tool_name' => $params['remote_tool']['name'],
+ 'brood_id' => $params['remote_cerebrate']['id'],
+ 'name' => '',
+ 'settings' => '',
+ 'status' => $status,
+ 'created' => time(),
+ 'modified' => time()
+ ];
+ $data = $remoteToolConnections->patchEntity($data, $entry);
+ $remoteToolConnections->save($data);
+ } else {
+ $data = $remoteToolConnections->patchEntity($remoteToolConnection, ['status' => $status, 'modified' => time()]);
+ $remoteToolConnections->save($data);
+ }
+ }
+
+ public function initiateConnectionWrapper(array $params): array
+ {
+ $result = $this->initiateConnection($params);
+ $this->remoteToolConnectionStatus($params, self::STATE_INITIAL);
+ return $result;
+ }
+
+ public function acceptConnectionWrapper(array $params): array
+ {
+ $result = $this->acceptConnection($params);
+ $this->remoteToolConnectionStatus($params, self::STATE_ACCEPT);
+ return $result;
+ }
+
+ public function finaliseConnectionWrapper(array $params): bool
+ {
+ $this->remoteToolConnectionStatus($params, self::STATE_CONNECTED);
+ return false;
+ }
}
?>
diff --git a/src/Lib/default/local_tool_connectors/MispConnector.php b/src/Lib/default/local_tool_connectors/MispConnector.php
index 1acd685..d86afad 100644
--- a/src/Lib/default/local_tool_connectors/MispConnector.php
+++ b/src/Lib/default/local_tool_connectors/MispConnector.php
@@ -143,6 +143,9 @@ class MispConnector extends CommonConnectorTools
if ($response->isOk()) {
return $response;
} else {
+ if (!empty($params['softError'])) {
+ return $response;
+ }
throw new NotFoundException(__('Could not retrieve the requested resource.'));
}
}
@@ -537,11 +540,128 @@ class MispConnector extends CommonConnectorTools
if ($response->getStatusCode() == 200) {
return ['success' => 1, 'message' => __('Setting saved.')];
} else {
- return ['success' => 0, 'message' => __('Could not fetch the remote sharing group.')];
+ return ['success' => 0, 'message' => __('Could not update.')];
}
}
throw new MethodNotAllowedException(__('Invalid http request type for the given action.'));
+ }
+ public function initiateConnection(array $params): array
+ {
+ $params['connection_settings'] = json_decode($params['connection']['settings'], true);
+ $params['misp_organisation'] = $this->getSetOrg($params);
+ $params['sync_user'] = $this->createSyncUser($params);
+ return [
+ 'email' => $params['sync_user']['email'],
+ 'authkey' => $params['sync_user']['authkey'],
+ 'url' => $params['connection_settings']['url']
+ ];
+ }
+
+ public function acceptConnection(array $params): array
+ {
+ $params['sync_user_enabled'] = true;
+ $params['connection_settings'] = json_decode($params['connection']['settings'], true);
+ $params['misp_organisation'] = $this->getSetOrg($params);
+ $params['sync_user'] = $this->createSyncUser($params);
+ $params['sync_connection'] = $this->addServer([
+ 'authkey' => $params['remote_tool']['authkey'],
+ 'url' => $params['remote_tool']['url'],
+ 'name' => $params['remote_tool']['name'],
+ 'remote_org_id' => $params['misp_organisation']['id']
+ ]);
+ return [
+ 'email' => $params['sync_user']['email'],
+ 'authkey' => $params['sync_user']['authkey'],
+ 'url' => $params['connection_settings']['url']
+ ];
+ }
+
+ public function finaliseConnection(array $params): bool
+ {
+ $params['sync_connection'] = $this->addServer([
+ 'authkey' => $params['remote_tool']['authkey'],
+ 'url' => $params['remote_tool']['url'],
+ 'name' => $params['remote_tool']['name'],
+ 'remote_org_id' => $params['misp_organisation']['id']
+ ]);
+ return true;
+ }
+
+ private function getSetOrg(array $params): array
+ {
+ $params['softError'] = 1;
+ $response = $this->getData('/organisations/view/' . $params['remote_org']['uuid'], $params);
+ if ($response->isOk()) {
+ $organisation = $response->getJson()['Organisation'];
+ if (!$organisation['local']) {
+ $organisation['local'] = 1;
+ $response = $this->postData('/admin/organisations/edit/' . $organisation['id'], $params);
+ if (!$response->isOk()) {
+ throw new MethodNotAllowedException(__('Could not update the organisation in MISP.'));
+ }
+ }
+ } else {
+ $params['body'] = [
+ 'uuid' => $params['remote_org']['uuid'],
+ 'name' => $params['remote_org']['name'],
+ 'local' => 1
+ ];
+ $response = $this->postData('/admin/organisations/add', $params);
+ if ($response->isOk()) {
+ $organisation = $response->getJson()['Organisation'];
+ } else {
+ throw new MethodNotAllowedException(__('Could not create the organisation in MISP.'));
+ }
+ }
+ return $organisation;
+ }
+
+ private function createSyncUser(array $params): array
+ {
+ $params['softError'] = 1;
+ $user = [
+ 'email' => 'sync_%s@' . parse_url($params['remote_cerebrate']['url'])['host'],
+ 'org_id' => $params['misp_organisation']['id'],
+ 'role_id' => empty($params['connection_settings']['role_id']) ? 5 : $params['connection_settings']['role_id'],
+ 'disabled' => 1,
+ 'change_pw' => 0,
+ 'termsaccepted' => 1
+ ];
+ return $this->createUser($user, $params);
+ }
+
+ private function addServer(array $params): array
+ {
+ if (
+ empty($params['authkey']) ||
+ empty($params['url']) ||
+ empty($params['remote_org_id']) ||
+ empty($params['name'])
+ ) {
+ throw new MethodNotAllowedException(__('Required data missing from the sync connection object. The following fields are required: [name, url, authkey, org_id].'));
+ }
+ $response = $this->postData('/servers/add', $params);
+ if (!$response->isOk()) {
+ throw new MethodNotAllowedException(__('Could not add Server in MISP.'));
+ }
+ return $response->getJson()['Server'];
+ }
+
+ private function createUser(array $user, array $params): array
+ {
+ if (strpos($user['email'], '%s') !== false) {
+ $user['email'] = sprintf(
+ $user['email'],
+ \Cake\Utility\Security::randomString(8)
+ );
+ }
+ $params['body'] = $user;
+ $response = $this->postData('/admin/users/add', $params);
+ if (!$response->isOk()) {
+ throw new MethodNotAllowedException(__('Could not add the user in MISP.'));
+ }
+ return $response->getJson()['User'];
}
}
diff --git a/src/Model/Entity/RemoteToolConnection.php b/src/Model/Entity/RemoteToolConnection.php
new file mode 100644
index 0000000..164ddd8
--- /dev/null
+++ b/src/Model/Entity/RemoteToolConnection.php
@@ -0,0 +1,11 @@
+get('Broods');
+ $tools = $broods->queryLocalTools($params['cerebrate_id']);
+ $remoteTool = [];
+ foreach ($tools as $tool) {
+ if ($tool['id'] === intval($params['remote_tool_id'])) {
+ $remoteTool = $tool;
+ }
+ }
+ if (empty($remoteTool)) {
+ throw new NotFoundException(__('Invalid remote tool specified.'));
+ }
+ return $remoteTool;
+ }
+
+ public function encodeConnectionChoice(array $params): array
+ {
+ $remoteTool = $this->getRemoteToolById($params);
+ $connections = $this->find()->where(['connector' => $remoteTool['connector']])->toArray();
+ $results = [];
+ foreach ($connections as $connection) {
+ $results[] = [
+ 'id' => $connection->id,
+ 'name' => $connection->name
+ ];
+ }
+ return $results;
+ }
+
+ public function encodeConnection(array $params): array
+ {
+ $params = $this->buildConnectionParams($params);
+ $result = $params['connector'][$params['remote_tool']['connector']]->initiateConnectionWrapper($params);
+ return $result;
+ }
+
+ public function buildConnectionParams(array $params): array
+ {
+ $remote_tool = $this->getRemoteToolById($params);
+ $broods = \Cake\ORM\TableRegistry::getTableLocator()->get('Broods');
+ $remote_cerebrate = $broods->find()->where(['id' => $params['cerebrate_id']])->first();
+ $connector = $this->getConnectors($remote_tool['connector']);
+ $connection = $this->find()->where(['id' => $params['local_tool_id']])->first();
+ $remote_org = $broods->Organisations->find()->where(['id' => $remote_cerebrate['organisation_id']])->first();
+ if (empty($connector[$remote_tool['connector']])) {
+ throw new NotFoundException(__('No valid connector found for the remote tool.'));
+ }
+ return [
+ 'remote_cerebrate' => $remote_cerebrate,
+ 'remote_org' => $remote_org,
+ 'remote_tool' => $remote_tool,
+ 'connector' => $connector,
+ 'connection' => $connection,
+ //'message' =>
+ ];
+ }
+
+ public function appendLocalToolConnections(int $brood_id, array $tool): array
+ {
+ $remoteToolConnections = \Cake\ORM\TableRegistry::getTableLocator()->get('RemoteToolConnections');
+ $connections = $remoteToolConnections->find()->where(['remote_tool_id' => $tool['id'], 'brood_id' => $brood_id])->toArray();
+ $local_tools = [];
+ foreach ($connections as $k => $connection) {
+ $temp = $this->find()->where(['id' => $connection['local_tool_id']])->select(['id', 'name'])->enableHydration(false)->first();
+ $temp['status'] = $connection['status'];
+ $local_tools[] = $temp;
+ }
+ return $local_tools;
+ }
}
diff --git a/src/Model/Table/RemoteToolConnectionsTable.php b/src/Model/Table/RemoteToolConnectionsTable.php
new file mode 100644
index 0000000..7e8cf21
--- /dev/null
+++ b/src/Model/Table/RemoteToolConnectionsTable.php
@@ -0,0 +1,27 @@
+BelongsTo(
+ 'LocalTools'
+ );
+ $this->setDisplayField('id');
+ }
+
+ public function validationDefault(Validator $validator): Validator
+ {
+ return $validator;
+ }
+}
diff --git a/templates/LocalTools/brood_tools.php b/templates/LocalTools/brood_tools.php
index ae41159..d069eca 100644
--- a/templates/LocalTools/brood_tools.php
+++ b/templates/LocalTools/brood_tools.php
@@ -29,6 +29,11 @@ echo $this->element('genericElements/IndexTable/index_table', [
[
'name' => __('Description'),
'data_path' => 'description',
+ ],
+ [
+ 'name' => __('Connected Local Tools'),
+ 'data_path' => 'local_tool',
+ 'element' => 'local_tools_status'
]
],
'title' => __('Local tools made available by the remote Cerebrate'),
@@ -37,8 +42,8 @@ echo $this->element('genericElements/IndexTable/index_table', [
'skip_pagination' => 1,
'actions' => [
[
- 'url' => '/localTools/connectionRequest',
- 'url_params_data_paths' => ['id'],
+ 'open_modal' => sprintf('/localTools/connectionRequest/%s/[onclick_params_data_path]', h($id)),
+ 'modal_params_data_path' => 'id',
'title' => 'Issue a connection request',
'icon' => 'plug'
]
diff --git a/templates/LocalTools/connection_request.php b/templates/LocalTools/connection_request.php
new file mode 100644
index 0000000..8f672e7
--- /dev/null
+++ b/templates/LocalTools/connection_request.php
@@ -0,0 +1,27 @@
+element('genericElements/Form/genericForm', [
+ 'data' => [
+ 'description' => __(
+ 'Connect the remote tool ({0}) on remote brood ({1}) using the local tool selected below.',
+ h($data['remoteTool']['name']),
+ h($data['remoteCerebrate']['name'])
+ ),
+ 'model' => 'LocalTools',
+ 'fields' => [
+ [
+ 'field' => 'local_tool_id',
+ 'options' => $dropdown,
+ 'type' => 'dropdown'
+ ]
+ ],
+ 'submit' => [
+ 'action' => $this->request->getParam('action')
+ ]
+ ]
+ ]);
+?>
+
diff --git a/templates/element/genericElements/IndexTable/Fields/local_tools_status.php b/templates/element/genericElements/IndexTable/Fields/local_tools_status.php
new file mode 100644
index 0000000..118b915
--- /dev/null
+++ b/templates/element/genericElements/IndexTable/Fields/local_tools_status.php
@@ -0,0 +1,13 @@
+Hash->extract($row, 'local_tools');
+ $output = [];
+ foreach ($tools as $tool) {
+ $output[] = sprintf(
+ '%s: %s',
+ h($tool['id']),
+ h($tool['name']),
+ h($tool['status'])
+ );
+ }
+ echo implode('
', $output);
+?>