From 6c00b5d26b0185b057837973ad77100fb5917cda Mon Sep 17 00:00:00 2001 From: Niraj Acharya Date: Tue, 26 Nov 2024 17:13:14 +0545 Subject: [PATCH 1/2] add test for creating auth tocken for an app using api --- .drone.star | 10 ++ .../acceptance/TestHelpers/AuthAppHelper.php | 94 ++++++++++++ tests/acceptance/bootstrap/AuthAppContext.php | 138 ++++++++++++++++++ tests/acceptance/config/behat.yml | 8 + .../features/apiAuthApp/token.feature | 62 ++++++++ 5 files changed, 312 insertions(+) create mode 100644 tests/acceptance/TestHelpers/AuthAppHelper.php create mode 100644 tests/acceptance/bootstrap/AuthAppContext.php create mode 100644 tests/acceptance/features/apiAuthApp/token.feature diff --git a/.drone.star b/.drone.star index 9fda683de2..7fa4f5a7a8 100644 --- a/.drone.star +++ b/.drone.star @@ -242,6 +242,16 @@ config = { "GATEWAY_GRPC_ADDR": "0.0.0.0:9142", }, }, + "authApp": { + "suites": [ + "apiAuthApp", + ], + "skip": False, + "extraServerEnvironment": { + "OCIS_ADD_RUN_SERVICES": "auth-app", + "PROXY_ENABLE_APP_AUTH": True, + }, + }, "cliCommands": { "suites": [ "cliCommands", diff --git a/tests/acceptance/TestHelpers/AuthAppHelper.php b/tests/acceptance/TestHelpers/AuthAppHelper.php new file mode 100644 index 0000000000..f308280b24 --- /dev/null +++ b/tests/acceptance/TestHelpers/AuthAppHelper.php @@ -0,0 +1,94 @@ + + * @copyright Copyright (c) 2024 Niraj Acharya niraj@jankaritech.com + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, + * as published by the Free Software Foundation; + * either version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * + */ + +namespace TestHelpers; + +use Psr\Http\Message\ResponseInterface; + +/** + * A helper class for managing Auth App API requests + */ +class AuthAppHelper { + + /** + * @return string + */ + public static function getAuthAppEndpoint():string { + return "/auth-app/tokens"; + } + + /** + * @param string $baseUrl + * @param string $user + * @param string $password + * + * @return ResponseInterface + */ + public static function listAllAppAuthToken(string $baseUrl, string $user, string $password) : ResponseInterface { + $url = $baseUrl . self::getAuthAppEndpoint(); + return HttpRequestHelper::sendRequest( + $url, + null, + "GET", + $user, + $password, + ); + } + + /** + * @param string $baseUrl + * @param string $user + * @param string $password + * @param string $expiration + * + * @return ResponseInterface + */ + public static function createAppAuthToken(string $baseUrl, string $user, string $password, string $expiration) : ResponseInterface { + $url = $baseUrl . self::getAuthAppEndpoint() . "?expiry=$expiration"; + return HttpRequestHelper::sendRequest( + $url, + null, + "POST", + $user, + $password, + ); + } + + /** + * @param string $baseUrl + * @param string $user + * @param string $password + * @param string $token + * + * @return ResponseInterface + */ + public static function deleteAppAuthToken(string $baseUrl, string $user, string $password, string $token) : ResponseInterface { + $url = $baseUrl . self::getAuthAppEndpoint() . "?token=$token"; + return HttpRequestHelper::sendRequest( + $url, + null, + "DELETE", + $user, + $password, + ); + } +} diff --git a/tests/acceptance/bootstrap/AuthAppContext.php b/tests/acceptance/bootstrap/AuthAppContext.php new file mode 100644 index 0000000000..50f77a28ad --- /dev/null +++ b/tests/acceptance/bootstrap/AuthAppContext.php @@ -0,0 +1,138 @@ + + * @copyright Copyright (c) 2024 Niraj Acharya niraj@jankaritech.com + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, + * as published by the Free Software Foundation; + * either version 3 of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * + */ + +use Behat\Behat\Context\Context; +use Behat\Behat\Hook\Scope\BeforeScenarioScope; +use TestHelpers\BehatHelper; +use GuzzleHttp\Exception\GuzzleException; +use TestHelpers\AuthAppHelper; + +require_once 'bootstrap.php'; + +/** + * AuthApp context + */ +class AuthAppContext implements Context { + private FeatureContext $featureContext; + private array $allCreatedTokens = []; + + /** + * @BeforeScenario + * + * @param BeforeScenarioScope $scope + * + * @return void + */ + public function before(BeforeScenarioScope $scope): void { + // Get the environment + $environment = $scope->getEnvironment(); + // Get all the contexts you need in this context + $this->featureContext = BehatHelper::getContext($scope, $environment, 'FeatureContext'); + } + + /** + * @When the administrator creates app token with expiration time :expiration using the API + * + * @param string $expiration + * + * @return void + */ + public function theAdministratorCreatesAppTokenForUserWithExpirationTimeUsingTheApi(string $expiration): void { + $this->featureContext->setResponse( + AuthAppHelper::createAppAuthToken( + $this->featureContext->getBaseUrl(), + $this->featureContext->getAdminUsername(), + $this->featureContext->getAdminPassword(), + $expiration, + ) + ); + } + + /** + * @Given the administrator has created app token with expiration time :expiration using the API + * + * @param string $expiration + * + * @return void + */ + public function theAdministratorHasCreatedAppTokenWithExpirationTimeUsingTheApi(string $expiration): void { + $response = AuthAppHelper::createAppAuthToken( + $this->featureContext->getBaseUrl(), + $this->featureContext->getAdminUsername(), + $this->featureContext->getAdminPassword(), + $expiration, + ); + $this->featureContext->theHTTPStatusCodeShouldBe(200, "", $response); + } + + /** + * @When admin lists all created tokens + * + * @return void + */ + public function adminListsAllCreatedTokens(): void { + $this->featureContext->setResponse( + AuthAppHelper::listAllAppAuthToken( + $this->featureContext->getBaseUrl(), + $this->featureContext->getAdminUsername(), + $this->featureContext->getAdminPassword(), + ) + ); + } + + /** + * @return void + */ + public function deleteAllToken() : void { + $response = AuthAppHelper::listAllAppAuthToken( + $this->featureContext->getBaseUrl(), + $this->featureContext->getAdminUsername(), + $this->featureContext->getAdminPassword(), + ); + $this->featureContext->theHTTPStatusCodeShouldBe(200, "", $response); + $rawBody = $response->getBody()->getContents(); + $tokens = json_decode($rawBody); + foreach ($tokens as $token) { + $this->featureContext->theHTTPStatusCodeShouldBe( + 200, + "", + AuthAppHelper::deleteAppAuthToken( + $this->featureContext->getBaseUrl(), + $this->featureContext->getAdminUsername(), + $this->featureContext->getAdminPassword(), + $token->token + ) + ); + } + } + + /** + * @AfterScenario + * + * @return void + * + * @throws Exception|GuzzleException + */ + public function cleanDataAfterTests(): void { + $this->deleteAllToken(); + } +} diff --git a/tests/acceptance/config/behat.yml b/tests/acceptance/config/behat.yml index 8d35def18d..04a57217c7 100644 --- a/tests/acceptance/config/behat.yml +++ b/tests/acceptance/config/behat.yml @@ -424,6 +424,14 @@ default: - FeatureContext: *common_feature_context_params - OcisConfigContext: + apiAuthApp: + paths: + - "%paths.base%/../features/apiAuthApp" + context: *common_ldap_suite_context + contexts: + - FeatureContext: *common_feature_context_params + - AuthAppContext: + cliCommands: paths: - "%paths.base%/../features/cliCommands" diff --git a/tests/acceptance/features/apiAuthApp/token.feature b/tests/acceptance/features/apiAuthApp/token.feature new file mode 100644 index 0000000000..5b2673d84c --- /dev/null +++ b/tests/acceptance/features/apiAuthApp/token.feature @@ -0,0 +1,62 @@ +Feature: create auth token + As a admin + I want to create App Tokens + So that I can use 3rd party apps + + + Scenario: admin creates app token + When the administrator creates app token with expiration time "72h" using the API + Then the HTTP status code should be "200" + And the JSON data of the response should match + """ + { + "type": "object", + "required": [ + "token", + "expiration_date", + "created_date", + "label" + ], + "properties": { + "token": { + "type": "string", + "pattern": "^[a-zA-Z0-9]{16}$" + }, + "label": { + "const": "Generated via API" + } + } + } + """ + + + Scenario: admin lists app token + Given the administrator has created app token with expiration time "72h" using the API + When admin lists all created tokens + Then the HTTP status code should be "200" + And the JSON data of the response should match + """ + { + "type": "array", + "minItems": 1, + "maxItems": 1, + "items": { + "type": "object", + "required": [ + "token", + "expiration_date", + "created_date", + "label" + ], + "properties": { + "token": { + "type": "string", + "pattern": "^\\$2a\\$11\\$[A-Za-z0-9./]{53}$" + }, + "label": { + "const": "Generated via API" + } + } + } + } + """ From 7546e476be47d2e3e0a4f582e2ac0fe32ac74170 Mon Sep 17 00:00:00 2001 From: Saw-jan Date: Thu, 5 Dec 2024 10:42:34 +0545 Subject: [PATCH 2/2] test: allow items check for multiple array items --- .drone.star | 1 + .../acceptance/TestHelpers/AuthAppHelper.php | 9 ++- tests/acceptance/bootstrap/AuthAppContext.php | 68 +++++-------------- tests/acceptance/bootstrap/FeatureContext.php | 13 ++-- .../features/apiAuthApp/token.feature | 21 +++--- 5 files changed, 44 insertions(+), 68 deletions(-) diff --git a/.drone.star b/.drone.star index 7fa4f5a7a8..2b9be9b12e 100644 --- a/.drone.star +++ b/.drone.star @@ -247,6 +247,7 @@ config = { "apiAuthApp", ], "skip": False, + "withRemotePhp": [True], "extraServerEnvironment": { "OCIS_ADD_RUN_SERVICES": "auth-app", "PROXY_ENABLE_APP_AUTH": True, diff --git a/tests/acceptance/TestHelpers/AuthAppHelper.php b/tests/acceptance/TestHelpers/AuthAppHelper.php index f308280b24..61d76d5ddd 100644 --- a/tests/acceptance/TestHelpers/AuthAppHelper.php +++ b/tests/acceptance/TestHelpers/AuthAppHelper.php @@ -28,11 +28,10 @@ use Psr\Http\Message\ResponseInterface; * A helper class for managing Auth App API requests */ class AuthAppHelper { - /** * @return string */ - public static function getAuthAppEndpoint():string { + public static function getAuthAppEndpoint(): string { return "/auth-app/tokens"; } @@ -43,7 +42,7 @@ class AuthAppHelper { * * @return ResponseInterface */ - public static function listAllAppAuthToken(string $baseUrl, string $user, string $password) : ResponseInterface { + public static function listAllAppAuthTokensForUser(string $baseUrl, string $user, string $password): ResponseInterface { $url = $baseUrl . self::getAuthAppEndpoint(); return HttpRequestHelper::sendRequest( $url, @@ -62,7 +61,7 @@ class AuthAppHelper { * * @return ResponseInterface */ - public static function createAppAuthToken(string $baseUrl, string $user, string $password, string $expiration) : ResponseInterface { + public static function createAppAuthToken(string $baseUrl, string $user, string $password, string $expiration): ResponseInterface { $url = $baseUrl . self::getAuthAppEndpoint() . "?expiry=$expiration"; return HttpRequestHelper::sendRequest( $url, @@ -81,7 +80,7 @@ class AuthAppHelper { * * @return ResponseInterface */ - public static function deleteAppAuthToken(string $baseUrl, string $user, string $password, string $token) : ResponseInterface { + public static function deleteAppAuthToken(string $baseUrl, string $user, string $password, string $token): ResponseInterface { $url = $baseUrl . self::getAuthAppEndpoint() . "?token=$token"; return HttpRequestHelper::sendRequest( $url, diff --git a/tests/acceptance/bootstrap/AuthAppContext.php b/tests/acceptance/bootstrap/AuthAppContext.php index 50f77a28ad..ad95dc02db 100644 --- a/tests/acceptance/bootstrap/AuthAppContext.php +++ b/tests/acceptance/bootstrap/AuthAppContext.php @@ -33,7 +33,6 @@ require_once 'bootstrap.php'; */ class AuthAppContext implements Context { private FeatureContext $featureContext; - private array $allCreatedTokens = []; /** * @BeforeScenario @@ -50,89 +49,56 @@ class AuthAppContext implements Context { } /** - * @When the administrator creates app token with expiration time :expiration using the API + * @When user :user creates app token with expiration time :expiration using the auth-app API * + * @param string $user * @param string $expiration * * @return void */ - public function theAdministratorCreatesAppTokenForUserWithExpirationTimeUsingTheApi(string $expiration): void { + public function userCreatesAppTokenWithExpirationTimeUsingTheAuthAppApi(string $user, string $expiration): void { $this->featureContext->setResponse( AuthAppHelper::createAppAuthToken( $this->featureContext->getBaseUrl(), - $this->featureContext->getAdminUsername(), - $this->featureContext->getAdminPassword(), + $this->featureContext->getActualUsername($user), + $this->featureContext->getPasswordForUser($user), $expiration, ) ); } /** - * @Given the administrator has created app token with expiration time :expiration using the API + * @Given user :user has created app token with expiration time :expiration * + * @param string $user * @param string $expiration * * @return void */ - public function theAdministratorHasCreatedAppTokenWithExpirationTimeUsingTheApi(string $expiration): void { + public function userHasCreatedAppTokenWithExpirationTime(string $user, string $expiration): void { $response = AuthAppHelper::createAppAuthToken( $this->featureContext->getBaseUrl(), - $this->featureContext->getAdminUsername(), - $this->featureContext->getAdminPassword(), + $this->featureContext->getActualUsername($user), + $this->featureContext->getPasswordForUser($user), $expiration, ); $this->featureContext->theHTTPStatusCodeShouldBe(200, "", $response); } /** - * @When admin lists all created tokens + * @When user :user lists all created tokens using the auth-app API + * + * @param string $user * * @return void */ - public function adminListsAllCreatedTokens(): void { + public function userListsAllCreatedTokensUsingTheAuthAppApi(string $user): void { $this->featureContext->setResponse( - AuthAppHelper::listAllAppAuthToken( + AuthAppHelper::listAllAppAuthTokensForUser( $this->featureContext->getBaseUrl(), - $this->featureContext->getAdminUsername(), - $this->featureContext->getAdminPassword(), + $this->featureContext->getActualUsername($user), + $this->featureContext->getPasswordForUser($user), ) ); } - - /** - * @return void - */ - public function deleteAllToken() : void { - $response = AuthAppHelper::listAllAppAuthToken( - $this->featureContext->getBaseUrl(), - $this->featureContext->getAdminUsername(), - $this->featureContext->getAdminPassword(), - ); - $this->featureContext->theHTTPStatusCodeShouldBe(200, "", $response); - $rawBody = $response->getBody()->getContents(); - $tokens = json_decode($rawBody); - foreach ($tokens as $token) { - $this->featureContext->theHTTPStatusCodeShouldBe( - 200, - "", - AuthAppHelper::deleteAppAuthToken( - $this->featureContext->getBaseUrl(), - $this->featureContext->getAdminUsername(), - $this->featureContext->getAdminPassword(), - $token->token - ) - ); - } - } - - /** - * @AfterScenario - * - * @return void - * - * @throws Exception|GuzzleException - */ - public function cleanDataAfterTests(): void { - $this->deleteAllToken(); - } } diff --git a/tests/acceptance/bootstrap/FeatureContext.php b/tests/acceptance/bootstrap/FeatureContext.php index 1b11fe8d34..b7144e1e97 100644 --- a/tests/acceptance/bootstrap/FeatureContext.php +++ b/tests/acceptance/bootstrap/FeatureContext.php @@ -1132,9 +1132,11 @@ class FeatureContext extends BehatVariablesContext { Assert::fail("'$validator' should be an object not an array"); } Assert::assertFalse($value->allOf || $value->anyOf, "'allOf' and 'anyOf' are not allowed in array"); - Assert::assertNotNull($value->oneOf, "'oneOf' is required to assert more than one elements"); - Assert::assertTrue(\is_array($value->oneOf), "'oneOf' should be an array"); - Assert::assertEquals($schemaObj->maxItems, \count($value->oneOf), "Expected " . $schemaObj->maxItems . " 'oneOf' items but got " . \count($value->oneOf)); + if ($value->oneOf) { + Assert::assertNotNull($value->oneOf, "'oneOf' is required to assert more than one elements"); + Assert::assertTrue(\is_array($value->oneOf), "'oneOf' should be an array"); + Assert::assertEquals($schemaObj->maxItems, \count($value->oneOf), "Expected " . $schemaObj->maxItems . " 'oneOf' items but got " . \count($value->oneOf)); + } } Assert::assertTrue(\is_object($value), "'$validator' should be an object when expecting 1 element"); break; @@ -1226,7 +1228,7 @@ class FeatureContext extends BehatVariablesContext { $errors = $this->getJsonSchemaErrors($e); $messages = ["JSON Schema validation failed:"]; - $previousPointer = ''; + $previousPointer = null; $errorCount = 0; foreach ($errors as $error) { $expected = $error->constraint; @@ -1236,6 +1238,9 @@ class FeatureContext extends BehatVariablesContext { $dataPointer = \str_replace("/", ".", \trim($error->getDataPointer(), "/")); $pointer = \str_contains($schemaPointer, "additionalProperties") ? $dataPointer : $schemaPointer; + if ($pointer === '') { + $pointer = "{root}"; + } if ($pointer === $previousPointer) { continue; } diff --git a/tests/acceptance/features/apiAuthApp/token.feature b/tests/acceptance/features/apiAuthApp/token.feature index 5b2673d84c..53de35f218 100644 --- a/tests/acceptance/features/apiAuthApp/token.feature +++ b/tests/acceptance/features/apiAuthApp/token.feature @@ -1,11 +1,14 @@ Feature: create auth token - As a admin + As a user I want to create App Tokens So that I can use 3rd party apps + Background: + Given user "Alice" has been created with default attributes - Scenario: admin creates app token - When the administrator creates app token with expiration time "72h" using the API + + Scenario: user creates app token + When user "Alice" creates app token with expiration time "72h" using the auth-app API Then the HTTP status code should be "200" And the JSON data of the response should match """ @@ -30,16 +33,18 @@ Feature: create auth token """ - Scenario: admin lists app token - Given the administrator has created app token with expiration time "72h" using the API - When admin lists all created tokens + Scenario: user lists app tokens + Given user "Alice" has created app token with expiration time "72h" + And user "Alice" has created app token with expiration time "2h" + When user "Alice" lists all created tokens using the auth-app API Then the HTTP status code should be "200" And the JSON data of the response should match """ { "type": "array", - "minItems": 1, - "maxItems": 1, + "minItems": 2, + "maxItems": 2, + "uniqueItems": true, "items": { "type": "object", "required": [