Merge branch 'issue-73-disable-oidc' into 'master'

Option to not use OIDC

Closes #73

See merge request yaal/canaille!23
This commit is contained in:
Éloi Rivard 2021-12-06 23:19:40 +00:00
commit 7091834910
7 changed files with 47 additions and 27 deletions

View file

@ -82,7 +82,7 @@ GROUP_USER_FILTER = "member={user.dn}"
# You can define access controls that define what users can do on canaille # You can define access controls that define what users can do on canaille
# An access control consists in a FILTER to match users, a list of PERMISSIONS # An access control consists in a FILTER to match users, a list of PERMISSIONS
# matched users will be able to perform, and fields users will be able # matched users will be able to perform, and fields users will be able
# to READ and WRITE. # to READ and WRITE. Users matching several filters will cumulate permissions.
# #
# A 'FILTER' parameter that is a LDAP filter used to determine if a user # A 'FILTER' parameter that is a LDAP filter used to determine if a user
# belongs to an access control. If absent, all the users will match this # belongs to an access control. If absent, all the users will match this
@ -94,17 +94,19 @@ GROUP_USER_FILTER = "member={user.dn}"
# #
# The 'PERMISSIONS' parameter that is an list of items the users in the access # The 'PERMISSIONS' parameter that is an list of items the users in the access
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be: # control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
# - "use_oidc" to allow OpenID Connect authentication
# - "manage_oidc" to allow OpenID Connect client managements
# - "manage_users" to allow other users management # - "manage_users" to allow other users management
# - "manage_groups" to allow group edition and creation # - "manage_groups" to allow group edition and creation
# - "manage_oidc" to allow OpenID Connect client managements
# - "delete_account" allows a user to delete his own account. If used with # - "delete_account" allows a user to delete his own account. If used with
# manage_users, the user can delete any account # manage_users, the user can delete any account
# - "impersonate_users" to allow a user to take the identity of another user # - "impersonate_users" to allow a user to take the identity of another user
# #
# The 'READ' and 'WRITE' attributes are the LDAP attributes of the user # The 'READ' and 'WRITE' attributes are the LDAP attributes of the user
# object that users will be able to read and/or write. # object that users will be able to read and/or write.
[ACL.DEFAULT] [ACL.DEFAULT]
READ = ["uid", "groups"] READ = ["uid", "groups"]
PERMISSIONS = ["use_oidc"]
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber"] WRITE = ["givenName", "sn", "userPassword", "telephoneNumber"]
[ACL.ADMIN] [ACL.ADMIN]
@ -116,8 +118,7 @@ PERMISSIONS = [
"delete_account", "delete_account",
"impersonate_users", "impersonate_users",
] ]
READ = ["uid"] WRITE = ["groups"]
WRITE = ["groups", "givenName", "sn", "userPassword"]
# The jwt configuration. You can generate a RSA keypair with: # The jwt configuration. You can generate a RSA keypair with:
# openssl genrsa -out private.pem 4096 # openssl genrsa -out private.pem 4096

View file

@ -150,6 +150,10 @@ class User(LDAPObject):
self.read |= set(details.get("READ", [])) self.read |= set(details.get("READ", []))
self.write |= set(details.get("WRITE", [])) self.write |= set(details.get("WRITE", []))
@property
def can_use_oidc(self):
return "use_oidc" in self.permissions
@property @property
def can_manage_users(self): def can_manage_users(self):
return "manage_users" in self.permissions return "manage_users" in self.permissions

View file

@ -76,6 +76,9 @@ def authorize():
return redirect(request.url) return redirect(request.url)
if not user.can_use_oidc:
abort(400)
# CONSENT # CONSENT
consents = Consent.filter( consents = Consent.filter(

View file

@ -38,11 +38,13 @@
<i class="id card icon"></i> <i class="id card icon"></i>
{% trans %}My profile{% endtrans %} {% trans %}My profile{% endtrans %}
</a> </a>
{% if user.can_use_oidc %}
<a class="item {% if menuitem == "consents" %}active{% endif %}" <a class="item {% if menuitem == "consents" %}active{% endif %}"
href="{{ url_for('consents.consents') }}"> href="{{ url_for('consents.consents') }}">
<i class="handshake icon"></i> <i class="handshake icon"></i>
{% trans %}My consents{% endtrans %} {% trans %}My consents{% endtrans %}
</a> </a>
{% endif %}
{% if user.can_manage_users %} {% if user.can_manage_users %}
<a class="item {% if menuitem == "users" %}active{% endif %}" <a class="item {% if menuitem == "users" %}active{% endif %}"
href="{{ url_for('account.users') }}"> href="{{ url_for('account.users') }}">

View file

@ -84,7 +84,7 @@ GROUP_USER_FILTER = "member={user.dn}"
# You can define access controls that define what users can do on canaille # You can define access controls that define what users can do on canaille
# An access control consists in a FILTER to match users, a list of PERMISSIONS # An access control consists in a FILTER to match users, a list of PERMISSIONS
# matched users will be able to perform, and fields users will be able # matched users will be able to perform, and fields users will be able
# to READ and WRITE. # to READ and WRITE. Users matching several filters will cumulate permissions.
# #
# A 'FILTER' parameter that is a LDAP filter used to determine if a user # A 'FILTER' parameter that is a LDAP filter used to determine if a user
# belongs to an access control. If absent, all the users will match this # belongs to an access control. If absent, all the users will match this
@ -96,17 +96,19 @@ GROUP_USER_FILTER = "member={user.dn}"
# #
# The 'PERMISSIONS' parameter that is an list of items the users in the access # The 'PERMISSIONS' parameter that is an list of items the users in the access
# control will be able to manage. 'PERMISSIONS' is optionnal. Values can be: # control will be able to manage. 'PERMISSIONS' is optionnal. Values can be:
# - "use_oidc" to allow OpenID Connect authentication
# - "manage_oidc" to allow OpenID Connect client managements
# - "manage_users" to allow other users management # - "manage_users" to allow other users management
# - "manage_groups" to allow group edition and creation # - "manage_groups" to allow group edition and creation
# - "manage_oidc" to allow OpenID Connect client managements
# - "delete_account" allows a user to delete his own account. If used with # - "delete_account" allows a user to delete his own account. If used with
# manage_users, the user can delete any account # manage_users, the user can delete any account
# - "impersonate_users" to allow a user to take the identity of another user # - "impersonate_users" to allow a user to take the identity of another user
# #
# The 'READ' and 'WRITE' attributes are the LDAP attributes of the user # The 'READ' and 'WRITE' attributes are the LDAP attributes of the user
# object that users will be able to read and/or write. # object that users will be able to read and/or write.
[ACL.DEFAULT] [ACL.DEFAULT]
READ = ["uid", "groups"] READ = ["uid", "groups"]
PERMISSIONS = ["use_oidc"]
WRITE = ["givenName", "sn", "userPassword", "telephoneNumber"] WRITE = ["givenName", "sn", "userPassword", "telephoneNumber"]
[ACL.ADMIN] [ACL.ADMIN]
@ -118,14 +120,12 @@ PERMISSIONS = [
"delete_account", "delete_account",
"impersonate_users", "impersonate_users",
] ]
READ = ["uid"] WRITE = ["groups"]
WRITE = ["groups", "givenName", "sn", "userPassword"]
[ACL.HALF_ADMIN] [ACL.HALF_ADMIN]
FILTER = "memberof=cn=moderators,ou=groups,dc=mydomain,dc=tld" FILTER = "memberof=cn=moderators,ou=groups,dc=mydomain,dc=tld"
PERMISSIONS = ["manage_users", "manage_groups", "delete_account"] PERMISSIONS = ["manage_users", "manage_groups", "delete_account"]
READ = ["uid"] WRITE = ["groups"]
WRITE = ["groups", "givenName", "sn", "userPassword"]
# The jwt configuration. You can generate a RSA keypair with: # The jwt configuration. You can generate a RSA keypair with:
# openssl genrsa -out private.pem 4096 # openssl genrsa -out private.pem 4096

View file

@ -147,7 +147,7 @@ def configuration(slapd_server, smtpd, keypair_path):
"ACL": { "ACL": {
"DEFAULT": { "DEFAULT": {
"READ": ["uid", "groups"], "READ": ["uid", "groups"],
"PERMISSIONS": [], "PERMISSIONS": ["use_oidc"],
"WRITE": [ "WRITE": [
"mail", "mail",
"givenName", "givenName",
@ -166,28 +166,14 @@ def configuration(slapd_server, smtpd, keypair_path):
"impersonate_users", "impersonate_users",
"manage_groups", "manage_groups",
], ],
"READ": ["uid"],
"WRITE": [ "WRITE": [
"mail",
"givenName",
"sn",
"userPassword",
"telephoneNumber",
"employeeNumber",
"groups", "groups",
], ],
}, },
"MODERATOR": { "MODERATOR": {
"FILTER": "(|(uid=moderator)(sn=moderator))", "FILTER": "(|(uid=moderator)(sn=moderator))",
"PERMISSIONS": ["manage_users", "manage_groups", "delete_account"], "PERMISSIONS": ["manage_users", "manage_groups", "delete_account"],
"READ": ["uid"],
"WRITE": [ "WRITE": [
"mail",
"givenName",
"sn",
"userPassword",
"telephoneNumber",
"employeeNumber",
"groups", "groups",
], ],
}, },

View file

@ -438,6 +438,30 @@ def test_authorization_code_flow_when_consent_already_given_but_for_a_smaller_sc
assert "groups" in consents[0].oauthScope assert "groups" in consents[0].oauthScope
def test_authorization_code_flow_but_user_cannot_use_oidc(
testclient, slapd_connection, user, client, keypair, other_client
):
testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = []
res = testclient.get(
"/oauth/authorize",
params=dict(
response_type="code",
client_id=client.oauthClientID,
scope="profile",
nonce="somenonce",
),
status=200,
)
res.form["login"] = "John (johnny) Doe"
res = res.form.submit(status=200)
res.form["password"] = "correct horse battery staple"
res = res.form.submit(status=302)
res = res.follow(status=400)
def test_prompt_none(testclient, slapd_connection, logged_user, client): def test_prompt_none(testclient, slapd_connection, logged_user, client):
Consent( Consent(
oauthClient=client.dn, oauthClient=client.dn,