Skip to content
Snippets Groups Projects
Commit 95c2327a authored by Benjamin Bertrand's avatar Benjamin Bertrand
Browse files

Add command to sync users with LDAP server

Command shall be run every night to keep the users in the database in
sync with the LDAP server.
If a user is not found:
- set its groups to []
- revoke all its tokens
parent ef44731e
No related branches found
No related tags found
No related merge requests found
# -*- coding: utf-8 -*-
"""
app.commands
~~~~~~~~~~~~
This module defines extra flask commands.
:copyright: (c) 2018 European Spallation Source ERIC
:license: BSD 2-Clause, see LICENSE for more details.
"""
import ldap3
import sqlalchemy as sa
from flask import current_app
from .extensions import db, ldap_manager
from .defaults import defaults
from .models import User
from . import utils
def sync_user(connection, user):
"""Synchronize the user from the database with information from the LDAP server"""
search_attr = current_app.config.get('LDAP_USER_LOGIN_ATTR')
object_filter = current_app.config.get('LDAP_USER_OBJECT_FILTER')
search_filter = f'(&{object_filter}({search_attr}={user.username}))'
connection.search(
search_base=ldap_manager.full_user_search_dn,
search_filter=search_filter,
search_scope=getattr(
ldap3, current_app.config.get('LDAP_USER_SEARCH_SCOPE')),
attributes=current_app.config.get('LDAP_GET_USER_ATTRIBUTES')
)
if len(connection.response) == 1:
ldap_user = connection.response[0]
attributes = ldap_user['attributes']
user.display_name = utils.attribute_to_string(attributes['cn'])
user.email = utils.attribute_to_string(attributes['mail'])
groups = ldap_manager.get_user_groups(dn=ldap_user['dn'], _connection=connection)
user.groups = sorted([utils.attribute_to_string(group['cn']) for group in groups])
current_app.logger.info(f'{user} updated')
else:
# Clear user's groups
user.groups = []
# Revoke all user's tokens
for token in user.tokens:
db.session.delete(token)
current_app.logger.info(f'{user} disabled')
return user
def register_cli(app):
@app.cli.command()
def initdb():
"""Create the database tables and initialize them with default values"""
db.engine.execute('CREATE EXTENSION IF NOT EXISTS citext')
db.create_all()
for instance in defaults:
db.session.add(instance)
try:
db.session.commit()
except sa.exc.IntegrityError as e:
db.session.rollback()
app.logger.debug(f'{instance} already exists')
@app.cli.command()
def syncusers():
"""Synchronize all users from the database with information the LDAP server"""
try:
connection = ldap_manager.connection
except ldap3.core.exceptions.LDAPException as e:
current_app.logger.warning(f'Failed to connect to the LDAP server: {e}')
return
for user in User.query.all():
sync_user(connection, user)
db.session.commit()
...@@ -24,22 +24,7 @@ from .user.views import bp as user ...@@ -24,22 +24,7 @@ from .user.views import bp as user
from .api.user import bp as user_api from .api.user import bp as user_api
from .api.inventory import bp as inventory_api from .api.inventory import bp as inventory_api
from .api.network import bp as network_api from .api.network import bp as network_api
from .defaults import defaults from .commands import register_cli
def register_cli(app):
@app.cli.command()
def initdb():
"""Create the database tables and initialize them with default values"""
db.engine.execute('CREATE EXTENSION IF NOT EXISTS citext')
db.create_all()
for instance in defaults:
db.session.add(instance)
try:
db.session.commit()
except sa.exc.IntegrityError as e:
db.session.rollback()
app.logger.debug(f'{instance} already exists')
def create_app(config=None): def create_app(config=None):
......
...@@ -89,7 +89,7 @@ def save_user(dn, username, data, memberships): ...@@ -89,7 +89,7 @@ def save_user(dn, username, data, memberships):
display_name=utils.attribute_to_string(data['cn']), display_name=utils.attribute_to_string(data['cn']),
email=utils.attribute_to_string(data['mail'])) email=utils.attribute_to_string(data['mail']))
# Always update the user groups to keep them up-to-date # Always update the user groups to keep them up-to-date
user.groups = [utils.attribute_to_string(group['cn']) for group in memberships] user.groups = sorted([utils.attribute_to_string(group['cn']) for group in memberships])
db.session.add(user) db.session.add(user)
db.session.commit() db.session.commit()
return user return user
......
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