Add groups field on user profile (WIP)

This commit is contained in:
Camille Daniel 2021-04-08 17:38:13 +02:00
parent 22b702c065
commit 75df94216a
8 changed files with 69 additions and 8 deletions

View file

@ -23,7 +23,7 @@ from flask_babel import Babel
from .flaskutils import current_user
from .ldaputils import LDAPObject
from .oauth2utils import config_oauth
from .models import User, Token, AuthorizationCode, Client, Consent
from .models import User, Token, AuthorizationCode, Client, Consent, Group
try: # pragma: no cover
import sentry_sdk
@ -123,10 +123,12 @@ def setup_app(app):
try:
LDAPObject.root_dn = app.config["LDAP"]["ROOT_DN"]
base = app.config["LDAP"]["USER_BASE"]
if base.endswith(app.config["LDAP"]["ROOT_DN"]):
base = base[: -len(app.config["LDAP"]["ROOT_DN"]) - 1]
User.base = base
user_base = app.config["LDAP"]["USER_BASE"]
if user_base.endswith(app.config["LDAP"]["ROOT_DN"]):
user_base = user_base[: -len(app.config["LDAP"]["ROOT_DN"]) - 1]
User.base = user_base
group_base = app.config["LDAP"]["GROUP_BASE"]
Group.base = group_base
app.url_map.strict_slashes = False

View file

@ -272,6 +272,8 @@ def profile_edit(user, username):
user[attribute.name] = data
else:
user[attribute.name] = [data]
elif attribute.name == "groups":
user.groups = attribute.data
if (
not form["password1"].data or user.set_password(form["password1"].data)

View file

@ -127,6 +127,7 @@ PROFILE_FORM_FIELDS = dict(
"placeholder": _("1234"),
},
),
groups=wtforms.SelectMultipleField(_("Groups"), choices=["foo", "bar"])
)

View file

@ -16,6 +16,7 @@ class User(LDAPObject):
id = "cn"
admin = False
moderator = False
_groups = []
@classmethod
def get(cls, login=None, dn=None, filter=None, conn=None):
@ -114,6 +115,27 @@ class User(LDAPObject):
return self.cn[0]
@property
def groups(self):
return self._groups
@groups.setter
def groups(self, value):
self._groups = value
class Group(LDAPObject):
id = "cn"
@classmethod
def available_groups(cls, conn=None):
conn = conn or cls.ldap()
groups = cls.filter(objectClass=current_app.config["LDAP"].get("GROUP_CLASS"), conn=conn)
Group.attr_type_by_name(conn=conn)
attribute = current_app.config["LDAP"].get("GROUP_NAME_ATTRIBUTE")
return [(group[attribute][0], group.dn) for group in groups]
class Client(LDAPObject, ClientMixin):
object_class = ["oauthClient"]
base = "ou=clients,ou=oauth"

View file

@ -82,6 +82,9 @@
{% if "employeeNumber" in form %}
{{ sui.render_field(form.employeeNumber) }}
{% endif %}
{% if "groups" in form %}
{{ sui.render_field(form.groups) }}
{% endif %}
<h4 class="ui dividing header">{% trans %}Account information{% endtrans %}</h4>
{% if "uid" in form %}

View file

@ -9,7 +9,7 @@ from cryptography.hazmat.backends import default_backend as crypto_default_backe
from flask_webtest import TestApp
from werkzeug.security import gen_salt
from canaille import create_app
from canaille.models import User, Client, Token, AuthorizationCode, Consent
from canaille.models import User, Client, Token, AuthorizationCode, Consent, Group
from canaille.ldaputils import LDAPObject
@ -93,6 +93,10 @@ def slapd_server():
"dn: ou=users," + slapd.suffix,
"objectClass: organizationalUnit",
"ou: users",
"",
"dn: ou=groups," + slapd.suffix,
"objectClass: organizationalUnit",
"ou: groups",
]
)
+ "\n"
@ -100,6 +104,7 @@ def slapd_server():
LDAPObject.root_dn = slapd.suffix
User.base = "ou=users"
Group.base = "ou=groups"
yield slapd
finally:
@ -143,7 +148,11 @@ def app(slapd_server, keypair_path):
"userPassword",
"telephoneNumber",
"employeeNumber",
"groups",
],
"GROUP_BASE": "ou=groups",
"GROUP_CLASS": "groupOfNames",
"GROUP_NAME_ATTRIBUTE": "cn",
},
"JWT": {
"PUBLIC_KEY": public_key_path,
@ -338,3 +347,14 @@ def cleanups(slapd_connection):
yield
for consent in Consent.filter(conn=slapd_connection):
consent.delete(conn=slapd_connection)
@pytest.fixture
def foo_group(user, slapd_connection):
Group.ocs_by_name(slapd_connection)
g = Group(
objectClass = ["groupOfNames"],
member=[user.dn],
cn="foo",
)
g.save(slapd_connection)
return g

9
tests/test_groups.py Normal file
View file

@ -0,0 +1,9 @@
from canaille.models import Group
def test_no_group(app, slapd_connection):
with app.app_context():
assert Group.available_groups(conn=slapd_connection) == []
def test_foo_group(app, slapd_connection, foo_group):
with app.app_context():
assert Group.available_groups(conn=slapd_connection) == [("foo", foo_group.dn)]

View file

@ -2,8 +2,9 @@ import mock
from canaille.models import User
def test_profile(testclient, slapd_connection, logged_user):
def test_profile(testclient, slapd_connection, logged_user, foo_group):
res = testclient.get("/profile/user", status=200)
assert res.form["groups"].options == [('foo', False, 'foo')]
res.form["uid"] = "user"
res.form["givenName"] = "given_name"
@ -11,7 +12,7 @@ def test_profile(testclient, slapd_connection, logged_user):
res.form["mail"] = "email@mydomain.tld"
res.form["telephoneNumber"] = "555-666-777"
res.form["employeeNumber"] = 666
res.form["groups"] = ["foo", "bar"]
res = res.form.submit(name="action", value="edit", status=200)
assert "Profile updated successfuly." in res, str(res)
@ -23,6 +24,7 @@ def test_profile(testclient, slapd_connection, logged_user):
assert ["email@mydomain.tld"] == logged_user.mail
assert ["555-666-777"] == logged_user.telephoneNumber
assert "666" == logged_user.employeeNumber
assert ["foo", "bar"] == logged_user.groups
with testclient.app.app_context():
assert logged_user.check_password("correct horse battery staple")