add: add basic api coverage of inbox processor endpoint, extend openapi spec

pull/80/head
Luciano Righetti 2022-01-13 16:34:43 +01:00
parent 5906f6d2c7
commit c8fd8f4a62
4 changed files with 391 additions and 1 deletions

View File

@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
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 function init(): void
{
$faker = \Faker\Factory::create();
$this->records = [
[
'id' => self::INBOX_USER_REGISTRATION_ID,
'uuid' => $faker->uuid(),
'scope' => 'User',
'action' => 'Registration',
'title' => 'User account creation requested for foo@bar.com',
'origin' => '::1',
'comment' => null,
'description' => 'Handle user account for this cerebrate instance',
'user_id' => UsersFixture::USER_ADMIN_ID,
'data' => [
'email' => 'foo@bar.com',
'password' => '$2y$10$dr5C0MWgBx1723yyws0HPudTqHz4k8wJ1PQ1ApVkNuH64LuZAr\/ve',
],
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
[
'id' => self::INBOX_INCOMING_CONNECTION_REQUEST_ID,
'uuid' => $faker->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,
'data' => [
'connectorName' => 'MispConnector',
'cerebrateURL' => 'http://127.0.0.1',
'local_tool_id' => 1,
'remote_tool_id' => 1,
],
'created' => $faker->dateTime()->getTimestamp(),
'modified' => $faker->dateTime()->getTimestamp()
],
];
parent::init();
}
}

View File

@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Helper\ApiTestTrait;
class CreateInboxEntryApiTest extends TestCase
{
use IntegrationTestTrait;
use ApiTestTrait;
protected const ENDPOINT = '/api/v1/inbox/createEntry';
protected $fixtures = [
'app.Inbox',
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function setUp(): void
{
parent::setUp();
$this->initializeValidator(APP . '../webroot/docs/openapi.yaml');
}
public function testAddUserRegistrationInbox(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
// to avoid $this->request->clientIp() to return null
$_SERVER['REMOTE_ADDR'] = '::1';
$url = sprintf("%s/%s/%s", self::ENDPOINT, 'User', 'Registration');
$this->post(
$url,
[
'email' => 'john@example.com',
'password' => 'Password12345!'
]
);
$this->assertResponseOk();
$this->assertResponseContains('"email": "john@example.com"');
$this->assertDbRecordExists(
'Inbox',
[
'id' => 3, // hacky, but `data` is json string cannot verify the value because of the hashed password
'scope' => 'User',
'action' => 'Registration',
]
);
//TODO: $this->assertRequestMatchesOpenApiSpec();
$this->assertResponseMatchesOpenApiSpec($url, 'post');
}
public function testAddUserRegistrationInboxNotAllowedAsRegularUser(): void
{
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$url = sprintf("%s/%s/%s", self::ENDPOINT, 'User', 'Registration');
$this->post(
$url,
[
'email' => 'john@example.com',
'password' => 'Password12345!'
]
);
$this->assertResponseCode(405);
$this->assertDbRecordNotExists('Inbox', ['id' => 3]);
//TODO: $this->assertRequestMatchesOpenApiSpec();
$this->assertResponseMatchesOpenApiSpec($url, 'post');
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Users;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\InboxFixture;
use App\Test\Helper\ApiTestTrait;
class IndexInboxApiTest extends TestCase
{
use IntegrationTestTrait;
use ApiTestTrait;
protected const ENDPOINT = '/api/v1/inbox/index';
protected $fixtures = [
'app.Inbox',
'app.Organisations',
'app.Individuals',
'app.Roles',
'app.Users',
'app.AuthKeys'
];
public function setUp(): void
{
parent::setUp();
$this->initializeValidator(APP . '../webroot/docs/openapi.yaml');
}
public function testIndexInbox(): void
{
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$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));
// TODO: $this->assertRequestMatchesOpenApiSpec();
$this->assertResponseMatchesOpenApiSpec(self::ENDPOINT);
}
}

View File

@ -17,6 +17,8 @@ tags:
description: "Organisations can be equivalent to legal entities or specific individual teams within such entities. Their purpose is to relate individuals to their affiliations and for release control of information using the Trust Circles." description: "Organisations can be equivalent to legal entities or specific individual teams within such entities. Their purpose is to relate individuals to their affiliations and for release control of information using the Trust Circles."
- name: Tags - name: Tags
description: "Tags can be attached to entity to quickly classify them, allowing further filtering and searches." description: "Tags can be attached to entity to quickly classify them, allowing further filtering and searches."
- name: Inbox
description: "Inbox messages represent A list of requests to be manually processed."
paths: paths:
/api/v1/individuals/index: /api/v1/individuals/index:
@ -369,6 +371,42 @@ paths:
default: default:
$ref: "#/components/responses/ApiErrorResponse" $ref: "#/components/responses/ApiErrorResponse"
/api/v1/inbox/index:
get:
summary: "Get inbox list"
operationId: getinbox
tags:
- Inbox
parameters:
- $ref: "#/components/parameters/quickFilter"
responses:
"200":
$ref: "#/components/responses/InboxListResponse"
"403":
$ref: "#/components/responses/UnauthorizedApiErrorResponse"
"405":
$ref: "#/components/responses/MethodNotAllowedApiErrorResponse"
default:
$ref: "#/components/responses/ApiErrorResponse"
/api/v1/inbox/createEntry/User/Registration:
post:
summary: "Create user registration inbox entry"
operationId: createInboxEntry
tags:
- Inbox
requestBody:
$ref: "#/components/requestBodies/CreateUserRegistrationInboxEntryRequest"
responses:
"200":
$ref: "#/components/responses/CreateUserRegistrationInboxEntryResponse"
"403":
$ref: "#/components/responses/UnauthorizedApiErrorResponse"
"405":
$ref: "#/components/responses/MethodNotAllowedApiErrorResponse"
default:
$ref: "#/components/responses/ApiErrorResponse"
components: components:
schemas: schemas:
# General # General
@ -615,6 +653,109 @@ components:
perm_org_admin: perm_org_admin:
type: boolean type: boolean
# Inbox
InboxScope:
type: string
enum:
- "User"
- "LocalTool"
InboxAction:
type: string
enum:
- "Registration"
- "IncomingConnectionRequest"
- "AcceptedRequest"
- "DeclinedRequest"
InboxTitle:
type: string
InboxOrigin:
type: string
InboxComment:
type: string
nullable: true
InboxDescription:
type: string
nullable: true
Inbox:
type: object
properties:
id:
$ref: "#/components/schemas/ID"
uuid:
$ref: "#/components/schemas/UUID"
scope:
$ref: "#/components/schemas/InboxScope"
action:
$ref: "#/components/schemas/InboxAction"
title:
$ref: "#/components/schemas/InboxTitle"
origin:
$ref: "#/components/schemas/InboxOrigin"
comment:
$ref: "#/components/schemas/InboxComment"
description:
$ref: "#/components/schemas/InboxDescription"
user_id:
$ref: "#/components/schemas/ID"
created:
$ref: "#/components/schemas/DateTime"
modified:
$ref: "#/components/schemas/DateTime"
UserRegistrationInbox:
type: object
allOf:
- $ref: "#/components/schemas/Inbox"
- type: object
properties:
data:
type: object
properties:
email:
type: string
format: email
password:
type: string
user:
$ref: "#/components/schemas/User"
local_tool_connector_name:
type: string
nullable: true
IncomingConnectionRequestInbox:
type: object
allOf:
- $ref: "#/components/schemas/Inbox"
- type: object
properties:
data:
type: object
properties:
connectorName:
type: string
enum:
- "MispConnector"
cerebrateURL:
type: string
example: "http://192.168.0.1"
local_tool_id:
type: integer
remote_tool_id:
type: integer
InboxList:
type: array
items:
anyOf:
- $ref: "#/components/schemas/UserRegistrationInbox"
- $ref: "#/components/schemas/IncomingConnectionRequestInbox"
# Errors # Errors
ApiError: ApiError:
type: object type: object
@ -685,7 +826,7 @@ components:
parameters: parameters:
individualId: individualId:
name: userId name: individualId
in: path in: path
description: "Numeric ID of the User" description: "Numeric ID of the User"
required: true required: true
@ -876,6 +1017,20 @@ components:
description: "Stringified JSON array of the tag names to remove." description: "Stringified JSON array of the tag names to remove."
example: '["red"]' example: '["red"]'
# Inbox
CreateUserRegistrationInboxEntryRequest:
description: "Create user registration inbox entry request"
content:
application/json:
schema:
type: object
properties:
email:
type: string
format: email
password:
type: string
responses: responses:
# Individuals # Individuals
IndividualResponse: IndividualResponse:
@ -937,6 +1092,52 @@ components:
schema: schema:
$ref: "#/components/schemas/TagList" $ref: "#/components/schemas/TagList"
# Inbox
UserRegistrationInboxResponse:
description: "User registration inbox response"
content:
application/json:
schema:
$ref: "#/components/schemas/UserRegistrationInbox"
IncomingConnectionRequestInboxResponse:
description: "Incoming connection request inbox response"
content:
application/json:
schema:
$ref: "#/components/schemas/IncomingConnectionRequestInbox"
InboxListResponse:
description: "Inbox list response"
content:
application/json:
schema:
$ref: "#/components/schemas/InboxList"
CreateUserRegistrationInboxEntryResponse:
description: "Inbox response"
content:
application/json:
schema:
type: object
properties:
data:
allOf:
- $ref: "#/components/schemas/UserRegistrationInbox"
- properties:
local_tool_connector_name:
type: string
nullable: true
success:
type: boolean
message:
type: string
example: "User account creation requested. Please wait for an admin to approve your account."
errors:
type: array
items:
type: object
# Errors # Errors
ApiErrorResponse: ApiErrorResponse:
description: "Unexpected API error" description: "Unexpected API error"