mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-21 12:09:40 -06:00
multiTenancyTests (#1313)
* multiTenancyTests * fix linter issues * fix after review
This commit is contained in:
@@ -33,6 +33,7 @@ PLUGINS_S3_CACHE = "plugins/s3-cache:1"
|
||||
PLUGINS_SLACK = "plugins/slack:1"
|
||||
REDIS = "redis:6-alpine"
|
||||
READY_RELEASE_GO = "woodpeckerci/plugin-ready-release-go:latest"
|
||||
OPENLDAP = "bitnami/openldap:2.6"
|
||||
|
||||
DEFAULT_PHP_VERSION = "8.2"
|
||||
DEFAULT_NODEJS_VERSION = "20"
|
||||
@@ -113,7 +114,7 @@ config = {
|
||||
"skip": False,
|
||||
"withRemotePhp": [True],
|
||||
"emailNeeded": True,
|
||||
"extraEnvironment": {
|
||||
"extraTestEnvironment": {
|
||||
"EMAIL_HOST": "email",
|
||||
"EMAIL_PORT": "9000",
|
||||
},
|
||||
@@ -207,7 +208,7 @@ config = {
|
||||
"skip": False,
|
||||
"withRemotePhp": [True],
|
||||
"emailNeeded": True,
|
||||
"extraEnvironment": {
|
||||
"extraTestEnvironment": {
|
||||
"EMAIL_HOST": "email",
|
||||
"EMAIL_PORT": "9000",
|
||||
},
|
||||
@@ -250,7 +251,7 @@ config = {
|
||||
"withRemotePhp": [True],
|
||||
"federationServer": True,
|
||||
"emailNeeded": True,
|
||||
"extraEnvironment": {
|
||||
"extraTestEnvironment": {
|
||||
"EMAIL_HOST": "email",
|
||||
"EMAIL_PORT": "9000",
|
||||
},
|
||||
@@ -300,6 +301,36 @@ config = {
|
||||
"STORAGE_USERS_DRIVER": "decomposed",
|
||||
},
|
||||
},
|
||||
"multiTenancy": {
|
||||
"suites": [
|
||||
"apiTenancy",
|
||||
],
|
||||
"skip": False,
|
||||
"withRemotePhp": [True],
|
||||
"ldapNeeded": True,
|
||||
"extraTestEnvironment": {
|
||||
"USE_PREPARED_LDAP_USERS": True,
|
||||
},
|
||||
"extraServerEnvironment": {
|
||||
"OC_LDAP_USER_SCHEMA_TENANT_ID": "departmentNumber",
|
||||
"OC_LDAP_URI": "ldaps://ldap-server:1636",
|
||||
"OC_LDAP_INSECURE": True,
|
||||
"OC_LDAP_BIND_DN": "cn=admin,dc=opencloud,dc=eu",
|
||||
"OC_LDAP_BIND_PASSWORD": "admin",
|
||||
"OC_LDAP_GROUP_BASE_DN": "ou=groups,dc=opencloud,dc=eu",
|
||||
"OC_LDAP_GROUP_SCHEMA_ID": "entryUUID",
|
||||
"OC_LDAP_USER_BASE_DN": "ou=users,dc=opencloud,dc=eu",
|
||||
"OC_LDAP_USER_FILTER": "(objectclass=inetOrgPerson)",
|
||||
"OC_LDAP_USER_SCHEMA_ID": "entryUUID",
|
||||
"OC_LDAP_DISABLE_USER_MECHANISM": "none",
|
||||
"GRAPH_LDAP_SERVER_UUID": True,
|
||||
"GRAPH_LDAP_GROUP_CREATE_BASE_DN": "ou=custom,ou=groups,dc=opencloud,dc=eu",
|
||||
"GRAPH_LDAP_REFINT_ENABLED": True,
|
||||
"FRONTEND_READONLY_USER_ATTRIBUTES": "user.onPremisesSamAccountName,user.displayName,user.mail,user.passwordProfile,user.accountEnabled,user.appRoleAssignments",
|
||||
"OC_LDAP_SERVER_WRITE_ENABLED": False,
|
||||
"OC_EXCLUDE_RUN_SERVICES": "idm",
|
||||
},
|
||||
},
|
||||
},
|
||||
"apiTests": {
|
||||
"numberOfParts": 7,
|
||||
@@ -913,7 +944,7 @@ def localApiTestPipeline(ctx):
|
||||
defaults = {
|
||||
"suites": {},
|
||||
"skip": False,
|
||||
"extraEnvironment": {},
|
||||
"extraTestEnvironment": {},
|
||||
"extraServerEnvironment": {},
|
||||
"storages": storages,
|
||||
"accounts_hash_difficulty": 4,
|
||||
@@ -924,6 +955,7 @@ def localApiTestPipeline(ctx):
|
||||
"collaborationServiceNeeded": False,
|
||||
"extraCollaborationEnvironment": {},
|
||||
"withRemotePhp": with_remote_php,
|
||||
"ldapNeeded": False,
|
||||
}
|
||||
|
||||
if "localApiTests" in config:
|
||||
@@ -941,11 +973,13 @@ def localApiTestPipeline(ctx):
|
||||
(waitForServices("online-offices", ["collabora:9980", "onlyoffice:443", "fakeoffice:8080"]) if params["collaborationServiceNeeded"] else []) +
|
||||
(waitForClamavService() if params["antivirusNeeded"] else []) +
|
||||
(waitForEmailService() if params["emailNeeded"] else []) +
|
||||
(ldapService() if params["ldapNeeded"] else []) +
|
||||
(waitForLdapService() if params["ldapNeeded"] else []) +
|
||||
opencloudServer(storage, params["accounts_hash_difficulty"], extra_server_environment = params["extraServerEnvironment"], with_wrapper = True, tika_enabled = params["tikaNeeded"]) +
|
||||
(opencloudServer(storage, params["accounts_hash_difficulty"], deploy_type = "federation", extra_server_environment = params["extraServerEnvironment"]) if params["federationServer"] else []) +
|
||||
((wopiCollaborationService("fakeoffice") + wopiCollaborationService("collabora") + wopiCollaborationService("onlyoffice")) if params["collaborationServiceNeeded"] else []) +
|
||||
(openCloudHealthCheck("wopi", ["wopi-collabora:9304", "wopi-onlyoffice:9304", "wopi-fakeoffice:9304"]) if params["collaborationServiceNeeded"] else []) +
|
||||
localApiTests(name, params["suites"], storage, params["extraEnvironment"], run_with_remote_php) +
|
||||
localApiTests(name, params["suites"], storage, params["extraTestEnvironment"], run_with_remote_php) +
|
||||
logRequests(),
|
||||
"services": (emailService() if params["emailNeeded"] else []) +
|
||||
(clamavService() if params["antivirusNeeded"] else []) +
|
||||
@@ -2823,6 +2857,49 @@ def waitForClamavService():
|
||||
],
|
||||
}]
|
||||
|
||||
def ldapService():
|
||||
return [
|
||||
{
|
||||
"name": "ldap-server",
|
||||
"image": OPENLDAP,
|
||||
"detach": True,
|
||||
"environment": {
|
||||
"BITNAMI_DEBUG": "true",
|
||||
"LDAP_TLS_VERIFY_CLIENT": "never",
|
||||
"LDAP_ENABLE_TLS": "yes",
|
||||
"LDAP_TLS_CA_FILE": "/opt/bitnami/openldap/share/openldap.crt",
|
||||
"LDAP_TLS_CERT_FILE": "/opt/bitnami/openldap/share/openldap.crt",
|
||||
"LDAP_TLS_KEY_FILE": "/opt/bitnami/openldap/share/openldap.key",
|
||||
"LDAP_ROOT": "dc=opencloud,dc=eu",
|
||||
"LDAP_ADMIN_PASSWORD": "admin",
|
||||
},
|
||||
"commands": [
|
||||
"mkdir -p /opt/bitnami/openldap/share",
|
||||
"mkdir -p /tmp/custom-scripts",
|
||||
"mkdir -p /tmp/ldif-files",
|
||||
"cp tests/config/woodpecker/ldap/*.ldif /tmp/ldif-files/",
|
||||
"cp tests/config/woodpecker/ldap/docker-entrypoint-override.sh /tmp/custom-scripts/",
|
||||
"chmod +x /tmp/custom-scripts/docker-entrypoint-override.sh",
|
||||
"ls -la /tmp/ldif-files/",
|
||||
"/tmp/custom-scripts/docker-entrypoint-override.sh /opt/bitnami/scripts/openldap/run.sh",
|
||||
],
|
||||
"backend_options": {
|
||||
"docker": {
|
||||
"user": "0:0",
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
def waitForLdapService():
|
||||
return [{
|
||||
"name": "wait-for-ldap",
|
||||
"image": OC_CI_WAIT_FOR,
|
||||
"commands": [
|
||||
"wait-for -it ldap-server:1636 -t 600",
|
||||
],
|
||||
}]
|
||||
|
||||
def fakeOffice():
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -344,8 +344,8 @@ class GraphHelper {
|
||||
/**
|
||||
* @param string $baseUrl
|
||||
* @param string $xRequestId
|
||||
* @param string $adminUser
|
||||
* @param string $adminPassword
|
||||
* @param string $user
|
||||
* @param string $password
|
||||
* @param string $searchTerm
|
||||
*
|
||||
* @return ResponseInterface
|
||||
@@ -353,16 +353,16 @@ class GraphHelper {
|
||||
public static function searchUser(
|
||||
string $baseUrl,
|
||||
string $xRequestId,
|
||||
string $adminUser,
|
||||
string $adminPassword,
|
||||
string $user,
|
||||
string $password,
|
||||
string $searchTerm
|
||||
): ResponseInterface {
|
||||
$url = self::getFullUrl($baseUrl, "users?\$search=$searchTerm");
|
||||
return HttpRequestHelper::get(
|
||||
$url,
|
||||
$xRequestId,
|
||||
$adminUser,
|
||||
$adminPassword,
|
||||
$user,
|
||||
$password,
|
||||
self::getRequestHeaders()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -89,6 +89,13 @@ class OcHelper {
|
||||
return (\getenv("TEST_REVA") === "true");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function isUsingPreparedLdapUsers(): bool {
|
||||
return (\getenv("USE_PREPARED_LDAP_USERS") === "true");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string false if no command given or the command as string
|
||||
*/
|
||||
|
||||
@@ -450,7 +450,7 @@ class SpacesContext implements Context {
|
||||
* @throws Exception|GuzzleException
|
||||
*/
|
||||
public function cleanDataAfterTests(): void {
|
||||
if (OcHelper::isTestingOnReva()) {
|
||||
if (OcHelper::isTestingOnReva() || OcHelper::isUsingPreparedLdapUsers()) {
|
||||
return;
|
||||
}
|
||||
$this->deleteAllProjectSpaces();
|
||||
|
||||
@@ -442,6 +442,13 @@ default:
|
||||
- AuthAppContext:
|
||||
- CliContext:
|
||||
- OcConfigContext:
|
||||
|
||||
apiTenancy:
|
||||
paths:
|
||||
- "%paths.base%/../features/apiTenancy"
|
||||
context: *common_ldap_suite_context
|
||||
contexts:
|
||||
- FeatureContext: *common_feature_context_params
|
||||
|
||||
cliCommands:
|
||||
paths:
|
||||
|
||||
77
tests/acceptance/features/apiTenancy/mutltiTenancy.feature
Normal file
77
tests/acceptance/features/apiTenancy/mutltiTenancy.feature
Normal file
@@ -0,0 +1,77 @@
|
||||
Feature: Multi-tenancy
|
||||
I want to make sure that users from different tenants are isolated from each other,
|
||||
so that each tenant's data and users remain private and secure.
|
||||
|
||||
Note:
|
||||
All users are managed via LDAP and are assumed to exist.
|
||||
Tests will use existing users without creating or deleting them.
|
||||
|
||||
Prepared LDAP users:
|
||||
| user | tenant | group |
|
||||
|-------|----------|----------------------|
|
||||
| alice | tenant-1 | new-features-lovers |
|
||||
| brian | tenant-1 | - |
|
||||
| carol | tenant-2 | - |
|
||||
| david | tenant-2 | release-lover |
|
||||
|
||||
|
||||
Scenario: users from the same tenant can see each other
|
||||
When user "Brian" searches for user "ali" using Graph API
|
||||
Then the HTTP status code should be "200"
|
||||
And the JSON data of the response should match
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["value"],
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"maxItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"displayName",
|
||||
"id",
|
||||
"onPremisesSamAccountName",
|
||||
"userType"
|
||||
],
|
||||
"properties": {
|
||||
"displayName": {
|
||||
"const": "Alice Hansen"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
|
||||
},
|
||||
"onPremisesSamAccountName": {
|
||||
"const": ""
|
||||
},
|
||||
"userType": {
|
||||
"const": "Member"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
Scenario: users from different tenants cannot see each other
|
||||
When user "David" searches for user "brian" using Graph API
|
||||
Then the HTTP status code should be "200"
|
||||
And the JSON data of the response should match
|
||||
"""
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["value"],
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "array",
|
||||
"minItems": 0,
|
||||
"maxItems": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
25
tests/config/woodpecker/ldap/10_base.ldif
Normal file
25
tests/config/woodpecker/ldap/10_base.ldif
Normal file
@@ -0,0 +1,25 @@
|
||||
dn: dc=opencloud,dc=eu
|
||||
objectClass: organization
|
||||
objectClass: dcObject
|
||||
dc: opencloud
|
||||
o: openCloud
|
||||
|
||||
dn: ou=users,dc=opencloud,dc=eu
|
||||
objectClass: organizationalUnit
|
||||
ou: users
|
||||
|
||||
dn: cn=admin,dc=opencloud,dc=eu
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: person
|
||||
cn: admin
|
||||
sn: admin
|
||||
uid: ldapadmin
|
||||
departmentNumber: {{ .TenantID }}
|
||||
|
||||
dn: ou=groups,dc=opencloud,dc=eu
|
||||
objectClass: organizationalUnit
|
||||
ou: groups
|
||||
|
||||
dn: ou=custom,ou=groups,dc=opencloud,dc=eu
|
||||
objectClass: organizationalUnit
|
||||
ou: custom
|
||||
74
tests/config/woodpecker/ldap/20_users.ldif
Normal file
74
tests/config/woodpecker/ldap/20_users.ldif
Normal file
@@ -0,0 +1,74 @@
|
||||
dn: uid=alice,ou=users,dc=opencloud,dc=eu
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: alice
|
||||
givenName: Alice
|
||||
sn: Hansen
|
||||
cn: alice
|
||||
displayName: Alice Hansen
|
||||
description: Senior DevOps engineer responsible for cloud infrastructure automation.
|
||||
mail: alice@example.org
|
||||
departmentNumber: tenant-1
|
||||
userPassword:: e1NTSEF9eGY5OXlPOXVxSVJ5eTFxdFhQYVYxTnd6WE4wUWRReVU=
|
||||
|
||||
dn: uid=brian,ou=users,dc=opencloud,dc=eu
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: brian
|
||||
givenName: Brian
|
||||
sn: Murphy
|
||||
cn: brian
|
||||
displayName: Brian Murphy
|
||||
description: IT support specialist focused on end-user systems and service desk operations.
|
||||
mail: brian@example.org
|
||||
departmentNumber: tenant-1
|
||||
userPassword:: e1NTSEF9Y0xpdnEzdUxzNzB3SjU0R1dmR0EybndxbUZoRmNoOXQ=
|
||||
|
||||
dn: uid=carol,ou=users,dc=opencloud,dc=eu
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: carol
|
||||
givenName: Carol
|
||||
sn: King
|
||||
cn: carol
|
||||
displayName: Carol King
|
||||
description: Project manager leading enterprise IT solutions and digital transformation projects.
|
||||
mail: carol@example.org
|
||||
departmentNumber: tenant-2
|
||||
userPassword:: e1NTSEF9bWFiT2FyNEE4UWlJUm1Pb2JhNm1pYm1QMjQraDkzSEw=
|
||||
|
||||
dn: uid=david,ou=users,dc=opencloud,dc=eu
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: david
|
||||
givenName: David
|
||||
sn: Lopez
|
||||
cn: david
|
||||
displayName: David Lopez
|
||||
description: Systems architect working on scalable backend services and platform reliability.
|
||||
mail: david@example.org
|
||||
departmentNumber: tenant-2
|
||||
userPassword:: e1NTSEF9MEh2a3J0UTVONmZNSUhyL1NlWVQvclBYTjg0bi9SYlc=
|
||||
|
||||
dn: uid=admin,ou=users,dc=opencloud,dc=eu
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: admin
|
||||
givenName: Admin
|
||||
sn: Admin
|
||||
cn: Admin
|
||||
displayName: Admin
|
||||
description: System administrator
|
||||
mail: admin@example.org
|
||||
departmentNumber: tenant-1
|
||||
userPassword:: e1NTSEF9bFU2dDRHSC9Cb28wV2lnM1A0SVAzQTIyWE9aL2pCa1M=
|
||||
13
tests/config/woodpecker/ldap/30_groups.ldif
Normal file
13
tests/config/woodpecker/ldap/30_groups.ldif
Normal file
@@ -0,0 +1,13 @@
|
||||
dn: cn=new-features-lovers,ou=groups,dc=opencloud,dc=eu
|
||||
objectClass: groupOfNames
|
||||
objectClass: top
|
||||
cn: new-features-lovers
|
||||
description: New features lovers
|
||||
member: uid=alice,ou=users,dc=opencloud,dc=eu
|
||||
|
||||
dn: cn=release-lovers,ou=groups,dc=opencloud,dc=eu
|
||||
objectClass: groupOfNames
|
||||
objectClass: top
|
||||
cn: release-lovers
|
||||
description: Release lovers
|
||||
member: uid=david,ou=users,dc=opencloud,dc=eu
|
||||
42
tests/config/woodpecker/ldap/docker-entrypoint-override.sh
Normal file
42
tests/config/woodpecker/ldap/docker-entrypoint-override.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
printenv
|
||||
|
||||
if [ ! -f /opt/bitnami/openldap/share/openldap.key ]
|
||||
then
|
||||
openssl req -x509 -newkey rsa:4096 -keyout /opt/bitnami/openldap/share/openldap.key -out /opt/bitnami/openldap/share/openldap.crt -sha256 -days 365 -batch -nodes
|
||||
fi
|
||||
|
||||
mkdir -p /opt/bitnami/openldap/ldifs
|
||||
|
||||
if [ -d "/tmp/ldif-files" ]; then
|
||||
cp /tmp/ldif-files/*.ldif /opt/bitnami/openldap/ldifs/
|
||||
fi
|
||||
|
||||
/opt/bitnami/scripts/openldap/entrypoint.sh "$@" &
|
||||
ENTRYPOINT_PID=$!
|
||||
|
||||
echo "Waiting for LDAP server to start..."
|
||||
while ! ldapsearch -x -H ldap://localhost:1389 -D "cn=admin,dc=opencloud,dc=eu" -w admin -b "dc=opencloud,dc=eu" > /dev/null 2>&1; do
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "LDAP server is running, importing LDIF files..."
|
||||
|
||||
if [ -f "/opt/bitnami/openldap/ldifs/10_base.ldif" ]; then
|
||||
echo "Importing 10_base.ldif..."
|
||||
ldapadd -x -H ldap://localhost:1389 -D "cn=admin,dc=opencloud,dc=eu" -w admin -f /opt/bitnami/openldap/ldifs/10_base.ldif
|
||||
fi
|
||||
|
||||
if [ -f "/opt/bitnami/openldap/ldifs/20_users.ldif" ]; then
|
||||
echo "Importing 20_users.ldif..."
|
||||
ldapadd -x -H ldap://localhost:1389 -D "cn=admin,dc=opencloud,dc=eu" -w admin -f /opt/bitnami/openldap/ldifs/20_users.ldif
|
||||
fi
|
||||
|
||||
if [ -f "/opt/bitnami/openldap/ldifs/30_groups.ldif" ]; then
|
||||
echo "Importing 30_groups.ldif..."
|
||||
ldapadd -x -H ldap://localhost:1389 -D "cn=admin,dc=opencloud,dc=eu" -w admin -f /opt/bitnami/openldap/ldifs/30_groups.ldif
|
||||
fi
|
||||
|
||||
echo "LDIF import completed!"
|
||||
|
||||
wait $ENTRYPOINT_PID
|
||||
Reference in New Issue
Block a user