diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5e9bbd5cd694559670f5820e7f7c0f915c07b753..0efc6c0c78300fc7b7aa811a4b83b49ab6a23ed5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -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
diff --git a/Pipfile b/Pipfile
index d38782c31f01885d67f83d21b128592abfd19e82..123122bb5d3cdd5b0abf66ecec6906d0154a4e02 100644
--- a/Pipfile
+++ b/Pipfile
@@ -22,6 +22,7 @@ python-gitlab = "*"
 psycopg2-binary = "*"
 flask-restplus = "*"
 celery = {extras = ["auth", "yaml", "msgpack", "redis"]}
+python-ldap = "*"
 
 [dev-packages]
 pytest-cov = "*"
diff --git a/portal/__init__.py b/portal/__init__.py
index ea08b93e76b2ff0fbc2ccd9ba085d477830205bf..a17d3ce2f6877efbda807ad7b34ff3ca834f731c 100644
--- a/portal/__init__.py
+++ b/portal/__init__.py
@@ -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
 
 
diff --git a/portal/service/users.py b/portal/service/users.py
index 941ca64d19b6541b1dac1d87d1b548ad586fc15a..528e03a619f9b4ab2817130d2c1d0fbd4d869aec 100644
--- a/portal/service/users.py
+++ b/portal/service/users.py
@@ -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
diff --git a/portal/tools/ldap_client.py b/portal/tools/ldap_client.py
new file mode 100644
index 0000000000000000000000000000000000000000..c69d5618428b62a8cd44789d05254f5ec6bf6088
--- /dev/null
+++ b/portal/tools/ldap_client.py
@@ -0,0 +1,66 @@
+"""
+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]