Skip to content

Commit 3ffcb3b

Browse files
committed
Merge branch '223-trusted-clients' into 'main'
rename Client.preconsent in Client.trusted Closes #223 See merge request yaal/canaille!243
2 parents c9ca3c8 + c9ee827 commit 3ffcb3b

24 files changed

+2369
-2334
lines changed

CHANGES.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ Added
599599
- Display TOS and policy URI on the consent list page. :pr:`102`
600600
- Admin token deletion. :pr:`100` :pr:`101`
601601
- Revoked consents can be restored. :pr:`103`
602-
- Pre-consented clients are displayed in the user consent list,
602+
- Trusted clients are displayed in the user consent list,
603603
and their consents can be revoked. :issue:`69` :pr:`103`
604604
- A ``populate`` command can be used to fill the database with
605605
random users generated with faker. :pr:`105`

canaille/backends/ldap/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ class Client(canaille.oidc.models.Client, LDAPObject):
140140
"id": "entryUUID",
141141
"created": "createTimestamp",
142142
"last_modified": "modifyTimestamp",
143-
"preconsent": "oauthPreconsent",
143+
"trusted": "oauthPreconsent",
144144
# post_logout_redirect_uris is not yet supported by authlib
145145
"post_logout_redirect_uris": "oauthPostLogoutRedirectURI",
146146
"audience": "oauthAudience",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Rename client.preconsent in client.trusted.
2+
3+
Revision ID: 1740765703
4+
Revises: 1738929510
5+
Create Date: 2025-02-28 19:01:43.485715
6+
7+
"""
8+
9+
from collections.abc import Sequence
10+
11+
from alembic import op
12+
13+
# revision identifiers, used by Alembic.
14+
revision: str = "1740765703"
15+
down_revision: str | None = "1738929510"
16+
branch_labels: str | Sequence[str] | None = ()
17+
depends_on: str | Sequence[str] | None = None
18+
19+
20+
def upgrade() -> None:
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
23+
with op.batch_alter_table("client") as batch_op:
24+
batch_op.alter_column("preconsent", new_column_name="trusted")
25+
# ### end Alembic commands ###
26+
27+
28+
def downgrade() -> None:
29+
# ### commands auto generated by Alembic - please adjust! ###
30+
with op.batch_alter_table("client") as batch_op:
31+
batch_op.alter_column("trusted", new_column_name="preconsent")
32+
# ### end Alembic commands ###

canaille/backends/sql/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ class Client(canaille.oidc.models.Client, Base, SqlAlchemyModel):
185185
)
186186

187187
description: Mapped[str] = mapped_column(String, nullable=True)
188-
preconsent: Mapped[bool] = mapped_column(Boolean, nullable=True)
188+
trusted: Mapped[bool] = mapped_column(Boolean, nullable=True)
189189
post_logout_redirect_uris: Mapped[list[str]] = mapped_column(
190190
MutableJson, nullable=True
191191
)

canaille/oidc/basemodels.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Client(Model):
1818
identifier_attribute: ClassVar[str] = "client_id"
1919

2020
description: str | None = None
21-
preconsent: bool | None = False
21+
trusted: bool | None = False
2222
# keep 'List' instead of 'list' do not break py310 with the memory backend
2323
audience: List["Client"] = [] # noqa: UP006
2424

canaille/oidc/endpoints/clients.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def add(user):
7070
software_version=form["software_version"].data,
7171
jwks=form["jwks"].data,
7272
jwks_uri=form["jwks_uri"].data,
73-
preconsent=form["preconsent"].data,
73+
trusted=form["trusted"].data,
7474
client_secret=""
7575
if form["token_endpoint_auth_method"].data == "none"
7676
else gen_salt(48),
@@ -105,7 +105,7 @@ def client_edit(client):
105105
data = {attribute: getattr(client, attribute) for attribute in client.attributes}
106106
if data["scope"]:
107107
data["scope"] = " ".join(data["scope"])
108-
data["preconsent"] = client.preconsent
108+
data["trusted"] = client.trusted
109109
form = ClientAddForm(request.form or None, data=data, client=client)
110110

111111
if not request.form or form.form_control():
@@ -141,7 +141,7 @@ def client_edit(client):
141141
jwks=form["jwks"].data,
142142
jwks_uri=form["jwks_uri"].data,
143143
audience=form["audience"].data,
144-
preconsent=form["preconsent"].data,
144+
trusted=form["trusted"].data,
145145
)
146146
Backend.instance.save(client)
147147
flash(

canaille/oidc/endpoints/consents.py

+13-13
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ def consents(user):
2525
clients = {t.client for t in consents}
2626

2727
nb_consents = len(consents)
28-
nb_preconsents = sum(
28+
nb_trusted = sum(
2929
1
3030
for client in Backend.instance.query(models.Client)
31-
if client.preconsent and client not in clients
31+
if client.trusted and client not in clients
3232
)
3333

3434
return render_template(
@@ -38,33 +38,33 @@ def consents(user):
3838
scope_details=SCOPE_DETAILS,
3939
ignored_scopes=["openid"],
4040
nb_consents=nb_consents,
41-
nb_preconsents=nb_preconsents,
41+
nb_trusted=nb_trusted,
4242
)
4343

4444

45-
@bp.route("/pre-consents")
45+
@bp.route("/trusted-applications")
4646
@user_needed()
4747
def pre_consents(user):
4848
consents = Backend.instance.query(models.Consent, subject=user)
4949
clients = {t.client for t in consents}
50-
preconsented = [
50+
trusted = [
5151
client
5252
for client in Backend.instance.query(models.Client)
53-
if client.preconsent and client not in clients
53+
if client.trusted and client not in clients
5454
]
5555

5656
nb_consents = len(consents)
57-
nb_preconsents = len(preconsented)
57+
nb_trusted = len(trusted)
5858

5959
return render_template(
60-
"oidc/preconsent_list.html",
60+
"oidc/trusted_list.html",
6161
menuitem="consents",
6262
scope_details=SCOPE_DETAILS,
6363
# TODO: do not delegate this var to the templates, or set this explicitly in the templates.
6464
ignored_scopes=["openid"],
65-
preconsented=preconsented,
65+
trusted=trusted,
6666
nb_consents=nb_consents,
67-
nb_preconsents=nb_preconsents,
67+
nb_trusted=nb_trusted,
6868
)
6969

7070

@@ -106,10 +106,10 @@ def restore(user, consent):
106106
return redirect(url_for("oidc.consents.consents"))
107107

108108

109-
@bp.route("/revoke-preconsent/<client(required=False):client>")
109+
@bp.route("/revoke-trusted/<client(required=False):client>")
110110
@user_needed()
111-
def revoke_preconsent(user, client):
112-
if not client or not client.preconsent:
111+
def revoke_trusted(user, client):
112+
if not client or not client.trusted:
113113
flash(_("Could not revoke this access"), "error")
114114
return redirect(url_for("oidc.consents.consents"))
115115

canaille/oidc/endpoints/forms.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ class ClientAddForm(Form):
182182
],
183183
render_kw={"placeholder": ""},
184184
)
185-
preconsent = wtforms.BooleanField(
186-
_("Pre-consent"),
185+
trusted = wtforms.BooleanField(
186+
_("Trusted"),
187187
validators=[wtforms.validators.Optional()],
188188
default=False,
189189
)

canaille/oidc/endpoints/oauth.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def authorize_consent(client, user):
142142
# Get the authorization code, or display the user consent form
143143
if request.method == "GET":
144144
client_has_user_consent = (
145-
(client.preconsent and (not consent or not consent.revoked))
145+
(client.trusted and (not consent or not consent.revoked))
146146
or (
147147
consent and all(scope in set(consent.scope) for scope in allowed_scopes)
148148
)

canaille/oidc/oauth.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -410,9 +410,7 @@ def authenticate_user(self, subject: str):
410410

411411
def has_granted_permission(self, client, user):
412412
grant = Backend.instance.get(models.Consent, client=client, subject=user)
413-
has_permission = (grant and not grant.revoked) or (
414-
not grant and client.preconsent
415-
)
413+
has_permission = (grant and not grant.revoked) or (not grant and client.trusted)
416414
return has_permission
417415

418416

canaille/scim/client.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,12 @@ def get_clients_to_notify(user):
189189
"""Return a list of clients that should be notified of updates on 'user'."""
190190
consents = Backend.instance.query(models.Consent, subject=user)
191191
consented_clients = {t.client for t in consents}
192-
preconsented_clients = [
192+
trusted_clients = [
193193
client
194194
for client in Backend.instance.query(models.Client)
195-
if client.preconsent and client not in consented_clients
195+
if client.trusted and client not in consented_clients
196196
]
197-
return list(consented_clients) + list(preconsented_clients)
197+
return list(consented_clients) + list(trusted_clients)
198198

199199

200200
def after_user_query(user):

canaille/templates/oidc/consent_list.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
:type ignored_scopes: :class:`list`
1717
:param nb_consents: The number of consents.
1818
:type nb_consents: :class:`int`
19-
:param nb_preconsents: The number of preconsented clients.
20-
:type nb_preconsents: :class:`int`
19+
:param nb_trusted: The number of trusted clients.
20+
:type nb_trusted: :class:`int`
2121
#}
2222
{% extends theme('base.html') %}
2323

@@ -34,7 +34,7 @@
3434
<a class="item" href="{{ url_for('oidc.consents.pre_consents') }}">
3535
<i class="stamp icon"></i>
3636
{% trans %}Pre-authorized applications{% endtrans %}
37-
{% if nb_preconsents %}<div class="ui mini label">{{ nb_preconsents|numberformat }}</div>{% endif %}
37+
{% if nb_trusted %}<div class="ui mini label">{{ nb_trusted|numberformat }}</div>{% endif %}
3838
</a>
3939
{% endblock %}
4040

canaille/templates/oidc/preconsent_list.html canaille/templates/oidc/trusted_list.html

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
{#
2-
.. screenshot:: |canaille|/consent/pre-consents
2+
.. screenshot:: |canaille|/consent/trusted-applications
33
:context: user
44
:align: right
55
:width: 275px
66

7-
The preconsented applications list.
7+
The trusted applications list.
88

9-
The preconsented applications list.
9+
The trusted applications list.
1010

1111
Display a list of trusted clients for which it is implied that users don't need to explicitly give their consent.
1212

1313
:param scope_details: Description of the OIDC scopes.
1414
:type scope_details: :class:`dict`
1515
:param ignored_scopes: The scopes to hide.
1616
:type ignored_scopes: :class:`list`
17-
:param preconsented: The list of implicitly consented clients.
18-
:type preconsented: :class:`list` [ :class:`~canaille.oidc.basemodels.Client` ]
17+
:param trusted: The list of implicitly consented clients.
18+
:type trusted: :class:`list` [ :class:`~canaille.oidc.basemodels.Client` ]
1919
:param nb_consents: The number of consents.
2020
:type nb_consents: :class:`int`
21-
:param nb_preconsents: The number of preconsented clients.
22-
:type nb_preconsents: :class:`int`
21+
:param nb_trusted: The number of trusted clients.
22+
:type nb_trusted: :class:`int`
2323
#}
2424
{% extends theme('base.html') %}
2525

@@ -36,7 +36,7 @@
3636
<a class="active item" href="{{ url_for('oidc.consents.pre_consents') }}">
3737
<i class="stamp icon"></i>
3838
{% trans %}Pre-authorized applications{% endtrans %}
39-
{% if nb_preconsents %}<div class="ui mini label">{{ nb_preconsents|numberformat }}</div>{% endif %}
39+
{% if nb_trusted %}<div class="ui mini label">{{ nb_trusted|numberformat }}</div>{% endif %}
4040
</a>
4141
{% endblock %}
4242

@@ -51,9 +51,9 @@ <h2 class="ui center aligned header">
5151
</div>
5252
</h2>
5353

54-
{% if preconsented %}
54+
{% if trusted %}
5555
<div class="ui centered cards">
56-
{% for client in preconsented %}
56+
{% for client in trusted %}
5757
<div class="ui card">
5858
<div class="content">
5959
{% if client.logo_uri %}
@@ -100,7 +100,7 @@ <h2 class="ui center aligned header">
100100
</span>
101101
</div>
102102
{% endif %}
103-
<a class="ui bottom attached button" href="{{ url_for('oidc.consents.revoke_preconsent', client=client ) }}">
103+
<a class="ui bottom attached button" href="{{ url_for('oidc.consents.revoke_trusted', client=client ) }}">
104104
<i class="remove icon"></i>
105105
{% trans %}Revoke access{% endtrans %}
106106
</a>

canaille/translations/messages.pot

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ msgid ""
88
msgstr ""
99
"Project-Id-Version: PROJECT VERSION\n"
1010
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
11-
"POT-Creation-Date: 2025-02-27 14:14+0100\n"
11+
"POT-Creation-Date: 2025-02-28 19:18+0100\n"
1212
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414
"Language-Team: LANGUAGE <[email protected]>\n"
@@ -803,14 +803,14 @@ msgid "JKWS URI"
803803
msgstr ""
804804

805805
#: canaille/oidc/endpoints/forms.py:186
806-
msgid "Pre-consent"
806+
msgid "Trusted"
807807
msgstr ""
808808

809-
#: canaille/oidc/endpoints/oauth.py:416
809+
#: canaille/oidc/endpoints/oauth.py:409
810810
msgid "You have been disconnected"
811811
msgstr ""
812812

813-
#: canaille/oidc/endpoints/oauth.py:433
813+
#: canaille/oidc/endpoints/oauth.py:426
814814
msgid "You have not been disconnected"
815815
msgstr ""
816816

demo/demoapp.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def populate(app):
161161
scope=["openid", "profile", "email", "groups", "address", "phone"],
162162
response_types=["code", "id_token"],
163163
token_endpoint_auth_method="client_secret_basic",
164-
preconsent=True,
164+
trusted=True,
165165
)
166166
app.backend.save(client2)
167167
client2.audience = [client2]

0 commit comments

Comments
 (0)