mirror of
https://github.com/owncloud/ocis
synced 2026-04-25 17:25:21 +02:00
The implicite nullable type has been deprecated. This fixes it by explicitely typing every nullable type. PHP is also bumped in composer and drone to v8.4.
2033 lines
55 KiB
PHP
2033 lines
55 KiB
PHP
<?php declare(strict_types=1);
|
|
/**
|
|
* @author Sergio Bertolin <sbertolin@owncloud.com>
|
|
*
|
|
* @copyright Copyright (c) 2018, ownCloud GmbH
|
|
* @license AGPL-3.0
|
|
*
|
|
* This code is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License, version 3,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* 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, version 3,
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
*
|
|
*/
|
|
|
|
use Behat\Gherkin\Node\TableNode;
|
|
use GuzzleHttp\Exception\ClientException;
|
|
use GuzzleHttp\Exception\GuzzleException;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use PHPUnit\Framework\Assert;
|
|
use TestHelpers\UserHelper;
|
|
use TestHelpers\HttpRequestHelper;
|
|
use TestHelpers\OcisHelper;
|
|
use TestHelpers\WebDavHelper;
|
|
use TestHelpers\GraphHelper;
|
|
use Laminas\Ldap\Exception\LdapException;
|
|
use Laminas\Ldap\Ldap;
|
|
|
|
/**
|
|
* Functions for provisioning of users and groups
|
|
*/
|
|
trait Provisioning {
|
|
/**
|
|
* list of users that were created on the local server during test runs
|
|
* key is the lowercase username, value is an array of user attributes
|
|
*/
|
|
private array $createdUsers = [];
|
|
private array $startingGroups = [];
|
|
private array $createdRemoteGroups = [];
|
|
private array $createdGroups = [];
|
|
|
|
/**
|
|
* Check if this is the admin group. That group is always a local group in
|
|
* ownCloud10, even if other groups come from LDAP.
|
|
*
|
|
* @param string $groupname
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function isLocalAdminGroup(string $groupname): bool {
|
|
return ($groupname === "admin");
|
|
}
|
|
|
|
/**
|
|
* Usernames are not case-sensitive, and can generally be specified with any
|
|
* mix of upper and lower case. For remembering usernames use the normalized
|
|
* form so that "alice" and "Alice" are remembered as the same user.
|
|
*
|
|
* @param string|null $username
|
|
*
|
|
* @return string
|
|
*/
|
|
public function normalizeUsername(?string $username): string {
|
|
return \strtolower((string)$username);
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function getCreatedUsers(): array {
|
|
return $this->createdUsers;
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function getCreatedGroups(): array {
|
|
return $this->createdGroups;
|
|
}
|
|
|
|
/**
|
|
* returns the display name of a user
|
|
* if no "Display Name" is set the username is returned instead
|
|
*
|
|
* @param string $username
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getUserDisplayName(string $username): string {
|
|
$normalizedUsername = $this->normalizeUsername($username);
|
|
$users = $this->getCreatedUsers();
|
|
if (isset($users[$normalizedUsername]['displayname'])) {
|
|
$displayName = (string) $users[$normalizedUsername]['displayname'];
|
|
if ($displayName !== '') {
|
|
return $displayName;
|
|
}
|
|
}
|
|
return $username;
|
|
}
|
|
|
|
/**
|
|
* @param string $user
|
|
* @param string $attribute
|
|
*
|
|
* @return mixed
|
|
* @throws Exception
|
|
*/
|
|
public function getAttributeOfCreatedUser(string $user, string $attribute): mixed {
|
|
$usersList = $this->getCreatedUsers();
|
|
$normalizedUsername = $this->normalizeUsername($user);
|
|
if (\array_key_exists($normalizedUsername, $usersList)) {
|
|
if (\array_key_exists($attribute, $usersList[$normalizedUsername])) {
|
|
return $usersList[$normalizedUsername][$attribute];
|
|
}
|
|
throw new Exception(
|
|
__METHOD__ . ": User '$user' has no attribute with name '$attribute'.",
|
|
);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param string $group
|
|
* @param string $attribute
|
|
*
|
|
* @return mixed
|
|
* @throws Exception
|
|
*/
|
|
public function getAttributeOfCreatedGroup(string $group, string $attribute): mixed {
|
|
$groupsList = $this->getCreatedGroups();
|
|
if (\array_key_exists($group, $groupsList)) {
|
|
if (\array_key_exists($attribute, $groupsList[$group])) {
|
|
return $groupsList[$group][$attribute];
|
|
}
|
|
throw new Exception(
|
|
__METHOD__ . ": Group '$group' has no attribute with name '$attribute'.",
|
|
);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param string $username
|
|
*
|
|
* @return string password
|
|
* @throws Exception
|
|
*/
|
|
public function getUserPassword(string $username): string {
|
|
$normalizedUsername = $this->normalizeUsername($username);
|
|
if ($normalizedUsername === $this->getAdminUsername()) {
|
|
$password = $this->getAdminPassword();
|
|
} elseif (\array_key_exists($normalizedUsername, $this->createdUsers)) {
|
|
$password = $this->createdUsers[$normalizedUsername]['password'];
|
|
} else {
|
|
throw new Exception(
|
|
"user '$username' was not created by this test run",
|
|
);
|
|
}
|
|
|
|
// make sure the function always returns a string
|
|
return (string) $password;
|
|
}
|
|
|
|
/**
|
|
* @Given user :user has been created with default attributes
|
|
*
|
|
* @param string $user
|
|
*
|
|
* @return void
|
|
* @throws Exception|GuzzleException
|
|
*/
|
|
public function userHasBeenCreatedWithDefaultAttributes(
|
|
string $user,
|
|
): void {
|
|
$this->userHasBeenCreated(["userName" => $user]);
|
|
}
|
|
|
|
/**
|
|
* @Given these users have been created without being initialized:
|
|
*
|
|
* @param TableNode $table
|
|
*
|
|
* @return void
|
|
* @throws Exception|GuzzleException
|
|
*/
|
|
public function userHasBeenCreatedWithDefaultAttributesAndNotInitialized(
|
|
TableNode $table,
|
|
): void {
|
|
$this->usersHaveBeenCreated($table, true, false);
|
|
}
|
|
|
|
/**
|
|
* @Given these users have been created with default attributes:
|
|
* expects a table of users with the heading
|
|
* "|username|"
|
|
*
|
|
* @param TableNode $table
|
|
*
|
|
* @return void
|
|
* @throws Exception|GuzzleException
|
|
*/
|
|
public function theseUsersHaveBeenCreatedWithDefaultAttributesAndWithoutSkeletonFiles(TableNode $table): void {
|
|
$this->usersHaveBeenCreated($table);
|
|
}
|
|
|
|
/**
|
|
* @Given the user :byUser has created a new user with the following attributes:
|
|
*
|
|
* @param string $byUser
|
|
* @param TableNode $table
|
|
*
|
|
* @return void
|
|
* @throws Exception|GuzzleException
|
|
*/
|
|
public function theAdministratorHasCreatedANewUserWithFollowingSettings(string $byUser, TableNode $table): void {
|
|
$rows = $table->getRowsHash();
|
|
$this->userHasBeenCreated(
|
|
$rows,
|
|
$byUser,
|
|
);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param string $groupname
|
|
*
|
|
* @return boolean
|
|
* @throws Exception
|
|
*/
|
|
public function theGroupShouldBeAbleToBeDeleted(string $groupname): bool {
|
|
if (\array_key_exists($groupname, $this->createdGroups)) {
|
|
return $this->createdGroups[$groupname]['possibleToDelete'] ?? true;
|
|
}
|
|
|
|
if (\array_key_exists($groupname, $this->createdRemoteGroups)) {
|
|
return $this->createdRemoteGroups[$groupname]['possibleToDelete'] ?? true;
|
|
}
|
|
|
|
throw new Exception(
|
|
__METHOD__
|
|
. " group '$groupname' was not created by this test run",
|
|
);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param string $path
|
|
*
|
|
* @return void
|
|
*/
|
|
public function importLdifFile(string $path): void {
|
|
$ldifData = \file_get_contents($path);
|
|
$this->importLdifData($ldifData);
|
|
}
|
|
|
|
/**
|
|
* imports an ldif string
|
|
*
|
|
* @param string $ldifData
|
|
*
|
|
* @return void
|
|
*/
|
|
public function importLdifData(string $ldifData): void {
|
|
$items = Laminas\Ldap\Ldif\Encoder::decode($ldifData);
|
|
if (isset($items['dn'])) {
|
|
// only one item in the ldif data
|
|
$this->ldap->add($items['dn'], $items);
|
|
} else {
|
|
foreach ($items as $item) {
|
|
if (isset($item["objectclass"])) {
|
|
if (\in_array("posixGroup", $item["objectclass"])) {
|
|
$this->ldapCreatedGroups[] = $item["cn"][0];
|
|
$this->addGroupToCreatedGroupsList($item["cn"][0]);
|
|
} elseif (\in_array("inetOrgPerson", $item["objectclass"])) {
|
|
$this->ldapCreatedUsers[] = $item["uid"][0];
|
|
$this->addUserToCreatedUsersList($item["uid"][0], $item["userpassword"][0]);
|
|
}
|
|
}
|
|
$this->ldap->add($item['dn'], $item);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array $suiteParameters
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws \LdapException
|
|
*/
|
|
public function connectToLdap(array $suiteParameters): void {
|
|
$this->ldapBaseDN = OcisHelper::getBaseDN();
|
|
$this->ldapUsersOU = OcisHelper::getUsersOU();
|
|
$this->ldapGroupsOU = OcisHelper::getGroupsOU();
|
|
$this->ldapGroupSchema = OcisHelper::getGroupSchema();
|
|
$this->ldapHost = OcisHelper::getHostname();
|
|
$this->ldapPort = OcisHelper::getLdapPort();
|
|
$useSsl = OcisHelper::useSsl();
|
|
$this->ldapAdminUser = OcisHelper::getBindDN();
|
|
$this->ldapAdminPassword = OcisHelper::getBindPassword();
|
|
$this->skipImportLdif = (\getenv("REVA_LDAP_SKIP_LDIF_IMPORT") === "true");
|
|
if ($useSsl === true) {
|
|
\putenv('LDAPTLS_REQCERT=never');
|
|
}
|
|
|
|
if ($this->ldapAdminPassword === "") {
|
|
$this->ldapAdminPassword = (string)$suiteParameters['ldapAdminPassword'];
|
|
}
|
|
$options = [
|
|
'host' => $this->ldapHost,
|
|
'port' => $this->ldapPort,
|
|
'password' => $this->ldapAdminPassword,
|
|
'bindRequiresDn' => true,
|
|
'useSsl' => $useSsl,
|
|
'baseDn' => $this->ldapBaseDN,
|
|
'username' => $this->ldapAdminUser,
|
|
];
|
|
$this->ldap = new Ldap($options);
|
|
$this->ldap->bind();
|
|
|
|
$ldifFile = __DIR__ . $suiteParameters['ldapInitialUserFilePath'];
|
|
if (!$this->skipImportLdif) {
|
|
try {
|
|
$this->importLdifFile($ldifFile);
|
|
} catch (LdapException $err) {
|
|
if (!\str_contains($err->getMessage(), "Already exists")) {
|
|
throw $err;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* prepares a suitable nested array with user-attributes for multiple users to be created
|
|
*
|
|
* @param boolean $setDefaultAttributes
|
|
* @param array $table
|
|
*
|
|
* @return array
|
|
* @throws JsonException
|
|
*/
|
|
public function buildUsersAttributesArray(bool $setDefaultAttributes, array $table): array {
|
|
$usersAttributes = [];
|
|
foreach ($table as $row) {
|
|
$userAttribute['userid'] = $this->getActualUsername($row['username']);
|
|
|
|
if (isset($row['displayname'])) {
|
|
$userAttribute['displayName'] = $row['displayname'];
|
|
} elseif ($setDefaultAttributes) {
|
|
$userAttribute['displayName'] = $this->getDisplayNameForUser($row['username']);
|
|
if ($userAttribute['displayName'] === null) {
|
|
$userAttribute['displayName'] = $this->getDisplayNameForUser('regularuser');
|
|
}
|
|
} else {
|
|
$userAttribute['displayName'] = null;
|
|
}
|
|
if (isset($row['email'])) {
|
|
$userAttribute['email'] = $row['email'];
|
|
} elseif ($setDefaultAttributes) {
|
|
$userAttribute['email'] = $this->getEmailAddressForUser($row['username']);
|
|
if ($userAttribute['email'] === null) {
|
|
$userAttribute['email'] = $row['username'] . '@owncloud.com';
|
|
}
|
|
} else {
|
|
$userAttribute['email'] = null;
|
|
}
|
|
|
|
if (isset($row['password'])) {
|
|
$userAttribute['password'] = $this->getActualPassword($row['password']);
|
|
} else {
|
|
$userAttribute['password'] = $this->getPasswordForUser($row['username']);
|
|
}
|
|
// Add request body to the bodies array. We will use that later to loop through created users.
|
|
$usersAttributes[] = $userAttribute;
|
|
}
|
|
return $usersAttributes;
|
|
}
|
|
|
|
/**
|
|
* creates a user in the ldap server
|
|
* the created user is added to `createdUsersList`
|
|
* ldap users are re-synced after creating a new user
|
|
*
|
|
* @param array $setting
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function createLdapUser(array $setting): void {
|
|
$ou = $this->ldapUsersOU;
|
|
// Some special characters need to be escaped in LDAP DN and attributes
|
|
// The special characters allowed in a username (UID) are +_.@-
|
|
// Of these, only + has to be escaped.
|
|
$userId = \str_replace('+', '\+', $setting["userid"]);
|
|
$newDN = 'uid=' . $userId . ',ou=' . $ou . ',' . $this->ldapBaseDN;
|
|
|
|
// pick a high uid number to make sure there are no conflicts with existing uid numbers
|
|
$uidNumber = \count($this->ldapCreatedUsers) + 30000;
|
|
$entry = [];
|
|
$entry['cn'] = $userId;
|
|
$entry['sn'] = $userId;
|
|
$entry['uid'] = $setting["userid"];
|
|
$entry['homeDirectory'] = '/home/openldap/' . $setting["userid"];
|
|
$entry['objectclass'][] = 'posixAccount';
|
|
$entry['objectclass'][] = 'inetOrgPerson';
|
|
$entry['objectclass'][] = 'organizationalPerson';
|
|
$entry['objectclass'][] = 'person';
|
|
$entry['objectclass'][] = 'top';
|
|
|
|
$entry['userPassword'] = $setting["password"];
|
|
if (isset($setting["displayName"])) {
|
|
$entry['displayName'] = $setting["displayName"];
|
|
}
|
|
if (isset($setting["email"])) {
|
|
$entry['mail'] = $setting["email"];
|
|
} elseif (!OcisHelper::isTestingOnReva()) {
|
|
$entry['mail'] = $userId . '@owncloud.com';
|
|
}
|
|
$entry['gidNumber'] = 5000;
|
|
$entry['uidNumber'] = $uidNumber;
|
|
|
|
if (!OcisHelper::isTestingOnReva()) {
|
|
$entry['objectclass'][] = 'ownCloud';
|
|
$entry['ownCloudUUID'] = WebDavHelper::generateUUIDv4();
|
|
}
|
|
|
|
try {
|
|
$this->ldap->add($newDN, $entry);
|
|
} catch (LdapException $e) {
|
|
if (\str_contains($e->getMessage(), "Already exists")) {
|
|
$this->ldap->delete(
|
|
"uid=" . ldap_escape(
|
|
$entry['uid'],
|
|
"",
|
|
LDAP_ESCAPE_DN,
|
|
) . ",ou=" . $this->ldapUsersOU . "," . $this->ldapBaseDN,
|
|
);
|
|
OcisHelper::deleteRevaUserData([$entry['uid']]);
|
|
$this->ldap->add($newDN, $entry);
|
|
}
|
|
}
|
|
|
|
$this->ldapCreatedUsers[] = $setting["userid"];
|
|
}
|
|
|
|
/**
|
|
* @param string $group group name
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws LdapException
|
|
*/
|
|
public function createLdapGroup(string $group): void {
|
|
$baseDN = $this->getLdapBaseDN();
|
|
$newDN = 'cn=' . $group . ',ou=' . $this->ldapGroupsOU . ',' . $baseDN;
|
|
$entry = [];
|
|
$entry['cn'] = $group;
|
|
$entry['objectclass'][] = 'top';
|
|
|
|
if ($this->ldapGroupSchema == "rfc2307") {
|
|
$entry['objectclass'][] = 'posixGroup';
|
|
$entry['gidNumber'] = 5000;
|
|
} else {
|
|
$entry['objectclass'][] = 'groupOfNames';
|
|
$entry['member'] = "";
|
|
}
|
|
if (!OcisHelper::isTestingOnReva()) {
|
|
$entry['objectclass'][] = 'ownCloud';
|
|
$entry['ownCloudUUID'] = WebDavHelper::generateUUIDv4();
|
|
}
|
|
|
|
try {
|
|
$this->ldap->add($newDN, $entry);
|
|
} catch (LdapException $e) {
|
|
if (\str_contains($e->getMessage(), "Already exists")) {
|
|
$this->ldap->delete(
|
|
"cn=" . ldap_escape($group, "", LDAP_ESCAPE_DN)
|
|
. ",ou=" . $this->ldapGroupsOU . "," . $this->ldapBaseDN,
|
|
);
|
|
$this->ldap->add($newDN, $entry);
|
|
}
|
|
}
|
|
$this->ldapCreatedGroups[] = $group;
|
|
}
|
|
|
|
/**
|
|
* deletes LDAP users|groups created during test
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function deleteLdapUsersAndGroups(): void {
|
|
foreach ($this->ldapCreatedUsers as $user) {
|
|
$this->ldap->delete(
|
|
"uid=" . ldap_escape($user, "", LDAP_ESCAPE_DN) . ",ou=" . $this->ldapUsersOU . "," . $this->ldapBaseDN,
|
|
);
|
|
$this->rememberThatUserIsNotExpectedToExist($user);
|
|
}
|
|
foreach ($this->ldapCreatedGroups as $group) {
|
|
$this->ldap->delete(
|
|
"cn=" . ldap_escape($group, "", LDAP_ESCAPE_DN)
|
|
. ",ou=" . $this->ldapGroupsOU . "," . $this->ldapBaseDN,
|
|
);
|
|
$this->rememberThatGroupIsNotExpectedToExist($group);
|
|
}
|
|
if (!$this->skipImportLdif) {
|
|
// delete all created ldap users
|
|
$this->ldap->delete(
|
|
"ou=" . $this->ldapUsersOU . "," . $this->ldapBaseDN,
|
|
true,
|
|
);
|
|
// delete all created ldap groups
|
|
$this->ldap->delete(
|
|
"ou=" . $this->ldapGroupsOU . "," . $this->ldapBaseDN,
|
|
true,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates multiple users
|
|
*
|
|
* This function will allow us to send user creation requests in parallel.
|
|
* This will be faster in comparison to waiting for each request to complete before sending another request.
|
|
*
|
|
* @param TableNode $table
|
|
* @param bool $useDefault
|
|
* @param bool $initialize
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws GuzzleException
|
|
*/
|
|
public function usersHaveBeenCreated(
|
|
TableNode $table,
|
|
bool $useDefault = true,
|
|
bool $initialize = true,
|
|
): void {
|
|
$this->verifyTableNodeColumns($table, ['username'], ['displayname', 'email', 'password']);
|
|
$table = $table->getColumnsHash();
|
|
$users = $this->buildUsersAttributesArray($useDefault, $table);
|
|
|
|
$requests = [];
|
|
$client = HttpRequestHelper::createClient(
|
|
$this->getAdminUsername(),
|
|
$this->getAdminPassword(),
|
|
);
|
|
|
|
foreach ($users as $userAttributes) {
|
|
if ($this->isTestingWithLdap()) {
|
|
$this->createLdapUser($userAttributes);
|
|
} else {
|
|
$attributesToCreateUser['userid'] = $userAttributes['userid'];
|
|
$attributesToCreateUser['password'] = $userAttributes['password'];
|
|
$attributesToCreateUser['displayname'] = $userAttributes['displayName'];
|
|
if ($userAttributes['email'] === null) {
|
|
Assert::assertArrayHasKey(
|
|
'userid',
|
|
$userAttributes,
|
|
__METHOD__ . " userAttributes array does not have key 'userid'",
|
|
);
|
|
$attributesToCreateUser['email'] = $userAttributes['userid'] . '@owncloud.com';
|
|
} else {
|
|
$attributesToCreateUser['email'] = $userAttributes['email'];
|
|
}
|
|
$body = GraphHelper::prepareCreateUserPayload(
|
|
$attributesToCreateUser['userid'],
|
|
$attributesToCreateUser['password'],
|
|
$attributesToCreateUser['email'],
|
|
$attributesToCreateUser['displayname'],
|
|
);
|
|
$request = GraphHelper::createRequest(
|
|
$this->getBaseUrl(),
|
|
"POST",
|
|
'users',
|
|
$body,
|
|
);
|
|
// Add the request to the $requests array so that they can be sent in parallel.
|
|
$requests[] = $request;
|
|
}
|
|
}
|
|
|
|
$exceptionToThrow = null;
|
|
if (!$this->isTestingWithLdap()) {
|
|
$results = HttpRequestHelper::sendBatchRequest($requests, $client);
|
|
// Check all requests to inspect failures.
|
|
foreach ($results as $key => $e) {
|
|
if ($e instanceof ClientException) {
|
|
$responseBody = $this->getJsonDecodedResponse($e->getResponse());
|
|
$httpStatusCode = $e->getResponse()->getStatusCode();
|
|
$graphStatusCode = $responseBody['error']['code'];
|
|
$messageText = $responseBody['error']['message'];
|
|
$exceptionToThrow = new Exception(
|
|
__METHOD__ .
|
|
" Unexpected failure when creating the user '" .
|
|
$users[$key]['userid'] . "'" .
|
|
"\nHTTP status $httpStatusCode " .
|
|
"\nGraph status $graphStatusCode " .
|
|
"\nError message $messageText",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create requests for setting displayname and email for the newly created users.
|
|
// These values cannot be set while creating the user, so we have to edit the newly created user to set these values.
|
|
foreach ($users as $userAttributes) {
|
|
if (!$this->isTestingWithLdap()) {
|
|
// for graph api, we need to save the user id to be able to add it in some group
|
|
// can be fetched with the "onPremisesSamAccountName" i.e. userid
|
|
$response = $this->graphContext->adminHasRetrievedUserUsingTheGraphApi($userAttributes['userid']);
|
|
$userAttributes['id'] = $this->getJsonDecodedResponse($response)['id'];
|
|
} else {
|
|
$userAttributes['id'] = null;
|
|
}
|
|
$this->addUserToCreatedUsersList(
|
|
$userAttributes['userid'],
|
|
$userAttributes['password'],
|
|
$userAttributes['displayName'],
|
|
$userAttributes['email'],
|
|
$userAttributes['id'],
|
|
);
|
|
}
|
|
|
|
if (isset($exceptionToThrow)) {
|
|
throw $exceptionToThrow;
|
|
}
|
|
|
|
foreach ($users as $user) {
|
|
Assert::assertTrue(
|
|
$this->userExists($user["userid"]),
|
|
"User '" . $user["userid"] . "' should exist but does not exist",
|
|
);
|
|
}
|
|
|
|
if ($initialize) {
|
|
foreach ($users as $user) {
|
|
$this->initializeUser($user['userid'], $user['password']);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $username
|
|
* @param string|null $password
|
|
*
|
|
* @return void
|
|
*/
|
|
public function resetUserPasswordAsAdminUsingTheProvisioningApi(string $username, ?string $password): void {
|
|
$this->userResetUserPasswordUsingProvisioningApi(
|
|
$this->getAdminUsername(),
|
|
$username,
|
|
$password,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string|null $user
|
|
* @param string|null $username
|
|
* @param string|null $password
|
|
*
|
|
* @return void
|
|
*/
|
|
public function userResetUserPasswordUsingProvisioningApi(
|
|
?string $user,
|
|
?string $username,
|
|
?string $password,
|
|
): void {
|
|
$targetUsername = $this->getActualUsername($username);
|
|
$password = $this->getActualPassword($password);
|
|
$this->userTriesToResetUserPasswordUsingTheProvisioningApi(
|
|
$user,
|
|
$targetUsername,
|
|
$password,
|
|
);
|
|
$this->rememberUserPassword($targetUsername, $password);
|
|
}
|
|
|
|
/**
|
|
* @param string|null $user
|
|
* @param string|null $username
|
|
* @param string|null $password
|
|
*
|
|
* @return void
|
|
*/
|
|
public function userTriesToResetUserPasswordUsingTheProvisioningApi(
|
|
?string $user,
|
|
?string $username,
|
|
?string $password,
|
|
): void {
|
|
$password = $this->getActualPassword($password);
|
|
$bodyTable = new TableNode([['key', 'password'], ['value', $password]]);
|
|
$this->ocsContext->sendRequestToOcsEndpoint(
|
|
$user,
|
|
"PUT",
|
|
"/cloud/users/$username",
|
|
$bodyTable,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @When /^the administrator deletes user "([^"]*)" using the provisioning API$/
|
|
*
|
|
* @param string $user
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function theAdminDeletesUserUsingTheProvisioningApi(string $user): void {
|
|
$user = $this->getActualUsername($user);
|
|
$this->setResponse($this->deleteUser($user));
|
|
$this->pushToLastHttpStatusCodesArray();
|
|
}
|
|
|
|
/**
|
|
* @Then /^user "([^"]*)" should exist$/
|
|
*
|
|
* @param string $user
|
|
*
|
|
* @return void
|
|
* @throws JsonException
|
|
*/
|
|
public function userShouldExist(string $user): void {
|
|
Assert::assertTrue(
|
|
$this->userExists($user),
|
|
"User '$user' should exist but does not exist",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Then /^user "([^"]*)" should not exist$/
|
|
*
|
|
* @param string $user
|
|
*
|
|
* @return void
|
|
* @throws JsonException
|
|
*/
|
|
public function userShouldNotExist(string $user): void {
|
|
$user = $this->getActualUsername($user);
|
|
Assert::assertFalse(
|
|
$this->userExists($user),
|
|
"User '$user' should not exist but does exist",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Then /^group "([^"]*)" should exist$/
|
|
*
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws GuzzleException
|
|
*/
|
|
public function groupShouldExist(string $group): void {
|
|
Assert::assertTrue(
|
|
$this->groupExists($group),
|
|
"Group '$group' should exist but does not exist",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Then /^group "([^"]*)" should not exist$/
|
|
*
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws GuzzleException
|
|
*/
|
|
public function groupShouldNotExist(string $group): void {
|
|
Assert::assertFalse(
|
|
$this->groupExists($group),
|
|
"Group '$group' should not exist but does exist",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Then /^these groups should (not|)\s?exist:$/
|
|
* expects a table of groups with the heading "groupname"
|
|
*
|
|
* @param string $shouldOrNot (not|)
|
|
* @param TableNode $table
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function theseGroupsShouldNotExist(string $shouldOrNot, TableNode $table): void {
|
|
$should = ($shouldOrNot !== "not");
|
|
$this->verifyTableNodeColumns($table, ['groupname']);
|
|
if ($this->isTestingWithLdap()) {
|
|
$groups = $this->getArrayOfGroupsResponded($this->getAllGroups());
|
|
foreach ($table as $row) {
|
|
if (\in_array($row['groupname'], $groups, true) !== $should) {
|
|
throw new Exception(
|
|
"group '" . $row['groupname'] .
|
|
"' does" . ($should ? " not" : "") .
|
|
" exist but should" . ($should ? "" : " not"),
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
$this->graphContext->theseGroupsShouldNotExist($shouldOrNot, $table);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @Given /^user "([^"]*)" has been deleted$/
|
|
*
|
|
* @param string $user
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function userHasBeenDeleted(string $user): void {
|
|
$user = $this->getActualUsername($user);
|
|
if ($this->userExists($user)) {
|
|
if ($this->isTestingWithLdap() && \in_array($user, $this->ldapCreatedUsers)) {
|
|
$this->deleteLdapUser($user);
|
|
} else {
|
|
$response = $this->deleteUser($user);
|
|
$this->theHTTPStatusCodeShouldBe(204, "", $response);
|
|
WebDavHelper::removeSpaceIdReferenceForUser($user);
|
|
}
|
|
}
|
|
Assert::assertFalse(
|
|
$this->userExists($user),
|
|
"User '$user' should not exist but does exist",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Given these users have been initialized:
|
|
* expects a table of users with the heading
|
|
* "|username|password|"
|
|
*
|
|
* @param TableNode $table
|
|
*
|
|
* @return void
|
|
*/
|
|
public function theseUsersHaveBeenInitialized(TableNode $table): void {
|
|
foreach ($table as $row) {
|
|
if (!isset($row ['password'])) {
|
|
$password = $this->getPasswordForUser($row ['username']);
|
|
} else {
|
|
$password = $row ['password'];
|
|
}
|
|
$this->initializeUser(
|
|
$row ['username'],
|
|
$password,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get all the existing groups
|
|
*
|
|
* @return ResponseInterface
|
|
*/
|
|
public function getAllGroups(): ResponseInterface {
|
|
$fullUrl = $this->getBaseUrl() . "/ocs/v$this->ocsApiVersion.php/cloud/groups";
|
|
return HttpRequestHelper::get(
|
|
$fullUrl,
|
|
$this->getAdminUsername(),
|
|
$this->getAdminPassword(),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $user
|
|
* @param string $otherUser
|
|
*
|
|
* @return void
|
|
*/
|
|
public function userGetsAllTheGroupsOfUser(string $user, string $otherUser): void {
|
|
$actualOtherUser = $this->getActualUsername($otherUser);
|
|
$fullUrl = $this->getBaseUrl() . "/ocs/v$this->ocsApiVersion.php/cloud/users/$actualOtherUser/groups";
|
|
$actualUser = $this->getActualUsername($user);
|
|
$actualPassword = $this->getUserPassword($actualUser);
|
|
$this->response = HttpRequestHelper::get(
|
|
$fullUrl,
|
|
$actualUser,
|
|
$actualPassword,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @When user :user gets the list of all users using the provisioning API
|
|
*
|
|
* @param string $user
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function userGetsTheListOfAllUsersUsingTheProvisioningApi(string $user): void {
|
|
$this->featureContext->setResponse(
|
|
$this->userGetsTheListOfAllUsers($user),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $user
|
|
*
|
|
* @return ResponseInterface
|
|
*/
|
|
public function userGetsTheListOfAllUsers(string $user): ResponseInterface {
|
|
$fullUrl = $this->getBaseUrl() . "/ocs/v$this->ocsApiVersion.php/cloud/users";
|
|
$actualUser = $this->getActualUsername($user);
|
|
$actualPassword = $this->getUserPassword($actualUser);
|
|
return HttpRequestHelper::get(
|
|
$fullUrl,
|
|
$actualUser,
|
|
$actualPassword,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Make a request about the user. That will force the server to fully
|
|
* initialize the user, including their skeleton files.
|
|
*
|
|
* @param string $user
|
|
* @param string $password
|
|
*
|
|
* @return void
|
|
*/
|
|
public function initializeUser(string $user, string $password): void {
|
|
if (OcisHelper::isTestingOnReva()) {
|
|
$url = $this->getBaseUrl() . "/ocs/v$this->ocsApiVersion.php/cloud/users/$user";
|
|
HttpRequestHelper::get(
|
|
$url,
|
|
$user,
|
|
$password,
|
|
);
|
|
return;
|
|
}
|
|
|
|
// initialize user by requesting drives
|
|
// NOTE: this should not be removed,
|
|
// as it will save the Personal and Shares drives information
|
|
$this->spacesContext->getSpaceByName($user, 'Personal');
|
|
}
|
|
|
|
/**
|
|
* adds a user to the list of users that were created during test runs
|
|
* makes it possible to use this list in other test steps
|
|
* or to delete them at the end of the test
|
|
*
|
|
* @param string $user
|
|
* @param string $password
|
|
* @param string|null $displayName
|
|
* @param string|null $email
|
|
* @param string|null $userId only set for the users created using the Graph API
|
|
* @param bool $shouldExist
|
|
*
|
|
* @return void
|
|
* @throws JsonException
|
|
*/
|
|
public function addUserToCreatedUsersList(
|
|
string $user,
|
|
string $password,
|
|
?string $displayName = null,
|
|
?string $email = null,
|
|
?string $userId = null,
|
|
bool $shouldExist = true,
|
|
): void {
|
|
$user = $this->getActualUsername($user);
|
|
$normalizedUsername = $this->normalizeUsername($user);
|
|
|
|
if ($shouldExist || !\array_key_exists($normalizedUsername, $this->createdUsers)) {
|
|
$this->createdUsers[$normalizedUsername] = [
|
|
"password" => $password,
|
|
"displayname" => $displayName,
|
|
"email" => $email,
|
|
"shouldExist" => $shouldExist,
|
|
"actualUsername" => $user,
|
|
"id" => $userId,
|
|
"serverType" => $this->currentServer,
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* remember the password of a user that already exists so that you can use
|
|
* ordinary test steps after changing their password.
|
|
*
|
|
* @param string $user
|
|
* @param string $password
|
|
*
|
|
* @return void
|
|
*/
|
|
public function rememberUserPassword(
|
|
string $user,
|
|
string $password,
|
|
): void {
|
|
$normalizedUsername = $this->normalizeUsername($user);
|
|
if (\array_key_exists($normalizedUsername, $this->createdUsers)) {
|
|
$this->createdUsers[$normalizedUsername]['password'] = $password;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $oldUserName
|
|
* @param string $newUserName
|
|
*
|
|
* @return void
|
|
*/
|
|
public function updateUsernameInCreatedUserList(string $oldUserName, string $newUserName): void {
|
|
$normalizedUsername = $this->normalizeUsername($oldUserName);
|
|
$normalizeNewUserName = $this->normalizeUsername($newUserName);
|
|
if (\array_key_exists($normalizedUsername, $this->createdUsers)) {
|
|
foreach ($this->createdUsers as $createdUser) {
|
|
if ($createdUser['actualUsername'] === $oldUserName) {
|
|
$this->createdUsers[$normalizeNewUserName] = $this->createdUsers[$normalizedUsername];
|
|
$this->createdUsers[$normalizeNewUserName]['actualUsername'] = $newUserName;
|
|
unset($this->createdUsers[$normalizedUsername]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remembers that a user from the list of users that were created during
|
|
* test runs is no longer expected to exist. Useful if a user was created
|
|
* during the setup phase but was deleted in a test run. We don't expect
|
|
* this user to exist in the tear-down phase, so remember that fact.
|
|
*
|
|
* @param string $user
|
|
*
|
|
* @return void
|
|
*/
|
|
public function rememberThatUserIsNotExpectedToExist(string $user): void {
|
|
$user = $this->getActualUsername($user);
|
|
$normalizedUsername = $this->normalizeUsername($user);
|
|
if (\array_key_exists($normalizedUsername, $this->createdUsers)) {
|
|
$this->createdUsers[$normalizedUsername]['shouldExist'] = false;
|
|
$this->createdUsers[$normalizedUsername]['possibleToDelete'] = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* creates a single user
|
|
*
|
|
* @param array $userData
|
|
* @param string|null $byUser
|
|
*
|
|
* @return void
|
|
* @throws Exception|GuzzleException
|
|
*/
|
|
public function userHasBeenCreated(
|
|
array $userData,
|
|
?string $byUser = null,
|
|
): void {
|
|
$userId = null;
|
|
|
|
$user = $userData["userName"];
|
|
$displayName = $userData["displayName"] ?? null;
|
|
$email = $userData["email"] ?? null;
|
|
$password = $userData["password"] ?? null;
|
|
|
|
if ($password === null) {
|
|
$password = $this->getPasswordForUser($user);
|
|
}
|
|
|
|
if ($displayName === null) {
|
|
$displayName = $this->getDisplayNameForUser($user);
|
|
if ($displayName === null) {
|
|
$displayName = $this->getDisplayNameForUser('regularuser');
|
|
}
|
|
}
|
|
|
|
if ($email === null) {
|
|
$email = $this->getEmailAddressForUser($user);
|
|
|
|
if ($email === null) {
|
|
// escape @ & space if present in userId
|
|
$email = \str_replace(["@", " "], "", $user) . '@owncloud.com';
|
|
}
|
|
}
|
|
$user = $this->getActualUsername($user);
|
|
$user = \trim($user);
|
|
|
|
if ($this->isTestingWithLdap()) {
|
|
$setting["userid"] = $user;
|
|
$setting["displayName"] = $displayName;
|
|
$setting["password"] = $password;
|
|
$setting["email"] = $email;
|
|
try {
|
|
$this->createLdapUser($setting);
|
|
} catch (LdapException $exception) {
|
|
throw new Exception(
|
|
__METHOD__ . " cannot create a LDAP user with provided data. Error: $exception",
|
|
);
|
|
}
|
|
} else {
|
|
$reqUser = $byUser ? $this->getActualUsername($byUser) : $this->getAdminUsername();
|
|
$response = GraphHelper::createUser(
|
|
$this->getBaseUrl(),
|
|
$reqUser,
|
|
$this->getPasswordForUser($reqUser),
|
|
$user,
|
|
$password,
|
|
$email,
|
|
$displayName,
|
|
);
|
|
Assert::assertEquals(
|
|
201,
|
|
$response->getStatusCode(),
|
|
__METHOD__ . " cannot create user '$user' using Graph API.\nResponse:" .
|
|
json_encode($this->getJsonDecodedResponse($response)),
|
|
);
|
|
$userId = $this->getJsonDecodedResponse($response)['id'];
|
|
}
|
|
|
|
$this->addUserToCreatedUsersList($user, $password, $displayName, $email, $userId);
|
|
|
|
Assert::assertTrue(
|
|
$this->userExists($user),
|
|
"User '$user' should exist but does not exist",
|
|
);
|
|
|
|
$this->initializeUser($user, $password);
|
|
}
|
|
|
|
/**
|
|
* @When the administrator removes user :user from group :group using the provisioning API
|
|
*
|
|
* @param string $user
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function adminRemovesUserFromGroupUsingTheProvisioningApi(string $user, string $group): void {
|
|
$user = $this->getActualUsername($user);
|
|
if (OcisHelper::isTestingOnReva()) {
|
|
$this->response = UserHelper::removeUserFromGroup(
|
|
$this->getBaseUrl(),
|
|
$user,
|
|
$group,
|
|
$this->getAdminUsername(),
|
|
$this->getAdminPassword(),
|
|
$this->ocsApiVersion,
|
|
);
|
|
} else {
|
|
$this->setResponse(
|
|
$this->graphContext->removeUserFromGroup(
|
|
$group,
|
|
$user,
|
|
),
|
|
);
|
|
}
|
|
|
|
$this->pushToLastStatusCodesArrays();
|
|
}
|
|
|
|
/**
|
|
* @Then /^the extra groups returned by the API should be$/
|
|
*
|
|
* @param TableNode $groupsList
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function theExtraGroupsShouldBe(TableNode $groupsList): void {
|
|
$this->verifyTableNodeColumnsCount($groupsList, 1);
|
|
$groups = $groupsList->getRows();
|
|
$groupsSimplified = $this->simplifyArray($groups);
|
|
if ($this->isTestingWithLdap()) {
|
|
$expectedGroups = \array_merge($this->startingGroups, $groupsSimplified);
|
|
$respondedArray = $this->getArrayOfGroupsResponded($this->response);
|
|
Assert::assertEqualsCanonicalizing(
|
|
$expectedGroups,
|
|
$respondedArray,
|
|
__METHOD__
|
|
. " Provided groups do not match the groups returned in the response.",
|
|
);
|
|
} else {
|
|
$this->graphContext->theseGroupsShouldBeInTheResponse($groupsSimplified);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Try to delete the group, catching anything bad that might happen.
|
|
* Use this method only in places where you want to try as best you
|
|
* can to delete the group, but do not want to error if there is a problem.
|
|
*
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function cleanupGroup(string $group): void {
|
|
try {
|
|
if ($this->isTestingWithLdap()) {
|
|
$this->deleteLdapGroup($group);
|
|
} else {
|
|
$response = $this->graphContext->deleteGroupWithName($group);
|
|
$this->theHTTPStatusCodeShouldBe(204, "", $response);
|
|
}
|
|
} catch (Exception $e) {
|
|
\error_log(
|
|
"INFORMATION: There was an unexpected problem trying to delete group " .
|
|
"'$group' message '" . $e->getMessage() . "'",
|
|
);
|
|
}
|
|
|
|
if ($this->theGroupShouldBeAbleToBeDeleted($group)
|
|
&& $this->groupExists($group)
|
|
) {
|
|
\error_log(
|
|
"INFORMATION: tried to delete group '$group'" .
|
|
" at the end of the scenario but it seems to still exist. " .
|
|
"There might be problems with later scenarios.",
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $user
|
|
*
|
|
* @return bool
|
|
* @throws JsonException
|
|
*/
|
|
public function userExists(string $user): bool {
|
|
$path = (!OcisHelper::isTestingOnReva())
|
|
? "/graph/v1.0"
|
|
: "/ocs/v2.php/cloud";
|
|
$fullUrl = $this->getBaseUrl() . $path . "/users/$user";
|
|
|
|
if (OcisHelper::isTestingOnReva()) {
|
|
$requestingUser = $this->getActualUsername($user);
|
|
$requestingPassword = $this->getPasswordForUser($user);
|
|
} else {
|
|
$requestingUser = $this->getAdminUsername();
|
|
$requestingPassword = $this->getAdminPassword();
|
|
}
|
|
|
|
$response = HttpRequestHelper::get(
|
|
$fullUrl,
|
|
$requestingUser,
|
|
$requestingPassword,
|
|
);
|
|
if ($response->getStatusCode() >= 400) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @Then /^user "([^"]*)" should belong to group "([^"]*)"$/
|
|
*
|
|
* @param string $user
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function userShouldBelongToGroup(string $user, string $group): void {
|
|
$user = $this->getActualUsername($user);
|
|
if (OcisHelper::isTestingOnReva()) {
|
|
$this->userGetsAllTheGroupsOfUser($this->getAdminUsername(), $user);
|
|
$respondedArray = $this->getArrayOfGroupsResponded($this->response);
|
|
\sort($respondedArray);
|
|
Assert::assertContains(
|
|
$group,
|
|
$respondedArray,
|
|
__METHOD__ . " Group '$group' does not exist in '"
|
|
. \implode(', ', $respondedArray)
|
|
. "'",
|
|
);
|
|
Assert::assertEquals(
|
|
200,
|
|
$this->response->getStatusCode(),
|
|
__METHOD__
|
|
. " Expected status code is '200' but got '"
|
|
. $this->response->getStatusCode()
|
|
. "'",
|
|
);
|
|
} else {
|
|
$this->graphContext->userShouldBeMemberInGroupUsingTheGraphApi(
|
|
$user,
|
|
$group,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @Then the following users should not belong to the following groups
|
|
*
|
|
* @param TableNode $table
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function theTheFollowingUserShouldNotBelongToTheFollowingGroup(TableNode $table): void {
|
|
$this->verifyTableNodeColumns($table, ["username", "groupname"]);
|
|
$rows = $table->getHash();
|
|
foreach ($rows as $row) {
|
|
$user = $this->getActualUsername($row["username"]);
|
|
$group = $row["groupname"];
|
|
if (OcisHelper::isTestingOnReva()) {
|
|
$fullUrl = $this->getBaseUrl() . "/ocs/v2.php/cloud/users/$user/groups";
|
|
$response = HttpRequestHelper::get(
|
|
$fullUrl,
|
|
$this->getAdminUsername(),
|
|
$this->getAdminPassword(),
|
|
);
|
|
$respondedArray = $this->getArrayOfGroupsResponded($response);
|
|
\sort($respondedArray);
|
|
Assert::assertNotContains($group, $respondedArray);
|
|
Assert::assertEquals(
|
|
200,
|
|
$response->getStatusCode(),
|
|
);
|
|
} else {
|
|
$this->graphContext->userShouldNotBeMemberInGroupUsingTheGraphApi($user, $group);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @Then group :group should not contain user :username
|
|
*
|
|
* @param string $group
|
|
* @param string $username
|
|
*
|
|
* @return void
|
|
*/
|
|
public function groupShouldNotContainUser(string $group, string $username): void {
|
|
$username = $this->getActualUsername($username);
|
|
$fullUrl = $this->getBaseUrl() . "/ocs/v2.php/cloud/groups/$group";
|
|
$response = HttpRequestHelper::get(
|
|
$fullUrl,
|
|
$this->getAdminUsername(),
|
|
$this->getAdminPassword(),
|
|
);
|
|
Assert::assertNotContains($username, $this->getArrayOfUsersResponded($response));
|
|
}
|
|
|
|
/**
|
|
* @When /^the administrator adds user "([^"]*)" to group "([^"]*)" using the provisioning API$/
|
|
*
|
|
* @param string $user
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function adminAddsUserToGroupUsingTheProvisioningApi(string $user, string $group): void {
|
|
$response = $this->graphContext->addUserToGroup($group, $user);
|
|
$this->setResponse($response);
|
|
}
|
|
|
|
/**
|
|
* @Given /^user "([^"]*)" has been added to group "([^"]*)"$/
|
|
*
|
|
* @param string $user
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function userHasBeenAddedToGroup(string $user, string $group): void {
|
|
$user = $this->getActualUsername($user);
|
|
if ($this->isTestingWithLdap()) {
|
|
try {
|
|
$this->addUserToLdapGroup(
|
|
$user,
|
|
$group,
|
|
);
|
|
} catch (LdapException $exception) {
|
|
throw new Exception(
|
|
"User $user cannot be added to $group Error: $exception",
|
|
);
|
|
}
|
|
} else {
|
|
$response = $this->graphContext->addUserToGroup($group, $user);
|
|
$this->theHTTPStatusCodeShouldBe(204, '', $response);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @Given the following users have been added to the following groups
|
|
*
|
|
* @param TableNode $table
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function theFollowingUserHaveBeenAddedToTheFollowingGroup(TableNode $table): void {
|
|
$this->verifyTableNodeColumns($table, ['username', 'groupname']);
|
|
foreach ($table as $row) {
|
|
$user = $row['username'];
|
|
$group = $row['groupname'];
|
|
$user = $this->getActualUsername($user);
|
|
if ($this->isTestingWithLdap()) {
|
|
try {
|
|
$this->addUserToLdapGroup(
|
|
$user,
|
|
$group,
|
|
);
|
|
} catch (LdapException $exception) {
|
|
throw new Exception(
|
|
"User $user cannot be added to $group Error: $exception",
|
|
);
|
|
}
|
|
} else {
|
|
$response = $this->graphContext->addUserToGroup($group, $user);
|
|
$this->theHTTPStatusCodeShouldBe(204, '', $response);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $group
|
|
* @param bool $shouldExist - true if the group should exist
|
|
* @param bool $possibleToDelete - true if it is possible to delete the group
|
|
* @param string|null $id - id of the group, only required for the groups created using the Graph API
|
|
*
|
|
* @return void
|
|
*/
|
|
public function addGroupToCreatedGroupsList(
|
|
string $group,
|
|
bool $shouldExist = true,
|
|
bool $possibleToDelete = true,
|
|
?string $id = null,
|
|
): void {
|
|
$groupData = [
|
|
"shouldExist" => $shouldExist,
|
|
"possibleToDelete" => $possibleToDelete,
|
|
];
|
|
if ($id !== null) {
|
|
$groupData["id"] = $id;
|
|
}
|
|
|
|
if ($this->currentServer === 'LOCAL') {
|
|
$this->createdGroups[$group] = $groupData;
|
|
} elseif ($this->currentServer === 'REMOTE') {
|
|
$this->createdRemoteGroups[$group] = $groupData;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remembers that a group from the list of groups that were created during
|
|
* test runs is no longer expected to exist. Useful if a group was created
|
|
* during the setup phase but was deleted in a test run. We don't expect
|
|
* this group to exist in the tear-down phase, so remember that fact.
|
|
*
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
*/
|
|
public function rememberThatGroupIsNotExpectedToExist(string $group): void {
|
|
if (\array_key_exists($group, $this->createdGroups)) {
|
|
$this->createdGroups[$group]['shouldExist'] = false;
|
|
$this->createdGroups[$group]['possibleToDelete'] = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @Given /^group "([^"]*)" has been created$/
|
|
*
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws GuzzleException
|
|
*/
|
|
public function groupHasBeenCreated(string $group): void {
|
|
$this->createTheGroup($group);
|
|
Assert::assertTrue(
|
|
$this->groupExists($group),
|
|
"Group '$group' should exist but does not exist",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @Given these groups have been created:
|
|
* expects a table of groups with the heading "groupname"
|
|
*
|
|
* @param TableNode $table
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function theseGroupsHaveBeenCreated(TableNode $table): void {
|
|
$this->verifyTableNodeColumns($table, ['groupname'], ['comment']);
|
|
foreach ($table as $row) {
|
|
$this->createTheGroup($row['groupname']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* creates a single group
|
|
*
|
|
* @param string $group
|
|
* @param string|null $method how to create the group api|occ
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function createTheGroup(string $group, ?string $method = null): void {
|
|
if ($method === null) {
|
|
$method = "graph";
|
|
if ($this->isTestingWithLdap()) {
|
|
$method = "ldap";
|
|
}
|
|
}
|
|
$group = \trim($group);
|
|
$method = \trim(\strtolower($method));
|
|
$groupCanBeDeleted = false;
|
|
$groupId = null;
|
|
switch ($method) {
|
|
case "ldap":
|
|
try {
|
|
$this->createLdapGroup($group);
|
|
} catch (LdapException $e) {
|
|
throw new Exception(
|
|
"could not create group '$group'. Error: $e",
|
|
);
|
|
}
|
|
break;
|
|
case "graph":
|
|
$newGroup = $this->graphContext->createGroup($group);
|
|
if ($newGroup->getStatusCode() === 201) {
|
|
$newGroup = $this->getJsonDecodedResponse($newGroup);
|
|
}
|
|
$groupCanBeDeleted = true;
|
|
$groupId = $newGroup["id"];
|
|
break;
|
|
default:
|
|
throw new InvalidArgumentException(
|
|
"Invalid method to create group '$group'",
|
|
);
|
|
}
|
|
|
|
$this->addGroupToCreatedGroupsList($group, true, $groupCanBeDeleted, $groupId);
|
|
}
|
|
|
|
/**
|
|
* @param string $attribute
|
|
* @param string $entry
|
|
* @param string $value
|
|
* @param bool $append
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function setTheLdapAttributeOfTheEntryTo(
|
|
string $attribute,
|
|
string $entry,
|
|
string $value,
|
|
bool $append = false,
|
|
): void {
|
|
$ldapEntry = $this->ldap->getEntry($entry . "," . $this->ldapBaseDN);
|
|
Laminas\Ldap\Attribute::setAttribute($ldapEntry, $attribute, $value, $append);
|
|
$this->ldap->update($entry . "," . $this->ldapBaseDN, $ldapEntry);
|
|
}
|
|
|
|
/**
|
|
* @param string $user
|
|
* @param string $group
|
|
* @param string|null $ou
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function addUserToLdapGroup(string $user, string $group, ?string $ou = null): void {
|
|
if ($ou === null) {
|
|
$ou = $this->getLdapGroupsOU();
|
|
}
|
|
if ($this->ldapGroupSchema == "rfc2307") {
|
|
$memberAttr = "memberUID";
|
|
$memberValue = "$user";
|
|
} else {
|
|
$memberAttr = "member";
|
|
$userbase = "ou=" . $this->getLdapUsersOU() . "," . $this->ldapBaseDN;
|
|
$memberValue = "uid=$user" . "," . "$userbase";
|
|
}
|
|
$this->setTheLdapAttributeOfTheEntryTo(
|
|
$memberAttr,
|
|
"cn=$group,ou=$ou",
|
|
$memberValue,
|
|
true,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $value
|
|
* @param string $attribute
|
|
* @param string $entry
|
|
*
|
|
* @return void
|
|
*/
|
|
public function deleteValueFromLdapAttribute(string $value, string $attribute, string $entry): void {
|
|
$this->ldap->deleteAttributes(
|
|
$entry . "," . $this->ldapBaseDN,
|
|
[$attribute => [$value]],
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $user
|
|
* @param string $group
|
|
* @param string|null $ou
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function removeUserFromLdapGroup(string $user, string $group, ?string $ou = null): void {
|
|
if ($ou === null) {
|
|
$ou = $this->getLdapGroupsOU();
|
|
}
|
|
if ($this->ldapGroupSchema == "rfc2307") {
|
|
$memberAttr = "memberUID";
|
|
$memberValue = "$user";
|
|
} else {
|
|
$memberAttr = "member";
|
|
$userbase = "ou=" . $this->getLdapUsersOU() . "," . $this->ldapBaseDN;
|
|
$memberValue = "uid=$user" . "," . "$userbase";
|
|
}
|
|
$this->deleteValueFromLdapAttribute(
|
|
$memberValue,
|
|
$memberAttr,
|
|
"cn=$group,ou=$ou",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $entry
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function deleteTheLdapEntry(string $entry): void {
|
|
$this->ldap->delete($entry . "," . $this->ldapBaseDN);
|
|
}
|
|
|
|
/**
|
|
* @param string $group
|
|
* @param string|null $ou
|
|
*
|
|
* @return void
|
|
* @throws LdapException
|
|
* @throws Exception
|
|
*/
|
|
public function deleteLdapGroup(string $group, ?string $ou = null): void {
|
|
if ($ou === null) {
|
|
$ou = $this->getLdapGroupsOU();
|
|
}
|
|
$this->deleteTheLdapEntry("cn=$group,ou=$ou");
|
|
$key = \array_search($group, $this->ldapCreatedGroups);
|
|
if ($key !== false) {
|
|
unset($this->ldapCreatedGroups[$key]);
|
|
}
|
|
$this->rememberThatGroupIsNotExpectedToExist($group);
|
|
}
|
|
|
|
/**
|
|
* @param string|null $username
|
|
* @param string|null $ou
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function deleteLdapUser(?string $username, ?string $ou = null): void {
|
|
if (!\in_array($username, $this->ldapCreatedUsers)) {
|
|
throw new Error(
|
|
"User " . $username . " was not created using Ldap and does not exist as an Ldap User",
|
|
);
|
|
}
|
|
if ($ou === null) {
|
|
$ou = $this->getLdapUsersOU();
|
|
}
|
|
$entry = "uid=$username,ou=$ou";
|
|
$this->deleteTheLdapEntry($entry);
|
|
$key = \array_search($username, $this->ldapCreatedUsers);
|
|
if ($key !== false) {
|
|
unset($this->ldapCreatedUsers[$key]);
|
|
}
|
|
$this->rememberThatUserIsNotExpectedToExist($username);
|
|
}
|
|
|
|
/**
|
|
* @Given /^user "([^"]*)" has been disabled$/
|
|
*
|
|
* @param string|null $user
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function adminHasDisabledUserUsingTheProvisioningApi(?string $user): void {
|
|
$user = $this->getActualUsername($user);
|
|
if (OcisHelper::isTestingOnReva()) {
|
|
$response = $this->disableOrEnableUser($this->getAdminUsername(), $user, 'disable');
|
|
} else {
|
|
$response = $this->graphContext->editUserUsingTheGraphApi(
|
|
$this->getAdminUsername(),
|
|
$user,
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
false,
|
|
);
|
|
}
|
|
Assert::assertEquals(
|
|
200,
|
|
$response->getStatusCode(),
|
|
__METHOD__
|
|
. " Expected status code is 200 but received " . $response->getStatusCode()
|
|
. "\nResponse body: " . $response->getBody(),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $user
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function deleteUser(string $user): ResponseInterface {
|
|
// Always try to delete the user
|
|
if (OcisHelper::isTestingOnReva()) {
|
|
$response = UserHelper::deleteUser(
|
|
$this->getBaseUrl(),
|
|
$user,
|
|
$this->getAdminUsername(),
|
|
$this->getAdminPassword(),
|
|
$this->ocsApiVersion,
|
|
);
|
|
} else {
|
|
// users can be deleted using the username in the GraphApi too
|
|
$response = $this->graphContext->adminDeletesUserUsingTheGraphApi($user);
|
|
}
|
|
if ($response->getStatusCode() === 204) {
|
|
$this->rememberThatUserIsNotExpectedToExist($user);
|
|
}
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* @Given /^group "([^"]*)" has been deleted$/
|
|
*
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
* @throws GuzzleException
|
|
*/
|
|
public function groupHasBeenDeleted(string $group): void {
|
|
if ($this->isTestingWithLdap()) {
|
|
$this->deleteLdapGroup($group);
|
|
} else {
|
|
$response = $this->graphContext->deleteGroupWithName($group);
|
|
$this->theHTTPStatusCodeShouldBe(204, "", $response);
|
|
}
|
|
$this->rememberThatGroupIsNotExpectedToExist($group);
|
|
Assert::assertFalse(
|
|
$this->groupExists($group),
|
|
"Group '$group' should not exist but does exist",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param string $group
|
|
*
|
|
* @return bool
|
|
* @throws Exception
|
|
* @throws GuzzleException
|
|
*/
|
|
public function groupExists(string $group): bool {
|
|
if ($this->isTestingWithLdap()) {
|
|
$baseDN = $this->getLdapBaseDN();
|
|
$newDN = 'cn=' . $group . ',ou=' . $this->ldapGroupsOU . ',' . $baseDN;
|
|
if ($this->ldap->getEntry($newDN) !== null) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
$group = \rawurlencode($group);
|
|
$fullUrl = $this->getBaseUrl() . "/graph/v1.0/groups/$group";
|
|
$this->response = HttpRequestHelper::get(
|
|
$fullUrl,
|
|
$this->getAdminUsername(),
|
|
$this->getAdminPassword(),
|
|
);
|
|
if ($this->response->getStatusCode() >= 400) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @Given user :user has been removed from group :group
|
|
*
|
|
* @param string $user
|
|
* @param string $group
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function adminHasRemovedUserFromGroup(string $user, string $group): void {
|
|
$user = $this->getActualUsername($user);
|
|
if ($this->isTestingWithLdap()
|
|
&& !$this->isLocalAdminGroup($group)
|
|
&& \in_array($group, $this->ldapCreatedGroups)
|
|
) {
|
|
$this->removeUserFromLdapGroup($user, $group);
|
|
} else {
|
|
$response = $this->graphContext->removeUserFromGroup($group, $user);
|
|
$this->TheHTTPStatusCodeShouldBe(204, '', $response);
|
|
}
|
|
|
|
if (OcisHelper::isTestingOnReva()) {
|
|
$fullUrl = $this->getBaseUrl() . "/ocs/v2.php/cloud/users/$user/groups";
|
|
$response = HttpRequestHelper::get(
|
|
$fullUrl,
|
|
$this->getAdminUsername(),
|
|
$this->getAdminPassword(),
|
|
);
|
|
$respondedArray = $this->getArrayOfGroupsResponded($response);
|
|
\sort($respondedArray);
|
|
Assert::assertNotContains($group, $respondedArray);
|
|
Assert::assertEquals(
|
|
200,
|
|
$response->getStatusCode(),
|
|
);
|
|
} else {
|
|
$this->graphContext->userShouldNotBeMemberInGroupUsingTheGraphApi($user, $group);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @Then /^the users returned by the API should be$/
|
|
*
|
|
* @param TableNode $usersList
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function theUsersShouldBe(TableNode $usersList): void {
|
|
$this->verifyTableNodeColumnsCount($usersList, 1);
|
|
$users = $usersList->getRows();
|
|
$usersSimplified = \array_map(
|
|
function ($user) {
|
|
return $this->getActualUsername($user);
|
|
},
|
|
$this->simplifyArray($users),
|
|
);
|
|
if ($this->isTestingWithLdap()) {
|
|
$respondedArray = $this->getArrayOfUsersResponded($this->response);
|
|
Assert::assertEqualsCanonicalizing(
|
|
$usersSimplified,
|
|
$respondedArray,
|
|
__METHOD__
|
|
. " Provided users do not match the users returned in the response.",
|
|
);
|
|
} else {
|
|
$this->graphContext->theseUsersShouldBeInTheResponse($usersSimplified);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses the xml answer to get the array of users returned.
|
|
*
|
|
* @param ResponseInterface $resp
|
|
*
|
|
* @return array
|
|
* @throws Exception
|
|
*/
|
|
public function getArrayOfUsersResponded(ResponseInterface $resp): array {
|
|
$listCheckedElements = HttpRequestHelper::getResponseXml($resp, __METHOD__)->data[0]->users[0]->element;
|
|
return \json_decode(\json_encode($listCheckedElements), true);
|
|
}
|
|
|
|
/**
|
|
* Parses the xml answer to get the array of groups returned.
|
|
*
|
|
* @param ResponseInterface $resp
|
|
*
|
|
* @return array
|
|
* @throws Exception
|
|
*/
|
|
public function getArrayOfGroupsResponded(ResponseInterface $resp): array {
|
|
$listCheckedElements
|
|
= HttpRequestHelper::getResponseXml($resp, __METHOD__)->data[0]->groups[0]->element;
|
|
return \json_decode(\json_encode($listCheckedElements), true);
|
|
}
|
|
|
|
/**
|
|
* Parses the xml answer to get the array of apps returned.
|
|
*
|
|
* @param ResponseInterface $resp
|
|
*
|
|
* @return array
|
|
* @throws Exception
|
|
*/
|
|
public function getArrayOfAppsResponded(ResponseInterface $resp): array {
|
|
$listCheckedElements = HttpRequestHelper::getResponseXml($resp, __METHOD__)->data[0]->apps[0]->element;
|
|
return \json_decode(\json_encode($listCheckedElements), true);
|
|
}
|
|
|
|
/**
|
|
* @Then /^the API should not return any data$/
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function theApiShouldNotReturnAnyData(): void {
|
|
$responseData = HttpRequestHelper::getResponseXml($this->response, __METHOD__)->data[0];
|
|
Assert::assertEmpty(
|
|
$responseData,
|
|
"Response data is not empty but it should be empty",
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @AfterScenario
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function afterScenario(): void {
|
|
if (OcisHelper::isTestingOnReva()) {
|
|
OcisHelper::deleteRevaUserData($this->getCreatedUsers());
|
|
}
|
|
|
|
if ($this->isTestingWithLdap()) {
|
|
$this->deleteLdapUsersAndGroups();
|
|
}
|
|
$this->cleanupDatabaseUsers();
|
|
$this->cleanupDatabaseGroups();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function cleanupDatabaseUsers(): void {
|
|
$previousServer = $this->currentServer;
|
|
foreach ($this->createdUsers as $userData) {
|
|
// do not try to delete if user doesn't exist
|
|
if (!$userData["shouldExist"]) {
|
|
continue;
|
|
}
|
|
$this->usingServer($userData["serverType"]);
|
|
|
|
$user = $userData['actualUsername'];
|
|
$response = $this->deleteUser($user);
|
|
$this->theHTTPStatusCodeShouldBe(204, "Failed to delete user '$user'", $response);
|
|
Assert::assertFalse(
|
|
$this->userExists($user),
|
|
"User '$user' should not exist but does exist",
|
|
);
|
|
}
|
|
$this->usingServer($previousServer);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function cleanupDatabaseGroups(): void {
|
|
$previousServer = $this->currentServer;
|
|
$this->usingServer('LOCAL');
|
|
foreach ($this->createdGroups as $group => $groupData) {
|
|
if ($groupData["possibleToDelete"]) {
|
|
if ($this->isTestingWithLdap()) {
|
|
$this->cleanupGroup((string)$group);
|
|
} else {
|
|
$response = $this->graphContext->deleteGroupWithId($groupData['id']);
|
|
$this->theHTTPStatusCodeShouldBe(204, "", $response);
|
|
}
|
|
}
|
|
}
|
|
$this->usingServer('REMOTE');
|
|
foreach ($this->createdRemoteGroups as $remoteGroup => $groupData) {
|
|
if ($groupData["possibleToDelete"]) {
|
|
if ($this->isTestingWithLdap()) {
|
|
$this->cleanupGroup((string)$remoteGroup);
|
|
} else {
|
|
$response = $this->graphContext->deleteGroupWithId($groupData['id']);
|
|
$this->theHTTPStatusCodeShouldBe(204, "", $response);
|
|
}
|
|
}
|
|
}
|
|
$this->usingServer($previousServer);
|
|
}
|
|
|
|
/**
|
|
* @BeforeScenario @rememberGroupsThatExist
|
|
*
|
|
* @return void
|
|
* @throws Exception
|
|
*/
|
|
public function rememberGroupsThatExistAtTheStartOfTheScenario(): void {
|
|
$this->startingGroups = $this->getArrayOfGroupsResponded($this->getAllGroups());
|
|
}
|
|
|
|
/**
|
|
* disable or enable user
|
|
*
|
|
* @param string $user
|
|
* @param string $otherUser
|
|
* @param string $action
|
|
*
|
|
* @return void
|
|
*/
|
|
public function disableOrEnableUser(string $user, string $otherUser, string $action): ResponseInterface {
|
|
$actualUser = $this->getActualUsername($user);
|
|
$actualPassword = $this->getPasswordForUser($actualUser);
|
|
$actualOtherUser = $this->getActualUsername($otherUser);
|
|
|
|
$fullUrl = $this->getBaseUrl()
|
|
. "/ocs/v$this->ocsApiVersion.php/cloud/users/$actualOtherUser/$action";
|
|
return HttpRequestHelper::put(
|
|
$fullUrl,
|
|
$actualUser,
|
|
$actualPassword,
|
|
);
|
|
}
|
|
}
|