Post-login lands on Spaces empty state instead of a principal dump. Profile menu exposes Session details with identity, tenant, roles/groups, and authz diagnostics for operator refinement (CSOC-WP-0004 T01/T07).
132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
import pytest
|
|
from django.urls import reverse
|
|
|
|
from coulomb_social.apps.identity.services import establish_session
|
|
from coulomb_social.apps.identity.user_engine import IdentityClaims
|
|
from coulomb_social.apps.members.models import Member, User
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_healthz(client):
|
|
r = client.get("/healthz")
|
|
assert r.status_code == 200
|
|
assert r.json()["status"] == "ok"
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_landing_public(client):
|
|
r = client.get(reverse("core:landing"))
|
|
assert r.status_code == 200
|
|
assert b"Sign in" in r.content
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_registration_link_uses_only_configured_destination(client, settings):
|
|
settings.NETKINGDOM_REGISTRATION_URL = (
|
|
"https://users.coulomb.social/register?client_id=coulomb-social"
|
|
)
|
|
r = client.get(reverse("identity:register") + "?next=https://evil.example")
|
|
assert r.status_code == 302
|
|
assert r["Location"] == settings.NETKINGDOM_REGISTRATION_URL
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_app_home_requires_login(client):
|
|
r = client.get(reverse("core:app_home"))
|
|
assert r.status_code == 302
|
|
assert reverse("identity:login") in r["Location"]
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_dev_login_lands_on_app_home_not_principal_dump(client, settings):
|
|
settings.DEBUG = True
|
|
settings.OIDC_ENABLED = False
|
|
|
|
r = client.post(
|
|
reverse("identity:dev_login"),
|
|
{
|
|
"subject": "sub-abc",
|
|
"issuer": "https://local.dev/issuer",
|
|
"name": "Ada Lovelace",
|
|
"email": "ada@example.com",
|
|
"preferred_username": "ada",
|
|
},
|
|
)
|
|
assert r.status_code == 302
|
|
assert reverse("core:app_home") in r["Location"]
|
|
|
|
member = Member.objects.get(subject="sub-abc")
|
|
assert member.tenant_id == settings.DEFAULT_TENANT_ID
|
|
assert member.display_name == "Ada Lovelace"
|
|
assert member.user_engine_user_id
|
|
assert member.user.has_usable_password() is False
|
|
|
|
home = client.get(reverse("core:app_home"))
|
|
assert home.status_code == 200
|
|
assert b"Spaces" in home.content
|
|
assert b"No spaces yet" in home.content
|
|
# Principal dump moved off the home body
|
|
assert b"user-engine id" not in home.content
|
|
assert b"sub-abc" not in home.content
|
|
# Profile chrome shows display name
|
|
assert b"Ada Lovelace" in home.content
|
|
assert b"Session details" in home.content
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_account_session_shows_principal_diagnostics(client, settings):
|
|
settings.DEBUG = True
|
|
settings.OIDC_ENABLED = False
|
|
client.post(
|
|
reverse("identity:dev_login"),
|
|
{
|
|
"subject": "sub-diag",
|
|
"issuer": "https://local.dev/issuer",
|
|
"name": "Diag User",
|
|
"email": "diag@example.com",
|
|
},
|
|
)
|
|
r = client.get(reverse("core:account_session"))
|
|
assert r.status_code == 200
|
|
assert b"Session details" in r.content
|
|
assert b"sub-diag" in r.content
|
|
assert b"Diag User" in r.content
|
|
assert b"user-engine id" in r.content
|
|
assert b"Tenant" in r.content
|
|
assert b"Roles" in r.content
|
|
assert b"Groups" in r.content
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_account_session_requires_login(client):
|
|
r = client.get(reverse("core:account_session"))
|
|
assert r.status_code == 302
|
|
assert reverse("identity:login") in r["Location"]
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_establish_session_idempotent(client, settings):
|
|
claims = IdentityClaims(
|
|
issuer="https://id.example",
|
|
subject="same-sub",
|
|
email="x@example.com",
|
|
name="Once",
|
|
)
|
|
settings.DEBUG = True
|
|
settings.OIDC_ENABLED = False
|
|
client.post(
|
|
reverse("identity:dev_login"),
|
|
{"subject": "same-sub", "issuer": "https://id.example", "name": "Once"},
|
|
)
|
|
client.post(
|
|
reverse("identity:dev_login"),
|
|
{"subject": "same-sub", "issuer": "https://id.example", "name": "Once"},
|
|
)
|
|
assert Member.objects.filter(subject="same-sub").count() == 1
|
|
assert User.objects.count() == 1
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_no_password_columns_on_member():
|
|
field_names = {f.name for f in Member._meta.fields}
|
|
assert "password" not in field_names
|