From b1ad454db8eac8c639569af157ca933948f89a5c Mon Sep 17 00:00:00 2001 From: Luciano Righetti Date: Tue, 18 Jan 2022 14:29:27 +0100 Subject: [PATCH] add: api tests for /encryptionkeys, extend openapi spec --- tests/Fixture/EncryptionKeysFixture.php | 133 ++++++++++++++++++ .../DeleteEncryptionKeyApiTest.php | 54 +++++++ .../IndexEncryptionKeysApiTest.php | 40 ++++++ webroot/docs/openapi.yaml | 128 ++++++++++++++++- 4 files changed, 352 insertions(+), 3 deletions(-) create mode 100644 tests/Fixture/EncryptionKeysFixture.php create mode 100644 tests/TestCase/Api/EncryptionKeys/DeleteEncryptionKeyApiTest.php create mode 100644 tests/TestCase/Api/EncryptionKeys/IndexEncryptionKeysApiTest.php diff --git a/tests/Fixture/EncryptionKeysFixture.php b/tests/Fixture/EncryptionKeysFixture.php new file mode 100644 index 0000000..05b92f8 --- /dev/null +++ b/tests/Fixture/EncryptionKeysFixture.php @@ -0,0 +1,133 @@ +records = [ + [ + 'id' => self::ENCRYPTION_KEY_ORG_A_ID, + 'uuid' => $faker->uuid(), + 'type' => self::TYPE_PGP, + 'encryption_key' => $this->getPublicKey(self::KEY_TYPE_EDCH), + 'revoked' => false, + 'expires' => null, + 'owner_id' => OrganisationsFixture::ORGANISATION_A_ID, + 'owner_model' => 'Organisation', + 'created' => $faker->dateTime()->getTimestamp(), + 'modified' => $faker->dateTime()->getTimestamp() + ], + [ + 'id' => self::ENCRYPTION_KEY_ORG_B_ID, + 'uuid' => $faker->uuid(), + 'type' => self::TYPE_PGP, + 'encryption_key' => $this->getPublicKey(self::KEY_TYPE_EDCH), + 'revoked' => false, + 'expires' => null, + 'owner_id' => OrganisationsFixture::ORGANISATION_A_ID, + 'owner_model' => 'Organisation', + 'created' => $faker->dateTime()->getTimestamp(), + 'modified' => $faker->dateTime()->getTimestamp() + ], + ]; + parent::init(); + } + + public function getPublicKey(string $type): string + { + switch ($type) { + case self::KEY_TYPE_EDCH: + return <<setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + $url = sprintf('%s/%d', self::ENDPOINT, EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID); + $this->delete($url); + + $this->assertResponseOk(); + $this->assertDbRecordNotExists('EncryptionKeys', ['id' => EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID]); + //TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec($url, 'delete'); + $this->addWarning('TODO: CRUDComponent::delete() sets some view variables, does not take into account `isRest()`, fix it.'); + } + + public function testDeleteEncryptionKeyNotAllowedAsRegularUser(): void + { + $this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY); + $url = sprintf('%s/%d', self::ENDPOINT, EncryptionKeysFixture::ENCRYPTION_KEY_ORG_B_ID); + $this->delete($url); + + $this->assertResponseCode(405); + $this->assertDbRecordExists('EncryptionKeys', ['id' => EncryptionKeysFixture::ENCRYPTION_KEY_ORG_B_ID]); + //TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec($url, 'delete'); + $this->addWarning('TODO: CRUDComponent::delete() sets some view variables, does not take into account `isRest()`, fix it.'); + } +} diff --git a/tests/TestCase/Api/EncryptionKeys/IndexEncryptionKeysApiTest.php b/tests/TestCase/Api/EncryptionKeys/IndexEncryptionKeysApiTest.php new file mode 100644 index 0000000..0b7cb98 --- /dev/null +++ b/tests/TestCase/Api/EncryptionKeys/IndexEncryptionKeysApiTest.php @@ -0,0 +1,40 @@ +setAuthToken(AuthKeysFixture::ADMIN_API_KEY); + $this->get(self::ENDPOINT); + + $this->assertResponseOk(); + $this->assertResponseContains(sprintf('"id": %d', EncryptionKeysFixture::ENCRYPTION_KEY_ORG_A_ID)); + // TODO: $this->assertRequestMatchesOpenApiSpec(); + $this->assertResponseMatchesOpenApiSpec(self::ENDPOINT); + } +} diff --git a/webroot/docs/openapi.yaml b/webroot/docs/openapi.yaml index f9418b9..c4852eb 100644 --- a/webroot/docs/openapi.yaml +++ b/webroot/docs/openapi.yaml @@ -23,6 +23,8 @@ tags: 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." - name: Broods 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." + - name: EncryptionKeys + description: "Assign encryption keys to the user, used to securely communicate or validate messages coming from the user." paths: /api/v1/individuals/index: @@ -575,7 +577,7 @@ paths: default: $ref: "#/components/responses/ApiErrorResponse" - /api/v1/broods/edit/{sharingGroupId}: + /api/v1/broods/edit/{broodId}: put: summary: "Edit brood" operationId: editBrood @@ -631,6 +633,43 @@ paths: default: $ref: "#/components/responses/ApiErrorResponse" + # EncryptionKeys + /api/v1/encryptionKeys/index: + get: + summary: "Get encryption keys list" + operationId: getEncryptionKeys + tags: + - EncryptionKeys + parameters: + - $ref: "#/components/parameters/quickFilter" + responses: + "200": + $ref: "#/components/responses/EncryptionKeyListResponse" + "403": + $ref: "#/components/responses/UnauthorizedApiErrorResponse" + "405": + $ref: "#/components/responses/MethodNotAllowedApiErrorResponse" + default: + $ref: "#/components/responses/ApiErrorResponse" + + /api/v1/encryptionKeys/delete/{encryptionKeyId}: + delete: + summary: "Delete encryption key by ID" + operationId: deleteEncryptionKeyById + tags: + - EncryptionKeys + parameters: + - $ref: "#/components/parameters/encryptionKeyId" + responses: + "200": + $ref: "#/components/responses/EncryptionKeyResponse" + "403": + $ref: "#/components/responses/UnauthorizedApiErrorResponse" + "405": + $ref: "#/components/responses/MethodNotAllowedApiErrorResponse" + default: + $ref: "#/components/responses/ApiErrorResponse" + components: schemas: # General @@ -658,6 +697,18 @@ components: AuthKey: type: string + ModelName: + type: string + enum: + - "Organisation" + - "User" + - "Individual" + - "EncryptionKey" + - "Role" + - "Tag" + - "SharingGroup" + - "Brood" + # Individuals IndividualFirstName: type: string @@ -1089,18 +1140,66 @@ components: type: boolean authkey: $ref: "#/components/schemas/AuthKey" + organisation: + $ref: "#/components/schemas/Organisation" created: $ref: "#/components/schemas/DateTime" modified: $ref: "#/components/schemas/DateTime" - organisation: - $ref: "#/components/schemas/Organisation" BroodList: type: array items: $ref: "#/components/schemas/Brood" + # EncryptionKeys + EncryptionKeyType: + type: string + enum: + - "pgp" + - "smime" + + EncryptionKeyValue: + type: string + example: | + -----BEGIN PGP PUBLIC KEY BLOCK----- + ... + -----END PGP PUBLIC KEY BLOCK----- + + EncryptionKeyExpiration: + type: integer + description: "Timestamp or null of there is no expiration" + nullable: true + + EncryptionKey: + type: object + properties: + id: + $ref: "#/components/schemas/ID" + uuid: + $ref: "#/components/schemas/UUID" + type: + $ref: "#/components/schemas/EncryptionKeyType" + encryption_key: + $ref: "#/components/schemas/EncryptionKeyValue" + revoked: + type: boolean + expires: + $ref: "#/components/schemas/EncryptionKeyExpiration" + owner_id: + $ref: "#/components/schemas/ID" + owner_model: + $ref: "#/components/schemas/ModelName" + created: + $ref: "#/components/schemas/DateTime" + modified: + $ref: "#/components/schemas/DateTime" + + EncryptionKeyList: + type: array + items: + $ref: "#/components/schemas/EncryptionKey" + # Errors ApiError: type: object @@ -1210,6 +1309,14 @@ components: schema: $ref: "#/components/schemas/ID" + encryptionKeyId: + name: encryptionKeyId + in: path + description: "Numeric ID of the EncryptionKey" + required: true + schema: + $ref: "#/components/schemas/ID" + quickFilter: name: quickFilter in: query @@ -1659,6 +1766,21 @@ components: type: number format: float + # EncryptionKeys + EncryptionKeyResponse: + description: "Encryption key response" + content: + application/json: + schema: + $ref: "#/components/schemas/EncryptionKey" + + EncryptionKeyListResponse: + description: "Encryption key list response" + content: + application/json: + schema: + $ref: "#/components/schemas/EncryptionKeyList" + # Errors ApiErrorResponse: description: "Unexpected API error"