Unverified Commit 363af840 authored by Peter Stanko's avatar Peter Stanko
Browse files

Extract uco from LDAP using ldap3 instead of python-ldap

parent 8f0da640
Pipeline #13208 passed with stage
in 13 minutes and 1 second
......@@ -22,11 +22,11 @@ python-gitlab = "*"
psycopg2-binary = "*"
flask-restplus = "*"
celery = {extras = ["auth", "yaml", "msgpack", "redis"]}
python-ldap = "*"
mockredispy = "*"
python-slugify = "*"
coloredlogs = "*"
worker-api = {editable = true, git = "https://gitlab.fi.muni.cz/grp-kontr2/worker-api.git", ref='master'}
"ldap3" = "*"
[dev-packages]
pylint = "*"
......
......@@ -105,6 +105,7 @@ Here are some important variables:
- `EMAIL_PORT` - Port on which the mail server is running
- `EMAIL_DEFAULT_FROM` - From who the emails are
- `PORTAL_DATA_WORKER_DOMAIN` - Domain where default worker will be running (default: `localhost`) This one is mostly for the template
- `LDAP_URL` - LDAP url, required only if you need LDAP support
For more take a look at the config files.
......
......@@ -38,6 +38,7 @@ class Config(object):
EMAIL_BACKEND = 'tests.utils.email_backend.EmailBackend'
PORTAL_LOG_CONFIG = False
PORTAL_DATA_WORKER_DOMAIN = os.getenv('PORTAL_DATA_WORKER_DOMAIN', 'localhost')
LDAP_URL = os.getenv('LDAP_URL', None)
class DevelopmentConfig(Config):
......
......@@ -2,7 +2,7 @@
Users service
"""
from typing import List
from typing import List, Optional
from portal import ldap_wrapper, logger
from portal.database.models import Course, Group, Project, Review, Role, Submission, User
......@@ -33,20 +33,30 @@ class UserLdapService:
def user(self):
return self.service.user
def extract_uco(self) -> int:
def extract_uco(self) -> Optional[int]:
"""Get uco from the ldap
Returns(int): User's uco
"""
username = self.user.username
user_dict = self.ldap.search_dict(f"uid={username},ou=People")
log.debug(f"[LDAP] User ({username}): {user_dict}")
if not user_dict:
return 0
desc = user_dict[0]['description']
uco = [u.decode('utf-8') for u in desc if u.decode('utf-8').startswith('UCO=')]
if not uco:
return 0
return int(uco[0][4:])
user_entity = self.ldap.search(f"uid={username},ou=People")
log.debug(f"[LDAP] User ({username}): {user_entity}")
if not user_entity:
return None
desc = user_entity.description
uco = self._parse_uco_from_desc(desc)
log.debug(f"[LDAP] User's UCO ({username}): {uco}")
return uco
def _parse_uco_from_desc(self, desc):
values: List[str] = desc.values
uco_entry = None
for item in values:
if item.startswith('UCO='):
uco_entry = item
if not uco_entry:
return None
uco = int(uco_entry[len('UCO='):])
return uco
class UserService:
......@@ -73,10 +83,17 @@ class UserService:
def _set_user_data(self, data: dict, full: bool = False) -> User:
if (data.get("is_admin") is not None) and full:
self.user.is_admin = data['is_admin']
if self.ldap.is_enabled:
data['uco'] = self.ldap.extract_uco()
self.__update_uco_using_ldap(data)
return general.update_entity(self.user, data, allowed=['name', 'email', 'uco'])
def __update_uco_using_ldap(self, data):
if self.ldap.is_enabled:
uco = self.ldap.extract_uco()
if uco:
data['uco'] = uco
else:
log.warning(f'[LDAP] Cannot extract UCO for user: {self.user.log_name}')
def create_user(self, **data):
"""Creates a new user
......
"""
LDAP integration module
"""
import ldap3
from flask import Flask
import ldap
from ldap.ldapobject import LDAPObject
import logging
from portal import logger
......@@ -15,6 +13,7 @@ class LDAPWrapper(object):
def __init__(self, app: Flask = None):
self.flask_app = None
self._ldap_client = None
self._ldap_server = None
self._selector_base = ',dc=fi,dc=muni,dc=cz'
if app:
self.init_app(app)
......@@ -49,22 +48,24 @@ class LDAPWrapper(object):
return self._selector_base
@property
def ldap(self) -> LDAPObject:
def ldap(self) -> ldap3.Server:
"""LDAP object instance
Returns(LDAPObject): LDAP Object instance
"""
if not self._ldap_client and self.is_enabled:
self._ldap_client = ldap.initialize(self.ldap_url, bytes_mode=False)
return self._ldap_client
if not self._ldap_server and self.is_enabled:
self._ldap_server = ldap3.Server(self.ldap_url, get_info=ldap3.ALL)
return self._ldap_server
@property
def ldap_connection(self):
connection = None
if self.ldap is not None:
connection = ldap3.Connection(self.ldap, auto_bind=True)
return connection
def search(self, selector: str):
selector = selector + self.selector_base
result = self.ldap.search_s(selector, ldap.SCOPE_SUBTREE, "objectclass=*")
self.ldap_connection.search(selector, '(objectclass=*)', attributes=ldap3.ALL_ATTRIBUTES)
result = self.ldap_connection.entries[0]
log.debug(f"[LDAP] Search ({selector}): {result}")
return result
def search_dict(self, *args, **kwargs):
l_res = self.search(*args, **kwargs)
if not l_res:
return None
return [rec[1] for rec in l_res]
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment