tests: extracted the prompt tests in a dedicated file

This commit is contained in:
Éloi Rivard 2023-12-22 21:18:02 +01:00
parent f7162e4a5a
commit 9ff0411e9e
No known key found for this signature in database
GPG key ID: 7EDA204EA57DD184
4 changed files with 111 additions and 75 deletions

View file

@ -55,9 +55,8 @@ def authorize():
abort(400, "Invalid client.")
user = current_user()
scopes = client.get_allowed_scope(request.args.get("scope", "").split(" ")).split(
" "
)
requested_scopes = request.args.get("scope", "").split(" ")
allowed_scopes = client.get_allowed_scope(requested_scopes).split(" ")
# LOGIN
@ -69,7 +68,9 @@ def authorize():
return redirect(url_for("core.auth.login"))
if not user.can_use_oidc:
abort(403, "User does not have the permission to achieve OIDC authentication.")
abort(
403, "The user does not have the permission to achieve OIDC authentication."
)
# CONSENT
@ -82,7 +83,9 @@ def authorize():
if request.method == "GET":
if (
(client.preconsent and (not consent or not consent.revoked))
or (consent and all(scope in set(consent.scope) for scope in scopes))
or (
consent and all(scope in set(consent.scope) for scope in allowed_scopes)
)
and not consent.revoked
):
return authorization.create_authorization_response(grant_user=user)
@ -125,14 +128,14 @@ def authorize():
if consent.revoked:
consent.restore()
consent.scope = client.get_allowed_scope(
list(set(scopes + consents[0].scope))
list(set(allowed_scopes + consents[0].scope))
).split(" ")
else:
consent = models.Consent(
consent_id=str(uuid.uuid4()),
client=client,
subject=user,
scope=scopes,
scope=allowed_scopes,
issue_date=datetime.datetime.now(datetime.timezone.utc),
)
consent.save()

View file

@ -76,6 +76,7 @@ def openid_configuration():
],
"subject_types_supported": ["pairwise", "public"],
"id_token_signing_alg_values_supported": ["RS256", "ES256", "HS256"],
"prompt_values_supported": ["none"],
}

View file

@ -1,4 +1,3 @@
import uuid
from urllib.parse import parse_qs
from urllib.parse import urlsplit
@ -610,73 +609,6 @@ def test_authorization_code_flow_but_user_cannot_use_oidc(
res = res.follow(status=403)
def test_prompt_none(testclient, logged_user, client):
consent = models.Consent(
consent_id=str(uuid.uuid4()),
client=client,
subject=logged_user,
scope=["openid", "profile"],
)
consent.save()
res = testclient.get(
"/oauth/authorize",
params=dict(
response_type="code",
client_id=client.client_id,
scope="openid profile",
nonce="somenonce",
prompt="none",
),
status=302,
)
assert res.location.startswith(client.redirect_uris[0])
params = parse_qs(urlsplit(res.location).query)
assert "code" in params
consent.delete()
def test_prompt_not_logged(testclient, user, client):
consent = models.Consent(
consent_id=str(uuid.uuid4()),
client=client,
subject=user,
scope=["openid", "profile"],
)
consent.save()
res = testclient.get(
"/oauth/authorize",
params=dict(
response_type="code",
client_id=client.client_id,
scope="openid profile",
nonce="somenonce",
prompt="none",
),
status=200,
)
assert "login_required" == res.json.get("error")
consent.delete()
def test_prompt_no_consent(testclient, logged_user, client):
res = testclient.get(
"/oauth/authorize",
params=dict(
response_type="code",
client_id=client.client_id,
scope="openid profile",
nonce="somenonce",
prompt="none",
),
status=200,
)
assert "consent_required" == res.json.get("error")
def test_nonce_required_in_oidc_requests(testclient, logged_user, client):
res = testclient.get(
"/oauth/authorize",

View file

@ -0,0 +1,100 @@
"""
Tests the behavior of Canaille depending on the OIDC 'prompt' parameter.
https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
"""
import uuid
from urllib.parse import parse_qs
from urllib.parse import urlsplit
from canaille.app import models
def test_prompt_none(testclient, logged_user, client):
"""
Nominal case with prompt=none
"""
consent = models.Consent(
consent_id=str(uuid.uuid4()),
client=client,
subject=logged_user,
scope=["openid", "profile"],
)
consent.save()
res = testclient.get(
"/oauth/authorize",
params=dict(
response_type="code",
client_id=client.client_id,
scope="openid profile",
nonce="somenonce",
prompt="none",
),
status=302,
)
assert res.location.startswith(client.redirect_uris[0])
params = parse_qs(urlsplit(res.location).query)
assert "code" in params
consent.delete()
def test_prompt_not_logged(testclient, user, client):
"""
prompt=none should return a login_required error when no
user is logged in.
login_required
The Authorization Server requires End-User authentication.
This error MAY be returned when the prompt parameter value in the
Authentication Request is none, but the Authentication Request
cannot be completed without displaying a user interface for End-User
authentication.
"""
consent = models.Consent(
consent_id=str(uuid.uuid4()),
client=client,
subject=user,
scope=["openid", "profile"],
)
consent.save()
res = testclient.get(
"/oauth/authorize",
params=dict(
response_type="code",
client_id=client.client_id,
scope="openid profile",
nonce="somenonce",
prompt="none",
),
status=200,
)
assert "login_required" == res.json.get("error")
consent.delete()
def test_prompt_no_consent(testclient, logged_user, client):
"""
prompt=none should return a consent_required error when user
are logged in but have not granted their consent.
consent_required
The Authorization Server requires End-User consent. This error MAY be
returned when the prompt parameter value in the Authentication Request
is none, but the Authentication Request cannot be completed without
displaying a user interface for End-User consent.
"""
res = testclient.get(
"/oauth/authorize",
params=dict(
response_type="code",
client_id=client.client_id,
scope="openid profile",
nonce="somenonce",
prompt="none",
),
status=200,
)
assert "consent_required" == res.json.get("error")