forked from Github-Mirrors/canaille
Add groups field on user profile (WIP)
This commit is contained in:
parent
22b702c065
commit
75df94216a
8 changed files with 69 additions and 8 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -127,6 +127,7 @@ PROFILE_FORM_FIELDS = dict(
|
|||
"placeholder": _("1234"),
|
||||
},
|
||||
),
|
||||
groups=wtforms.SelectMultipleField(_("Groups"), choices=["foo", "bar"])
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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
9
tests/test_groups.py
Normal 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)]
|
|
@ -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")
|
||||
|
|
Loading…
Reference in a new issue