015c622016
Add 162 integration tests covering authentication flows, TOTP MFA, SSH key/certificate management, organization workflows, multi-org access, self-service features, admin operations, authorization, security edge cases, department/principal management, CA management, policy compliance, WebAuthn passkeys, and ZeroTier network access. Includes: - Reusable API client library with session management - Test fixtures for users, organizations, memberships, and CAs - Helper functions for SSH key generation and verification - Documentation for running and writing tests Also update test configuration to disable conflicting maas plugins and configure WebAuthn/session settings for localhost testing.
88 lines
4.1 KiB
Python
88 lines
4.1 KiB
Python
"""Multi-organization access integration tests.
|
|
|
|
Covers cross-org isolation and role-based access control scenarios.
|
|
"""
|
|
import pytest
|
|
import uuid
|
|
|
|
from tests.integration.client.base import ApiError
|
|
from gatehouse_app.utils.constants import OrganizationRole
|
|
|
|
|
|
def assert_success(response: dict, message_contains: str = "") -> dict:
|
|
data = response.get("data", {})
|
|
assert response.get("success") is not False
|
|
if message_contains:
|
|
assert message_contains.lower() in response.get("message", "").lower()
|
|
return data
|
|
|
|
|
|
def assert_error(exc: ApiError, expected_status: int, expected_error_type: str | None = None):
|
|
assert exc.status_code == expected_status
|
|
if expected_error_type:
|
|
assert exc.error_type == expected_error_type
|
|
|
|
|
|
class TestMultiOrgAccess:
|
|
"""Test users in multiple organizations."""
|
|
|
|
def test_user_in_multiple_orgs_positive(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: MULTIORG-01 — User in multiple orgs with different roles.
|
|
|
|
WHAT: Create a user who is ADMIN in Org A and MEMBER in Org B,
|
|
then GET /users/me/organizations.
|
|
WHY: The org selector must show all orgs with correct roles.
|
|
EXPECTED: 200 OK with both orgs and correct roles.
|
|
"""
|
|
user = create_test_user(password="MyPassword123!")
|
|
org_a = create_test_org(name="Org A", slug=f"org-a-{uuid.uuid4().hex[:6]}")
|
|
org_b = create_test_org(name="Org B", slug=f"org-b-{uuid.uuid4().hex[:6]}")
|
|
create_test_membership(user["id"], org_a["id"], OrganizationRole.ADMIN)
|
|
create_test_membership(user["id"], org_b["id"], OrganizationRole.MEMBER)
|
|
|
|
integration_client.auth.login(email=user["email"], password="MyPassword123!")
|
|
result = integration_client.users.get_my_organizations()
|
|
data = assert_success(result)
|
|
orgs = data.get("organizations", [])
|
|
assert len(orgs) == 2, f"Expected 2 orgs, got {len(orgs)}"
|
|
|
|
def test_cross_org_admin_operation_blocked_negative(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: MULTIORG-02 — Cross-org admin operation blocked.
|
|
|
|
WHAT: User is ADMIN in Org A and MEMBER in Org B. Attempt to
|
|
perform an admin operation in Org B.
|
|
WHY: Role scopes must be per-organization.
|
|
EXPECTED: 403 Forbidden.
|
|
"""
|
|
user = create_test_user(password="MyPassword123!")
|
|
org_a = create_test_org(name="Org A", slug=f"org-a-{uuid.uuid4().hex[:6]}")
|
|
org_b = create_test_org(name="Org B", slug=f"org-b-{uuid.uuid4().hex[:6]}")
|
|
create_test_membership(user["id"], org_a["id"], OrganizationRole.ADMIN)
|
|
create_test_membership(user["id"], org_b["id"], OrganizationRole.MEMBER)
|
|
victim = create_test_user(password="VictimPass123!")
|
|
create_test_membership(victim["id"], org_b["id"], OrganizationRole.MEMBER)
|
|
|
|
integration_client.auth.login(email=user["email"], password="MyPassword123!")
|
|
with pytest.raises(ApiError) as exc_info:
|
|
integration_client.orgs.remove_member(org_b["id"], victim["id"])
|
|
|
|
assert exc_info.value.status_code == 403
|
|
|
|
def test_list_memberships_positive(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: MULTIORG-04 — List memberships across orgs.
|
|
|
|
WHAT: User in multiple orgs calls GET /users/me/memberships.
|
|
WHY: The memberships page shows orgs, departments, principals.
|
|
EXPECTED: 200 OK with orgs array.
|
|
"""
|
|
user = create_test_user(password="MyPassword123!")
|
|
org_a = create_test_org(name="Org A", slug=f"org-a-{uuid.uuid4().hex[:6]}")
|
|
org_b = create_test_org(name="Org B", slug=f"org-b-{uuid.uuid4().hex[:6]}")
|
|
create_test_membership(user["id"], org_a["id"], OrganizationRole.ADMIN)
|
|
create_test_membership(user["id"], org_b["id"], OrganizationRole.MEMBER)
|
|
|
|
integration_client.auth.login(email=user["email"], password="MyPassword123!")
|
|
result = integration_client.users.get_my_memberships()
|
|
data = assert_success(result)
|
|
assert "orgs" in data
|