Skip to content
Snippets Groups Projects
Verified Commit f22de5f7 authored by Peter Stanko's avatar Peter Stanko
Browse files

Enabled uco extraction for LDAP

parent e6a7b380
No related branches found
No related tags found
1 merge request!8LDAP integration
......@@ -19,7 +19,7 @@ build:
- shared-fi
before_script:
- echo exit 0 > /usr/sbin/policy-rc.d
- apt update && apt install -y redis-server
- apt update && apt install -y redis-server ldap-utils ldapscripts libldap2-dev libsasl2-dev
- service redis-server start
- python -V # Print out python version for debugging
- pip install pipenv
......
......@@ -22,6 +22,7 @@ python-gitlab = "*"
psycopg2-binary = "*"
flask-restplus = "*"
celery = {extras = ["auth", "yaml", "msgpack", "redis"]}
python-ldap = "*"
[dev-packages]
pytest-cov = "*"
......
......@@ -17,6 +17,7 @@ from storage import Storage
from portal import rest
from portal.config import CONFIGURATIONS
from portal.tools.gitlab_client import GitlabFactory
from portal.tools.ldap_client import LDAPWrapper
from portal.tools.paths import ROOT_DIR
db = SQLAlchemy()
......@@ -26,6 +27,7 @@ cors = CORS(supports_credentials=True)
storage = Storage()
migrate = Migrate(db=db)
gitlab_factory = GitlabFactory()
ldap_wrapper = LDAPWrapper()
log = logging.getLogger(__name__)
......@@ -65,7 +67,7 @@ def configure_storage(app: Flask) -> Flask:
test_files_dir=app.config.get('PORTAL_STORAGE_TEST_FILES_DIR'),
submissions_dir=app.config.get('PORTAL_STORAGE_SUBMISSIONS_DIR'),
workspace_dir=app.config.get('PORTAL_STORAGE_WORKSPACE_DIR')
)
)
storage.init_storage(**storage_config)
return app
......@@ -84,6 +86,7 @@ def configure_extensions(app: Flask):
oauth.init_app(app)
cors.init_app(app)
gitlab_factory.init_app(app)
ldap_wrapper.init_app(app)
return app
......
......@@ -5,6 +5,7 @@ Users service
import logging
from typing import List
from portal import ldap_wrapper
from portal.database.models import Course, Group, Project, Review, Role, Submission, User
from portal.service import emails, general
from portal.service.errors import IncorrectCredentialsError, PortalAPIError
......@@ -29,14 +30,36 @@ def create_user(**data) -> User:
Returns(User): Created user instance
"""
data['is_admin'] = data.get('is_admin', False)
new_user = User(username=data['username'])
username = data['username']
new_user = User(username=username)
__set_user_data(new_user, data, True)
if data['uco'] is None and ldap_wrapper.is_enabled:
new_user.uco = ldap_get_uco_for_user(username)
emails.notify_user(new_user, 'users', 'created',
context=dict(username=new_user.username))
context=dict(username=username))
log.info(f"[CREATE] User: {new_user}")
return new_user
def ldap_get_uco_for_user(username: str) -> int:
"""Get uco from the ldap
Args:
username(str): Username
Returns(int): User's uco
"""
user_dict = ldap_wrapper.search_dict(f"uid={username},ou=People")
if not user_dict:
return 0
desc = user_dict[0]['description']
uco = [u for u in desc if u.startswith('UCO=')]
if not uco:
return 0
return int(uco[0][4:])
def update_user(user: User, data: dict, full: bool = False) -> User:
"""Updates a user
......@@ -117,8 +140,8 @@ def find_users_filtered(course_id: str = None,
course = find_course(course_id)
users = users.join(User.groups).filter(
((Group.id == group_id) | (Group.name == group_id)) & (
course.id == Group.course_id)
)
course.id == Group.course_id)
)
return users.all()
......@@ -187,7 +210,7 @@ def find_submissions_filtered(user: User, course_id: str = None,
submissions = submissions.filter(
((Project.id.in_(project_ids)) | (Project.name.in_(project_ids))) &
(Project.course == course)
)
)
submissions = submissions.join(Course).filter(
(Course.id == course_id) | (Course.codename == course_id))
return submissions
......
"""
LDAP integration module
"""
from flask import Flask
import ldap
from ldap.ldapobject import LDAPObject
import logging
log = logging.getLogger(__name__)
class LDAPWrapper(object):
def __init__(self, app: Flask = None):
self.flask_app = None
self._ldap_client = None
self._selector_base = ',dc=fi,dc=muni,dc=cz'
if app:
self.init_app(app)
def init_app(self, app: Flask):
self.flask_app = app
self._ldap_client = None
return app
@property
def ldap_url(self) -> str:
"""Returns the LDAP server URL
Returns(str): URL to the LDAP server
"""
return self.flask_app.config.get('LDAP_URL', None)
@property
def is_enabled(self) -> bool:
"""Whether the LDAP extension is enabled
LDAP is enabled when LDAP url is set
Returns(bool): true if is enabled, otherwise false
"""
return self.ldap_url is not None
@property
def selector_base(self) -> str:
"""Base selector, for FI muni it is: 'dc=fi,dc=muni,dc=cz'
Returns(str): Selector base string
"""
return self._selector_base
@property
def ldap(self) -> LDAPObject:
"""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)
return self._ldap_client
def search(self, selector: str):
selector = selector + self.selector_base
return self.ldap.search_s(selector, ldap.SCOPE_SUBTREE, "objectclass=*")
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]
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