mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
154 lines
6.3 KiB
PHP
154 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace Tests\E2E\Services\Project;
|
|
|
|
use Tests\E2E\Client;
|
|
use Tests\E2E\Scopes\ProjectCustom;
|
|
use Tests\E2E\Scopes\Scope;
|
|
use Tests\E2E\Scopes\SideServer;
|
|
use Utopia\Database\Helpers\ID;
|
|
|
|
class PoliciesPasswordHistoryIntegrationTest extends Scope
|
|
{
|
|
use ProjectCustom;
|
|
use SideServer;
|
|
|
|
public function testPasswordHistoryIntegration(): void
|
|
{
|
|
$projectId = $this->getProject()['$id'];
|
|
$apiKey = $this->getProject()['apiKey'];
|
|
|
|
$serverHeaders = [
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $projectId,
|
|
'x-appwrite-key' => $apiKey,
|
|
'x-appwrite-response-format' => '1.9.4',
|
|
];
|
|
|
|
// Step 1: Enable password history policy with limit 3
|
|
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/password-history', $serverHeaders, [
|
|
'total' => 3,
|
|
]);
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
$this->assertSame(3, $response['body']['authPasswordHistory']);
|
|
|
|
$firstPassword = 'firstpassword';
|
|
$secondPassword = 'secondpassword';
|
|
$thirdPassword = 'thirdpassword';
|
|
$fourthPassword = 'fourthpassword';
|
|
|
|
// Step 2: Sign up user with firstpassword (policy on, so signup populates history)
|
|
$email = 'history_' . uniqid() . '@localhost.test';
|
|
$userId = ID::unique();
|
|
|
|
$account = $this->client->call(Client::METHOD_POST, '/account', [
|
|
'origin' => 'http://localhost',
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $projectId,
|
|
], [
|
|
'userId' => $userId,
|
|
'email' => $email,
|
|
'password' => $firstPassword,
|
|
'name' => 'History User',
|
|
]);
|
|
$this->assertSame(201, $account['headers']['status-code']);
|
|
|
|
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', [
|
|
'origin' => 'http://localhost',
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $projectId,
|
|
], [
|
|
'email' => $email,
|
|
'password' => $firstPassword,
|
|
]);
|
|
$this->assertSame(201, $session['headers']['status-code']);
|
|
$sessionCookie = $session['cookies']['a_session_' . $projectId];
|
|
|
|
$clientHeaders = [
|
|
'origin' => 'http://localhost',
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $projectId,
|
|
'cookie' => 'a_session_' . $projectId . '=' . $sessionCookie,
|
|
];
|
|
|
|
// Change password: first -> second
|
|
$response = $this->client->call(Client::METHOD_PATCH, '/account/password', $clientHeaders, [
|
|
'password' => $secondPassword,
|
|
'oldPassword' => $firstPassword,
|
|
]);
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
// Change password: second -> third
|
|
$response = $this->client->call(Client::METHOD_PATCH, '/account/password', $clientHeaders, [
|
|
'password' => $thirdPassword,
|
|
'oldPassword' => $secondPassword,
|
|
]);
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
// Step 3: Attempt to reuse each of the 3 previous passwords - all should fail
|
|
foreach ([$firstPassword, $secondPassword, $thirdPassword] as $reused) {
|
|
$response = $this->client->call(Client::METHOD_PATCH, '/account/password', $clientHeaders, [
|
|
'password' => $reused,
|
|
'oldPassword' => $thirdPassword,
|
|
]);
|
|
$this->assertSame(400, $response['headers']['status-code'], 'Reusing password "' . $reused . '" should be blocked by history policy');
|
|
$this->assertSame('password_recently_used', $response['body']['type']);
|
|
}
|
|
|
|
// Step 4: Setting fourthpassword succeeds
|
|
$response = $this->client->call(Client::METHOD_PATCH, '/account/password', $clientHeaders, [
|
|
'password' => $fourthPassword,
|
|
'oldPassword' => $thirdPassword,
|
|
]);
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
|
|
// Verify the new password works by signing in again
|
|
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', [
|
|
'origin' => 'http://localhost',
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $projectId,
|
|
], [
|
|
'email' => $email,
|
|
'password' => $fourthPassword,
|
|
]);
|
|
$this->assertSame(201, $session['headers']['status-code']);
|
|
|
|
// Step 5: Disable password history policy
|
|
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/password-history', $serverHeaders, [
|
|
'total' => null,
|
|
]);
|
|
$this->assertSame(200, $response['headers']['status-code']);
|
|
$this->assertSame(0, $response['body']['authPasswordHistory']);
|
|
|
|
// Step 6: With policy off, reusing any previous password should succeed, as should setting a brand new one.
|
|
// oldPassword must match current password, so walk through each previous password sequentially.
|
|
$fifthPassword = 'fifthpassword';
|
|
$chain = [
|
|
[$fourthPassword, $firstPassword],
|
|
[$firstPassword, $secondPassword],
|
|
[$secondPassword, $thirdPassword],
|
|
[$thirdPassword, $fourthPassword],
|
|
[$fourthPassword, $fifthPassword],
|
|
];
|
|
|
|
foreach ($chain as [$current, $next]) {
|
|
$response = $this->client->call(Client::METHOD_PATCH, '/account/password', $clientHeaders, [
|
|
'password' => $next,
|
|
'oldPassword' => $current,
|
|
]);
|
|
$this->assertSame(200, $response['headers']['status-code'], 'Changing password from "' . $current . '" to "' . $next . '" should succeed with history policy disabled');
|
|
}
|
|
|
|
// Verify the final password works by signing in
|
|
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', [
|
|
'origin' => 'http://localhost',
|
|
'content-type' => 'application/json',
|
|
'x-appwrite-project' => $projectId,
|
|
], [
|
|
'email' => $email,
|
|
'password' => $fifthPassword,
|
|
]);
|
|
$this->assertSame(201, $session['headers']['status-code']);
|
|
}
|
|
}
|