Skip to content
Snippets Groups Projects
Verified Commit f74081ae authored by nd's avatar nd
Browse files

added support to edit user

parent 8f76104f
No related branches found
No related tags found
No related merge requests found
...@@ -3,3 +3,7 @@ LDAP_BASE_GROUPS="ou=groups,dc=example,dc=com" ...@@ -3,3 +3,7 @@ LDAP_BASE_GROUPS="ou=groups,dc=example,dc=com"
LDAP_SERVICE_BIND_DN="" LDAP_SERVICE_BIND_DN=""
LDAP_SERVICE_BIND_PASSWORD="" LDAP_SERVICE_BIND_PASSWORD=""
LDAP_SERVICE_URL="ldapi:///" LDAP_SERVICE_URL="ldapi:///"
LDAP_USER_OBJECTCLASSES=["vmailUser", "top", "inetOrgPerson", "organizationalPerson", "person", "posixAccount"]
LDAP_USER_GID=20001
LDAP_USER_MIN_UID=10000
LDAP_USER_MAX_UID=18999
...@@ -26,7 +26,6 @@ class Group(): ...@@ -26,7 +26,6 @@ class Group():
@classmethod @classmethod
def from_ldap_dn(cls, dn): def from_ldap_dn(cls, dn):
conn = ldap.service_conn() conn = ldap.service_conn()
print(dn)
conn.search(dn, '(objectClass=groupOfUniqueNames)') conn.search(dn, '(objectClass=groupOfUniqueNames)')
if not len(conn.entries) == 1: if not len(conn.entries) == 1:
return None return None
......
from .ldap import bp as ldap_bp from .ldap import bp as ldap_bp
from .ldap import service_conn, user_conn, escape_filter_chars from .ldap import service_conn, user_conn, escape_filter_chars, uid_to_dn, loginname_to_dn, get_next_uid
bp = [ldap_bp] bp = [ldap_bp]
...@@ -20,3 +20,31 @@ def service_conn(): ...@@ -20,3 +20,31 @@ def service_conn():
def user_conn(): def user_conn():
pass pass
def uid_to_dn(uid):
conn = service_conn()
conn.search(current_app.config["LDAP_BASE_USER"], '(&(objectclass=person)(uidNumber={}))'.format(escape_filter_chars(uid)))
if not len(conn.entries) == 1:
return None
else:
return conn.entries[0].entry_dn
def loginname_to_dn(loginname):
return 'uid={},{}'.format(escape_filter_chars(loginname), current_app.config["LDAP_BASE_USER"])
def get_next_uid():
conn = service_conn()
conn.search(current_app.config["LDAP_BASE_USER"], '(objectclass=person)')
max_uid = current_app.config["LDAP_USER_MIN_UID"]
for i in conn.entries:
# skip out of range entries
if i['uidNumber'].value > current_app.config["LDAP_USER_MAX_UID"]:
continue
if i['uidNumber'].value < current_app.config["LDAP_USER_MIN_UID"]:
continue
max_uid = max(i['uidNumber'].value, max_uid)
next_uid = max_uid + 1
if uid_to_dn(next_uid):
raise Exception('No free uid found')
else:
return next_uid
import string import string
from ldap3 import MODIFY_REPLACE, HASHED_SALTED_SHA512
from flask import current_app
from uffd import ldap from uffd import ldap
class User(): class User():
...@@ -6,6 +10,7 @@ class User(): ...@@ -6,6 +10,7 @@ class User():
loginname = None loginname = None
displayname = None displayname = None
mail = None mail = None
newpassword = None
def __init__(self, uid=None, loginname='', displayname='', mail='', groups=None): def __init__(self, uid=None, loginname='', displayname='', mail='', groups=None):
self.uid = uid self.uid = uid
...@@ -14,7 +19,7 @@ class User(): ...@@ -14,7 +19,7 @@ class User():
self.mail = mail self.mail = mail
if isinstance(groups, str): if isinstance(groups, str):
groups = [groups] groups = [groups]
self.groups_ldap = groups self.groups_ldap = groups or []
self._groups = None self._groups = None
@classmethod @classmethod
...@@ -36,7 +41,35 @@ class User(): ...@@ -36,7 +41,35 @@ class User():
return User.from_ldap(conn.entries[0]) return User.from_ldap(conn.entries[0])
def to_ldap(self, new): def to_ldap(self, new):
pass conn = ldap.service_conn()
if new:
attributes= {
'uidNumber': ldap.get_next_uid(),
'gidNumber': current_app.config['LDAP_USER_GID'],
'homeDirectory': '/home/'+self.loginname,
'sn': ' ',
# same as for update
'givenName': self.displayname,
'displayName': self.displayname,
'cn': self.displayname,
'mail': self.mail,
}
dn = ldap.loginname_to_dn(self.loginname)
result = conn.add(dn, current_app.config['LDAP_USER_OBJECTCLASSES'], attributes)
else:
attributes = {
'givenName': [(MODIFY_REPLACE, [self.displayname])],
'displayName': [(MODIFY_REPLACE, [self.displayname])],
'cn': [(MODIFY_REPLACE, [self.displayname])],
'mail': [(MODIFY_REPLACE, [self.mail])],
}
dn = ldap.uid_to_dn(self.uid)
result = conn.modify(dn, attributes)
if result:
if self.newpassword:
print(self.newpassword)
conn.extend.standard.modify_password(user=dn, old_password=None, new_password=self.newpassword, hash_algorithm=HASHED_SALTED_SHA512)
return result
def get_groups(self): def get_groups(self):
from uffd.group.models import Group from uffd.group.models import Group
...@@ -66,4 +99,4 @@ class User(): ...@@ -66,4 +99,4 @@ class User():
return True return True
def set_password(self, value): def set_password(self, value):
raise Exception('TODO: user want to change passwords') self.newpassword = value
{% extends 'base.html' %} {% extends 'base.html' %}
{% block body %} {% block body %}
<form action="{{ url_for(".user_update", id_=user.uid) }}" method="POST"> <form action="{{ url_for(".user_update", uid=user.uid) }}" method="POST">
<div class="align-self-center"> <div class="align-self-center">
<div class="form-group col"> <div class="form-group col">
<label for="user-uid">uid</label> <label for="user-uid">uid</label>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<tr> <tr>
<th scope="col">uid</th> <th scope="col">uid</th>
<th scope="col">login name</th> <th scope="col">login name</th>
<th scope="col">given name</th> <th scope="col">display name</th>
<th scope="col"> <th scope="col">
<a type="button" class="btn btn-primary" href="{{ url_for(".user_show") }}"> <a type="button" class="btn btn-primary" href="{{ url_for(".user_show") }}">
<i class="fa fa-plus" aria-hidden="true"></i> New <i class="fa fa-plus" aria-hidden="true"></i> New
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</a> </a>
</td> </td>
<td> <td>
{{ user.givenname }} {{ user.displayname }}
</td> </td>
<td> <td>
<a href="{{ url_for(".user_show", uid=user.uid) }}" class="btn btn-primary"> <a href="{{ url_for(".user_show", uid=user.uid) }}" class="btn btn-primary">
......
...@@ -23,16 +23,18 @@ def user_list(): ...@@ -23,16 +23,18 @@ def user_list():
def user_show(uid=None): def user_show(uid=None):
if not uid: if not uid:
user = User() user = User()
ldif = '<none yet>'
else: else:
conn = service_conn() conn = service_conn()
conn.search(current_app.config["LDAP_BASE_USER"], '(&(objectclass=person)(uidNumber={}))'.format((escape_filter_chars(uid)))) conn.search(current_app.config["LDAP_BASE_USER"], '(&(objectclass=person)(uidNumber={}))'.format((escape_filter_chars(uid))))
assert len(conn.entries) == 1 assert len(conn.entries) == 1
user = User.from_ldap(conn.entries[0]) user = User.from_ldap(conn.entries[0])
return render_template('user.html', user=user, user_ldif=conn.entries[0].entry_to_ldif()) ldif = conn.entries[0].entry_to_ldif()
return render_template('user.html', user=user, user_ldif=ldif)
@bp.route("/<int:uid>/update", methods=['POST']) @bp.route("/<int:uid>/update", methods=['POST'])
@bp.route("/new", methods=['POST']) @bp.route("/new", methods=['POST'])
def user_update(uid=None): def user_update(uid=False):
conn = service_conn() conn = service_conn()
if uid: if uid:
conn.search(current_app.config["LDAP_BASE_USER"], '(&(objectclass=person)(uidNumber={}))'.format((escape_filter_chars(uid)))) conn.search(current_app.config["LDAP_BASE_USER"], '(&(objectclass=person)(uidNumber={}))'.format((escape_filter_chars(uid))))
...@@ -51,7 +53,7 @@ def user_update(uid=None): ...@@ -51,7 +53,7 @@ def user_update(uid=None):
new_password = request.form.get('password') new_password = request.form.get('password')
if new_password: if new_password:
user.set_password(new_password) user.set_password(new_password)
if user.to_ldap(conn, new=bool(uid)): if user.to_ldap(new=(not uid)):
flash('User updated') flash('User updated')
else: else:
flash('Error updating user: {}'.format(conn.result['message'])) flash('Error updating user: {}'.format(conn.result['message']))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment