diff --git a/tests/acceptance/features/bootstrap/CliContext.php b/tests/acceptance/features/bootstrap/CliContext.php new file mode 100644 index 0000000000..8a4f75bcf8 --- /dev/null +++ b/tests/acceptance/features/bootstrap/CliContext.php @@ -0,0 +1,121 @@ + + * @copyright Copyright (c) 2024 Sajan Gurung sajan@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\Hook\Scope\BeforeScenarioScope; +use Behat\Behat\Context\Context; +use PHPUnit\Framework\Assert; +use Psr\Http\Message\ResponseInterface; +use TestHelpers\CliHelper; +use TestHelpers\OcisConfigHelper; + +/** + * CLI context + */ +class CliContext implements Context { + private FeatureContext $featureContext; + + /** + * @BeforeScenario + * + * @param BeforeScenarioScope $scope + * + * @return void + */ + public function setUpScenario(BeforeScenarioScope $scope): void { + // Get the environment + $environment = $scope->getEnvironment(); + // Get all the contexts you need in this context + $this->featureContext = $environment->getContext('FeatureContext'); + } + + /** + * @Given the administrator has stopped the server + * + * @return void + */ + public function theAdministratorHasStoppedTheServer(): void { + $response = OcisConfigHelper::stopOcis(); + $this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response); + } + + /** + * @Given the administrator has started the server + * + * @return void + */ + public function theAdministratorHasStartedTheServer(): void { + $response = OcisConfigHelper::startOcis(); + $this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response); + } + + /** + * @When the administrator resets the password of user :user to :password using the CLI + * + * @param string $user + * @param string $password + * + * @return void + */ + public function theAdministratorResetsThePasswordOfUserUsingTheCLI(string $user, string $password): void { + $command = "idm resetpassword -u $user"; + $body = [ + "command" => $command, + "inputs" => [$password, $password] + ]; + + $this->featureContext->setResponse(CliHelper::runCommand($body)); + $this->featureContext->updateUserPassword($user, $password); + } + + /** + * @Then the command should be successful + * + * @return void + */ + public function theCommandShouldBeSuccessful(): void { + $response = $this->featureContext->getResponse(); + $this->featureContext->theHTTPStatusCodeShouldBe(200, '', $response); + + $jsonResponse = $this->featureContext->getJsonDecodedResponse($response); + + Assert::assertSame("OK", $jsonResponse["status"]); + Assert::assertSame(0, $jsonResponse["exitCode"], "Expected exit code to be 0, but got " . $jsonResponse["exitCode"]); + } + + /** + * @Then /^the command output (should|should not) contain "([^"]*)"$/ + * + * @param string $output + * + * @return void + */ + public function theCommandOutputShouldContain(string $shouldOrNot,string $output): void { + $response = $this->featureContext->getResponse(); + $jsonResponse = $this->featureContext->getJsonDecodedResponse($response); + + if ($shouldOrNot === "should") { + Assert::assertStringContainsString($output, $jsonResponse["message"]); + } else { + Assert::assertStringNotContainsString($output, $jsonResponse["message"]); + } + } +} \ No newline at end of file diff --git a/tests/acceptance/features/bootstrap/FeatureContext.php b/tests/acceptance/features/bootstrap/FeatureContext.php index d558882431..e2ea3a12c1 100644 --- a/tests/acceptance/features/bootstrap/FeatureContext.php +++ b/tests/acceptance/features/bootstrap/FeatureContext.php @@ -43,6 +43,7 @@ use TestHelpers\OcisHelper; use TestHelpers\GraphHelper; use TestHelpers\WebDavHelper; use TestHelpers\SettingsHelper; +use TestHelpers\OcisConfigHelper; require_once 'bootstrap.php'; @@ -655,6 +656,23 @@ class FeatureContext extends BehatVariablesContext { HttpLogger::writeLog(HttpLogger::getScenarioLogPath(), $logMessage); } + /** + * FIRST AfterScenario HOOK + * + * NOTE: This method is called after each scenario having the @env-config tag + * This ensures that the server is running for clean-up purposes + * + * @AfterScenario @env-config + * + * @return void + */ + public function startOcisServer(): void { + $response = OcisConfigHelper::startOcis(); + // 409 is returned if the server is already running + $this->theHTTPStatusCodeShouldBe([200, 409], 'Starting oCIS server', $response); + } + + /** * Get the externally-defined admin username, if any * @@ -1695,6 +1713,24 @@ class FeatureContext extends BehatVariablesContext { return (string)$this->getActualPassword($this->regularUserPassword); } + /** + * @param string $username + * @param string $password + * + * @return void + * @throws Exception + */ + public function updateUserPassword(string $username, string $password): void { + $username = $this->normalizeUsername($username); + if ($username === $this->getAdminUsername()) { + $this->adminPassword = $password; + } elseif (\array_key_exists($username, $this->createdUsers)) { + $this->createdUsers[$username]['password'] = $password; + } else { + throw new Exception("User '$username' not found"); + } + } + /** * Get the display name of the user. * diff --git a/tests/acceptance/features/bootstrap/WebDav.php b/tests/acceptance/features/bootstrap/WebDav.php index 235fa51a40..c4a5ad692a 100644 --- a/tests/acceptance/features/bootstrap/WebDav.php +++ b/tests/acceptance/features/bootstrap/WebDav.php @@ -443,12 +443,13 @@ trait WebDav { * @param string $user * @param string $folder * @param bool|null $isGivenStep + * @param string|null $password * * @return ResponseInterface * @throws JsonException | GuzzleException * @throws GuzzleException | JsonException */ - public function createFolder(string $user, string $folder, ?bool $isGivenStep = false): ResponseInterface { + public function createFolder(string $user, string $folder, ?bool $isGivenStep = false, ?string $password = null): ResponseInterface { $folder = '/' . \ltrim($folder, '/'); return $this->makeDavRequest( $user, @@ -459,7 +460,7 @@ trait WebDav { "files", null, false, - null, + $password, [], null, $isGivenStep @@ -3349,6 +3350,31 @@ trait WebDav { ); } + /** + * @Then user :user should be able to create folder :destination using password :password + * + * @param string $user + * @param string $destination + * @param string $password + * + * @return void + * @throws Exception + */ + public function userShouldBeAbleToCreateFolderUsingPassword(string $user, string $destination, string $password):void { + $user = $this->getActualUsername($user); + $response = $this->createFolder($user, $destination, true, $password); + $this->theHTTPStatusCodeShouldBe( + ["201", "204"], + "HTTP status code was not 201 or 204 while trying to create folder '$destination' for user '$user'", + $response + ); + $this->checkFileOrFolderExistsForUser( + $user, + "folder", + $destination + ); + } + /** * @Then user :user should not be able to create folder :destination * @@ -3369,6 +3395,26 @@ trait WebDav { ); } + /** + * @Then user :user should not be able to create folder :destination using password :password + * + * @param string $user + * @param string $destination + * @param string $password + * + * @return void + * @throws Exception + */ + public function userShouldNotBeAbleToCreateFolderUsingPassword(string $user, string $destination, string $password):void { + $user = $this->getActualUsername($user); + $response = $this->createFolder($user, $destination, false, $password); + $this->theHTTPStatusCodeShouldBeBetween(400, 499, $response); + $this->checkFileOrFolderDoesNotExistsForUser( + $user, + "folder", + $destination + ); + } /** * Old style chunking upload * diff --git a/tests/acceptance/features/cliResetPassword/resetUserPassword.feature b/tests/acceptance/features/cliResetPassword/resetUserPassword.feature new file mode 100644 index 0000000000..a0a314652f --- /dev/null +++ b/tests/acceptance/features/cliResetPassword/resetUserPassword.feature @@ -0,0 +1,17 @@ +@env-config +Feature: reset user password via CLI command + + + Scenario: reset user password + Given the user "Admin" has created a new user with the following attributes: + | userName | Alice | + | displayName | Alice Hansen | + | password | %alt1% | + And the administrator has stopped the server + When the administrator resets the password of user "Alice" to "newpass" using the CLI + Then the command should be successful + And the command output should contain "Password for user 'uid=Alice,ou=users,o=libregraph-idm' updated." + But the command output should not contain "Failed to update user password: entry does not exist" + And the administrator has started the server + And user "Alice" should be able to create folder "newFolder" using password "newpass" + But user "Alice" should not be able to create folder "anotherFolder" using password "%alt1%" \ No newline at end of file