Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add instruction to enable LDAP auth #311

Closed
lupin-de-mid opened this issue Feb 4, 2019 · 22 comments
Closed

Add instruction to enable LDAP auth #311

lupin-de-mid opened this issue Feb 4, 2019 · 22 comments
Assignees
Labels
documentation Documentation should be updated

Comments

@lupin-de-mid
Copy link

I see LDAP only in user_guide.md
Probably it is related to django-auth-ldap

@nmanovic
Copy link
Contributor

nmanovic commented Feb 5, 2019

Hi @lupin-de-mid ,

create settings.py file and add content below. Replace all <...> on something which is specific for your LDAP server configuration. Read django_auth_ldap documentation for more details about different parameters.

Inside docker-compose.override.yml you need to define DJANGO_SETTINGS_MODULE: settings inside environment section for cvat container. It will replace default cvat.settings.production settings file.

from cvat.settings.production import *

# add custom apps here
import ldap
from django_auth_ldap.config import LDAPSearch, NestedActiveDirectoryGroupType

DJANGO_AUTH_TYPE = 'LDAP'
AUTH_LOGIN_NOTE = '''<p>
    For successful login please make sure you are member of cvat_users group
</p>'''

# Baseline configuration.
AUTH_LDAP_SERVER_URI = "ldap://<ldap-host>:<ldap-port>"

# Credentials for LDAP server
AUTH_LDAP_BIND_DN = "<username>"
AUTH_LDAP_BIND_PASSWORD = "<password>"

# Set up basic user search
AUTH_LDAP_USER_SEARCH = LDAPSearch("<params>",
    ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)")

# Set up the basic group parameters.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("<params>",
    ldap.SCOPE_SUBTREE, "(objectClass=group)")
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()

# Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}

AUTH_LDAP_ALWAYS_UPDATE_USER = True

# Cache group memberships for an hour to minimize LDAP traffic
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600
AUTH_LDAP_AUTHORIZE_ALL_USERS = True

# Keep ModelBackend around for per-user permissions and maybe a local
# superuser.
AUTHENTICATION_BACKENDS += ['django_auth_ldap.backend.LDAPBackend']

AUTH_LDAP_ADMIN_GROUPS = [
    'CN=cvat_admin,<params>',
]

AUTH_LDAP_ANNOTATOR_GROUPS = [
    'CN=data_annotation,<params>',
]

AUTH_LDAP_USER_GROUPS = [
    'CN=cvat_users,<params>',
]

AUTH_LDAP_OBSERVER_GROUPS = [
    'CN=cvat_users,<params>',
]

@nmanovic
Copy link
Contributor

nmanovic commented Feb 5, 2019

@lupin-de-mid , let me know if it doesn't work for you. Could you please help us and contribute some documentation based on your experience and my hints?

@nmanovic nmanovic added the documentation Documentation should be updated label Feb 5, 2019
@nmanovic nmanovic added this to the Backlog milestone Feb 5, 2019
@lupin-de-mid
Copy link
Author

Hi @nmanovic, i'll try this week

Is it nesessary to provide groups in ldap?
I prefer manage permissions by cvat itself and use LDAP only for AUTH

@nmanovic
Copy link
Contributor

nmanovic commented Feb 5, 2019

Hi @nmanovic, i'll try this week

Is it nesessary to provide groups in ldap?
I prefer manage permissions by cvat itself and use LDAP only for AUTH

It is necessary because it is how CVAT will determine if the user has admin, user, annotator or observer roles. In case of basic authorization you do it manually in admin panel. In case of LDAP, admin panel can not be used anymore for specifying roles (you can but such settings will be reseted after LDAP cache is reinitialized) as far as I remember.

@rcbop
Copy link

rcbop commented Mar 9, 2020

I used a very similar configuration to the one presented above and I confirm it's working

@AzaelCicero
Copy link
Contributor

Where should I put the settings.py file to be picked up by build via docker-compose?

TOsmanov pushed a commit to TOsmanov/cvat that referenced this issue Aug 23, 2021
* Fix whitespace errors

As detected with `git diff --check`.

* Add a job to check for whitespace errors

I called it "lint" so that other checks could be added to it later.

* Bump copyright years in changed files
TOsmanov pushed a commit to TOsmanov/cvat that referenced this issue Aug 23, 2021
* Rename 'openvino' plugin to 'openvino_plugin' (cvat-ai#205)

Co-authored-by: Jihyeon Yi <[email protected]>

* Make remap labels more accurate, allow explicit label deletion, add docs, update tests (cvat-ai#203)

* Kate/handling multiple attributes and speed up detection split (cvat-ai#207)

* better handling multi-attributes for classification_split

* handling multi-attributes better for detection

* bugfix in calculating required number of images for splitting 2 correct side effect of the changes for re-id split

* allow multiple subsets with arbitrary names

* rename _is_number to _is_float and improve it

* Fix voc to coco example (cvat-ai#209)

* Fix export filtering

* update example in readme

* Fix export filename for LabelMe format (cvat-ai#200)

* change export filename for LabelMe format

* Allow simple merge for datasets with no labels

* Add a more complex test on relative paths

* Support escaping in attributes

* update changelog

Co-authored-by: Maxim Zhiltsov <[email protected]>

* split unlabeled data into subsets for task-specific splitters (cvat-ai#211)

* split unlabeled data into subsets for classification, detection. for re-id, 'not-supported' subsets for this data

* Fix image ext on saving in cvat format (cvat-ai#214)

* fix image saving in cvat format

* update changelog

* Label "face" for bounding boxes in Wider Face (cvat-ai#215)

* add face label

* update changelog

* Adding "difficult", "truncated", "occluded" attributes when converting to Pascal VOC if they are not present (cvat-ai#216)

* remove check for 'difficult' attribute

* remove check for 'truncated' and 'occluded' attributes

* update changelog

* Ignore empty lines in YOLO annotations (cvat-ai#221)

* Ignore empty lines in yolo annotations

* Add type hints for image class, catch image opening errors in image.size

* update changelog

* Classification task in LFW dataset format (cvat-ai#222)

* add classification

* update changelog

* update documentation

* Add splitter for segmentation task  (cvat-ai#223)

* added segmentation_split

* updated changelog

* rename reidentification to reid

* Support for CIFAR-10/100 format (cvat-ai#225)

* add CIFAR dataset format

* add CIFAR to documentation

* update Changelog

* add validation item for instance segmentation (cvat-ai#227)

* add validation item for instance segmentation

* Add panoptic and stuff COCO format (cvat-ai#210)

* add coco stuff and panoptic formats

* update CHANGELOG

Co-authored-by: Maxim Zhiltsov <[email protected]>

* update detection splitter algorithm from # of samples to # of instances (cvat-ai#235)

* add documentation for validator (cvat-ai#233)

* add documentation for validator

* add validation item description (cvat-ai#237)

* Fix converter for Pascal VOC format (cvat-ai#239)

* User documentation for Pascal VOC format (cvat-ai#228)

* add user documentation for Pascal VOC format

* add integration tests

* update changelog

* Support for MNIST dataset format (cvat-ai#234)

* add mnist format

* add mnist csv format

* add mnist to documentation

* make formats docs folder, create COCO format documentation (cvat-ai#241)

* Make formats docs folder, move format docs

* Create COCO format documentation

* Fixes in CIFAR dataset format (cvat-ai#243)

* Add folder creation

* Update changelog

* Add user documentation file and integration tests for YOLO format (cvat-ai#246)

* add user documentation file for yolo

* add integraion tests

* update user manual

* update changelog

* Add Cityscapes format (cvat-ai#249)

* add cityscapes format

* add format docs

* update changelog

* Fix saving attribute in WiderFace extractor (cvat-ai#251)

* add fixes

* update changelog

* Fix spelling errors (cvat-ai#252)

* Configurable Threshold CLI support (cvat-ai#250)

* add validator cli

* add configurable validator threshold

* update changelog

* CI. Move to GitHub actions. (cvat-ai#263)

* Moving to GitHub Actions

* Sending a coverage report if python3.6 (cvat-ai#264)

* Rename workflows (cvat-ai#265)

* Rename workflows

* Update repo config and badge (cvat-ai#266)

* Update PR template

* Update build status badge

* Fix deprecation warnings (cvat-ai#270)

* Update RISE docs (cvat-ai#255)

* Update rise docs

* Update cli help

* Pytest related changes (cvat-ai#248)

* Tests moved to pytest. Updated CI. Updated requirements.

* Updated contribution guide

* Added annotations for tests

* Updated tests

* Added code style guide

* Fix CI (cvat-ai#272)

* Fix script call

* change script call to binary call

* Fix help program name, add mark_bug (cvat-ai#275)

* Fix prog name

* Add mark_bug test annotation

* Fix labelmap parameter in CamVid (cvat-ai#262)

* Fix labelmap parameter in camvid

* Release 0.1.9 (dev) (cvat-ai#276)

* Update version

* Update changelog

* Fix numpy conflict (cvat-ai#278)

* Add changelog stub (cvat-ai#279)

* tests/requirements.py: remove the test_wrapper functions (cvat-ai#285)

* Subformat importers for VOC and COCO (cvat-ai#281)

* Document find_sources

* Add VOC subformat importers

* Add coco subformat importers

* Fix LFW

* Reduce voc detect dataset cases

* Reorganize coco tests, add subformat tests

* Fix default subset handling in Dataset

* Fix getting subset

* Fix coco tests

* Fix voc tests

* Update changelog

* Add image zip format (cvat-ai#273)

* add tests

* add image_zip format

* update changelog

Co-authored-by: Maxim Zhiltsov <[email protected]>

* Add KITTI detection and segmentation formats (cvat-ai#282)

* Add KITTI detection and segmentation formats

* Remove unused import

* Add KITTI user manual

Co-authored-by: Maxim Zhiltsov <[email protected]>

* Fix loading file and image processing in CIFAR (cvat-ai#284)

* Fix image layout and encoding problems

* Update Changelog

Co-authored-by: Maxim Zhiltsov <[email protected]>

* CLI tests for convert command for VOC dataset (cvat-ai#286)

* Add tests for convert command

* Convert most enum definitions from the functional style to the class style (cvat-ai#290)

* yolo format documentation update (cvat-ai#295)

* add info about coordinates in yolo format doc

* Fix merged dataset item filtering (cvat-ai#258)

* Add tests

* Fix xpathfilter transform

* Update changelog

* Sms/pytest marking cityscapes and zip (cvat-ai#298)

* Updated pytest marking for cityscapes and imagezip.

* Introduce Validator plugin type (cvat-ai#299)

* Introduce Validator plugin type

* Fix validator definitions (cvat-ai#303)

* update changelog

* Fixes in validator definitions

* Update validator cli

* Make TF availability check optional (cvat-ai#305)

* Make tf availability check optional

* update changelog

* Update pylint (cvat-ai#304)

* Add import order check in pylint

* Fix some linter problems

* Remove warning suppression comments

* Add lazy loading for builtin plugins (cvat-ai#306)

* Refactor env code

* Load builtin plugins lazily

* update changelog

* Update transforms handling in Dataset (cvat-ai#297)

* Update builtin transforms

* Optimize dataset length computation when no source

* Add filter test

* Fix transforms affecting categories

* Optimize categories transforms

* Update filters

* fix imports

* Avoid using default docstrings in plugins

* Fix patch saving in VOC, add keep_empty export parameter

* Fix flush_changes

* Fix removed images and subsets in dataset patch

* Update changelog

* Update voc doc

* Skip item transform base class in plugins

* Readable COCO and datumaro format for CJK (cvat-ai#307)

* Do not force ASCII in COCO and Datumaro JSONs for readable CJK

* Add tests

* Use utf-8 encoding for writing

Co-authored-by: Maxim Zhiltsov <[email protected]>

* Force utf-8 everywhere (cvat-ai#309)

* Fix in ImageNet_txt (cvat-ai#302)

* Add extensions for images to annotation file

* Remove image search in extractor

* Update changelog

Co-authored-by: Maxim Zhiltsov <[email protected]>

* Reduce duplication of dependency information (cvat-ai#308)

* Move requirements from setup.py to requirements-base.txt

* Add whitespace error checking to GitHub Actions (cvat-ai#311)

* Fix whitespace errors

As detected with `git diff --check`.

* Add a job to check for whitespace errors

I called it "lint" so that other checks could be added to it later.

* Bump copyright years in changed files

* Add initial support for the Open Images dataset (cvat-ai#291)

* Support reading or Labels in Open Images (v4, v5, v6)

* Add tests for the Open Images extractor/importer

* Add Open Images documentation

* Update changelog

* Fix tensorboardX dependency (cvat-ai#318)

* Fixing remark-lint issues. Adding remark-linter check. (cvat-ai#321)

* Fix remark-lint issues.

* Align continuation lines with the first line.

Apply comments

* Added remark check

* Add an upper bound on the Pillow dependency to work around a regression in 8.3 (cvat-ai#323)

* open_images_user_manual.md: fix image description file URLs

I accidentally swapped the URLs for test and validation sets.

* Fix COCO Panoptic (cvat-ai#319)

* add test

* Fix integer overflow in bgr2index

* Fix pylint issues. Added pylint checking. (cvat-ai#322)

* Added pylint job for CI

* Rework pip install

* Fixed remaining pylint warnings

Co-authored-by: Andrey Zhavoronkov <[email protected]>

* Open Images: add writing support (cvat-ai#315)

* open_images_user_manual.md: fix image description file URLs

* open_images_format: add conversion support

* open_images_format: add support for images in subdirectories

* open_images_format: add tests for writing support

* open_images_format: add documentation for the writing support

* Update the changelog entry for the Open Images support

* Add python bandit checks. (cvat-ai#316)

* Add bandit dependency

* Add bandit checks on CI

* Disable some warnings

Co-authored-by: Andrey Zhavoronkov <[email protected]>
Co-authored-by: Maxim Zhiltsov <[email protected]>

* Remove Pylint unused-import warning suppressions (cvat-ai#326)

* Remove Pylint unused-import warning suppressions

* Add a job to check import formatting using isort (cvat-ai#333)

* Reformat all imports using isort

* Implement a workflow for checking import formatting based on isort

* Reformat the enabled checker list in .pylintrc (cvat-ai#335)

Put each code on its own line and add a comment with its symbolic name.
That makes the list more understandable and easier to edit.

* Merge all linting jobs into one workflow file (cvat-ai#331)

Doing it this way means that on GitHub's Checks page, all jobs are displayed
under one "Linter" category, instead of multiple indistinguishable "Linter"
categories with one job each.

Move the whitespace checking job into the Linter workflow as well, since
that's where it logically belongs.

I also took the opportunity to slightly rename the jobs in order to spell
the linter names correctly.

* Fix cuboids / 3d / M6 (cvat-ai#320)

* CVAT-3D Milestone-6: Added Supervisely Point Cloud and KITTI Raw 3D formats

* Added Cuboid3d annotations

* Added docs for new formats

Co-authored-by: cdp <cdp123>
Co-authored-by: Jayraj <[email protected]>
Co-authored-by: Roman Donchenko <[email protected]>

* Clean up .pylintrc (cvat-ai#340)

* Clean up the list of messages in .pylintrc

* Remove obsolete Pylint options

* .pylintrc: move the disable setting and its documentation together

* Remove the commented-out setting.

* Revert "Add an upper bound on the Pillow dependency to work around a regression in 8.3 (cvat-ai#323)" (cvat-ai#341)

The regression was fixed in 8.3.1.

This reverts commit 9a85616.

* Enable pylint checkers that find invalid escape sequences (cvat-ai#344)

Fix the issues that they found.

* Factor out the images.meta loading code from YoloExtractor (cvat-ai#343)

* Factor out the images.meta loading code from YoloExtractor

It looks like the same thing will be needed for Open Images, so I'm
moving it to a common module.

* Rework image.meta parsing code to use shell syntax

This allows comments and improves extensibility.

* Support for CIFAR-100 (cvat-ai#301)

* Add support for CIFAR-100

* Update Changelog

* Update user_manual.md

* Add notes about differences in formats

* Fix importing for VGG Face 2 (cvat-ai#345)

* correct asset according the original vgg_face2 dataset

* fix importing of the original dataset

Co-authored-by: Maxim Zhiltsov <[email protected]>

* Dataset caching fixes (cvat-ai#351)

* Fix importing arbitrary file names in COCO subformats

* Optimize subset iteration in a simple scenario

* Fix subset iteration in dataset with transforms

* Cuboid 3D for Datumaro format (cvat-ai#349)

* Support cuboid_3d and point cloud in datumaro format

* Add cuboid_3d and point cloud tests in datumaro format

* Add image size type conversions

Co-authored-by: Maxim Zhiltsov <[email protected]>

* Add e2e tests for cuboids (cvat-ai#353)

* Add attr name check in kitti raw

* Add sly pcd e2e test

* Rename "object" attribute to "track_id" in sly point cloud

* Add kitti raw e2e test

* Update kitti raw example

* update changelog

* Release 0.1.10 (dev) (cvat-ai#354)

* Update changelog

* Add cifar security notice

* Update version

Co-authored-by: Emily Chun <[email protected]>
Co-authored-by: Jihyeon Yi <[email protected]>
Co-authored-by: Kirill Sizov <[email protected]>
Co-authored-by: Anastasia Yasakova <[email protected]>
Co-authored-by: Harim Kang <[email protected]>
Co-authored-by: Zoya Maslova <[email protected]>
Co-authored-by: Roman Donchenko <[email protected]>
Co-authored-by: Seungyoon Woo <[email protected]>
Co-authored-by: Dmitry Kruchinin <[email protected]>
Co-authored-by: Slawomir Strehlke <[email protected]>
Co-authored-by: Jaesun Park <[email protected]>
Co-authored-by: Andrey Zhavoronkov <[email protected]>
Co-authored-by: Jayraj <[email protected]>
@nmanovic nmanovic removed this from the Backlog milestone Nov 28, 2021
@ygean
Copy link

ygean commented Dec 2, 2021

I used a very similar configuration to the one presented above and I confirm it's working
@rcbop Can you describe the detail ?

@ningjunwei2
Copy link
Contributor

I install CVAT through helm, how should I configure LDAP?

@ningjunwei2
Copy link
Contributor

Hi @lupin-de-mid ,

create settings.py file and add content below. Replace all <...> on something which is specific for your LDAP server configuration. Read django_auth_ldap documentation for more details about different parameters.

Inside docker-compose.override.yml you need to define DJANGO_SETTINGS_MODULE: settings inside environment section for cvat container. It will replace default cvat.settings.production settings file.

from cvat.settings.production import *

# add custom apps here
import ldap
from django_auth_ldap.config import LDAPSearch, NestedActiveDirectoryGroupType

DJANGO_AUTH_TYPE = 'LDAP'
AUTH_LOGIN_NOTE = '''<p>
    For successful login please make sure you are member of cvat_users group
</p>'''

# Baseline configuration.
AUTH_LDAP_SERVER_URI = "ldap://<ldap-host>:<ldap-port>"

# Credentials for LDAP server
AUTH_LDAP_BIND_DN = "<username>"
AUTH_LDAP_BIND_PASSWORD = "<password>"

# Set up basic user search
AUTH_LDAP_USER_SEARCH = LDAPSearch("<params>",
    ldap.SCOPE_SUBTREE, "(sAMAccountName=%(user)s)")

# Set up the basic group parameters.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("<params>",
    ldap.SCOPE_SUBTREE, "(objectClass=group)")
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()

# Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}

AUTH_LDAP_ALWAYS_UPDATE_USER = True

# Cache group memberships for an hour to minimize LDAP traffic
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600
AUTH_LDAP_AUTHORIZE_ALL_USERS = True

# Keep ModelBackend around for per-user permissions and maybe a local
# superuser.
AUTHENTICATION_BACKENDS += ['django_auth_ldap.backend.LDAPBackend']

AUTH_LDAP_ADMIN_GROUPS = [
    'CN=cvat_admin,<params>',
]

AUTH_LDAP_ANNOTATOR_GROUPS = [
    'CN=data_annotation,<params>',
]

AUTH_LDAP_USER_GROUPS = [
    'CN=cvat_users,<params>',
]

AUTH_LDAP_OBSERVER_GROUPS = [
    'CN=cvat_users,<params>',
]

this file in settings.py? and it's path is /home/django/settings.py in container?

@ningjunwei2
Copy link
Contributor

from cvat.settings.production import *

I put the settings.py file in the container's /home/django/ directory.it cannot log in with an LDAP account.
Any other places to configure?

@vaskokj
Copy link

vaskokj commented Jun 3, 2022

Ok this information is pretty far out of date. Configuration settings, environment variables and flow have all changed from 2.x. Here is what I did to get it to work.

We need override several settings in the ./cvat/settings/base.py that isn't listed here.

Make a docker-compose.override.yml in your ./cvat/ folder (where your docker-compose.yml file is).

version: '3.3'

services:
  cvat:
    environment:
      DJANGO_SETTINGS_MODULE: settings
    volumes:
      - ./settings.py:/home/django/settings.py:ro

Create a settings.py file in your ./cvat folder (same directory as above)

Key things we need to override in settings.py are

IAM_TYPE = 'LDAP'
and
DJANGO_AUTH_LDAP_GROUPS

Here is my full working settings.py file (with my LDAP services redacted)

from cvat.settings.production import *

# add custom apps here
import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType, NestedActiveDirectoryGroupType

IAM_TYPE = 'LDAP'
AUTH_LOGIN_NOTE = '''<p>
    For successful login please make sure you are member of cvat_users group
</p>'''

# Baseline configuration.
AUTH_LDAP_SERVER_URI = "<redacted>"

# Credentials for LDAP server
AUTH_LDAP_BIND_DN = "<redacted>"
AUTH_LDAP_BIND_PASSWORD = "<redacted>"

# Set up basic user search
AUTH_LDAP_USER_SEARCH = LDAPSearch("<redacted>",
    ldap.SCOPE_SUBTREE, "(uid=%(user)s)")

# Set up the basic group parameters.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("<redacted>",
    ldap.SCOPE_SUBTREE, "(objectClass=groupofnames)")
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()

# Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}

AUTH_LDAP_ALWAYS_UPDATE_USER = True

# Cache group memberships for an hour to minimize LDAP traffic
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600
AUTH_LDAP_AUTHORIZE_ALL_USERS = False

# Keep ModelBackend around for per-user permissions and maybe a local
# superuser.
AUTHENTICATION_BACKENDS += ['django_auth_ldap.backend.LDAPBackend']

# example 'cn=cvat_admin,cn=groups,cn=accounts,dc=example,dc=com'
# change your cn to match whatever groups you have in your LDAP
AUTH_LDAP_ADMIN_GROUPS = [
    'cn=<redacted>,
]

AUTH_LDAP_WORKER_GROUPS = [
    'cn=<redacted>,
]

AUTH_LDAP_USER_GROUPS = [
    'cn=<redacted>,
]

AUTH_LDAP_BUSINESS_GROUPS = [
    'cn=<redacted>,
]
DJANGO_AUTH_LDAP_GROUPS = {"admin": AUTH_LDAP_ADMIN_GROUPS, "business": AUTH_LDAP_WORKER_GROUPS, "user": AUTH_LDAP_USER_GROUPS, "worker":AUTH_LDAP_BUSINESS_GROUPS}

Three notable changes IAM_TYPE = 'LDAP', AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() (I'm using FreeIPA so we have to use GroupOfNames), and DJANGO_AUTH_LDAP_GROUPS = {"admin": AUTH_LDAP_ADMIN_GROUPS, "business": AUTH_LDAP_WORKER_GROUPS, "user": AUTH_LDAP_USER_GROUPS, "worker":AUTH_LDAP_BUSINESS_GROUPS}.

DJANGO_AUTH_LDAP_GROUPS admin, business, user, worker is coming from IAM_ROLES = [IAM_ADMIN_ROLE, 'business', 'user', 'worker'] in ./cvat/settings/base.py in the code it "matches" based on the keywords in IAM_ROLES. The AUTH_LDAP_ADMIN_GROUPS, AUTH_LDAP_WORKER_GROUPS, AUTH_LDAP_USER_GROUPS , AUTH_LDAP_BUSINESS_GROUPS need to be added to DJANGO_AUTH_LDAP_GROUPS list depending on your groups. If you want to add more groups, just add more in your settings.py file. Hopefully this helps someone else for v2.x+. This works for me for CVAT v2.1.

@RyanHir
Copy link
Contributor

RyanHir commented Jul 22, 2022

@vaskokj
Hello,
The writeup you gave has been invaluable to me getting authentication with Active Directory, but I am unable to get group mappings to work. Are you sure DJANGO_AUTH_LDAP_GROUPS is valid? I cannot find any reference to this variable on google other than this exact issue.

I am able to authenticate, but users with the proper group assigned in the domain do not get elevated in CVAT.

Attached I have snippet of how I have groups set up

AUTH_LDAP_ADMIN_GROUPS = [
    'cn=Domain Admins,cn=Users,dc=ad.dc=example,dc=com',
]

AUTH_LDAP_BUSINESS_GROUPS = [
    'cn=Domain Admins,cn=Users,dc=ad,dc=example,dc=com',
]

AUTH_LDAP_USER_GROUPS = [
    'cn=Users,dc=ad,dc=example,dc=com',
]

AUTH_LDAP_WORKER_GROUPS = [
    'cn=Users,dc=ad,dc=example,dc=com',
]

DJANGO_AUTH_LDAP_GROUPS = {
    "admin": AUTH_LDAP_ADMIN_GROUPS,
    "business": AUTH_LDAP_BUSINESS_GROUPS,
    "user": AUTH_LDAP_USER_GROUPS,
    "worker": AUTH_LDAP_WORKER_GROUPS,
}

The assumption is that Domain Admins are elevated to admin in CVAT but this does not appear to be the case.

@vaskokj
Copy link

vaskokj commented Jul 24, 2022

@RyanHir Here is a less redacted version of that section.

# Keep ModelBackend around for per-user permissions and maybe a local
# superuser.
AUTHENTICATION_BACKENDS += ['django_auth_ldap.backend.LDAPBackend']

AUTH_LDAP_ADMIN_GROUPS = [
    'CN=cvat_admin,cn=groups,cn=accounts,dc=example,dc=com',
]

AUTH_LDAP_WORKER_GROUPS = [
    'CN=cvat_worker,cn=groups,cn=accounts,dc=example,dc=com',
]

AUTH_LDAP_USER_GROUPS = [
    'CN=cvat_users,cn=groups,cn=accounts,dc=examples,dc=com',
]

AUTH_LDAP_BUSINESS_GROUPS = [
    'CN=cvat_business,cn=groups,cn=accounts,dc=example,dc=com',
]
DJANGO_AUTH_LDAP_GROUPS = {
    "admin": AUTH_LDAP_ADMIN_GROUPS, 
    "worker": AUTH_LDAP_WORKER_GROUPS, 
    "user": AUTH_LDAP_USER_GROUPS, 
    "business":AUTH_LDAP_BUSINESS_GROUPS
}

One other thing to check would be the group search section. You might be failing to find your groups depending on where you are searching.

# Set up the basic group parameters.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("cn=groups,cn=accounts,dc=example,dc=com",
    ldap.SCOPE_SUBTREE, "(objectClass=groupofnames)")
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()

I did end up having to change AUTH_LDAP_GROUP_TYPE. Since you are using AD you might need https://django-auth-ldap.readthedocs.io/en/latest/reference.html#django_auth_ldap.config.ActiveDirectoryGroupType. See the list of options here from django. https://django-auth-ldap.readthedocs.io/en/latest/reference.html#django_auth_ldap.config.ActiveDirectoryGroupType

Also double check your SCOPE_SUBTREE. Running a query on the users and groups and getting all of their options should give you want you need to search for in this config.

I will note that the permissions that this enables is extremely vague. I never could find a good clear understanding of what permissions each one of these items gives you.

Also make sure you clear the CVAT users. If I remember correctly, CVAT only reads the groups on CVAT user creation.

Hopefully this helps.

@RyanHir
Copy link
Contributor

RyanHir commented Jul 24, 2022

@vaskokj I have recreated a config as close to what you have with FreeIPA, but I am still unable to get CVAT group assignment to work. I even deleted all volumes to ensure CVAT accounts are being recreated. ldapsearch is showing that the user is correctly assigned to be a member of cn=cvat_admins,cn=groups,cn=accounts,dc=ipa,dc=example,dc=com.

# We are overlaying production
from cvat.settings.production import *

# Custom code below
import ldap
from django_auth_ldap.config import LDAPSearch
from django_auth_ldap.config import GroupOfNamesType

# Notify CVAT that we are using LDAP authentication
DJANGO_AUTH_TYPE = 'LDAP'

# Talking to the LDAP server
AUTH_LDAP_SERVER_URI = "ldap://ipa.example.com" # IP Addresses also work
ldap.set_option(ldap.OPT_REFERRALS, 0)

# Authenticating with the LDAP server
AUTH_LDAP_BIND_DN = "CN=cvat_bind,CN=Users,CN=Accounts,DC=ipa,DC=example,DC=com"
AUTH_LDAP_BIND_PASSWORD = "SuperSecurePassword^21"

AUTH_LDAP_USER_SEARCH = LDAPSearch(
    "CN=Users,CN=Accounts,DC=ipa,DC=example,DC=com",
    ldap.SCOPE_SUBTREE,
    "(uid=%(user)s)"
)

AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
    "CN=Groups,CN=Accounts,DC=ipa,DC=example,DC=com",
    ldap.SCOPE_SUBTREE,
    "(objectClass=groupOfNames)"
)

# Mapping Django field names to FreeIPA attributes
AUTH_LDAP_USER_ATTR_MAP = {
    "user_name": "uid",
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
}

# Group Management
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()

# Register Django LDAP backend
AUTHENTICATION_BACKENDS += ['django_auth_ldap.backend.LDAPBackend']

# Map FreeIPA groups to Django/CVAT groups.
AUTH_LDAP_ADMIN_GROUPS = [
    'CN=cvat_admins,CN=Groups,CN=Accounts,DC=ipa,DC=example,DC=com',
]
AUTH_LDAP_BUSINESS_GROUPS = [
    'CN=cvat_managers,CN=Groups,CN=Accounts,DC=ipa,DC=example,DC=com',
]
AUTH_LDAP_WORKER_GROUPS = [
    'CN=Groups,CN=Accounts,DC=ipa,DC=example,DC=com',
]
AUTH_LDAP_USER_GROUPS = [
    'CN=Groups,CN=Accounts,DC=ipa,DC=example,DC=com',
]

DJANGO_AUTH_LDAP_GROUPS = {
    "admin": AUTH_LDAP_ADMIN_GROUPS,
    "business": AUTH_LDAP_BUSINESS_GROUPS,
    "user": AUTH_LDAP_USER_GROUPS,
    "worker": AUTH_LDAP_WORKER_GROUPS,
}

@RyanHir
Copy link
Contributor

RyanHir commented Jul 24, 2022

I believe the issue is with CVAT itself or Django. I opened an issue earlier when I was working with Active Directory documentation #40

@vaskokj
Copy link

vaskokj commented Jul 24, 2022

@RyanHir

I had the same problem. Users could authenticate but it wasn't pulling the groups properly. Same symptoms, I could have missed something in my config here, but it might be a difference in our environments (e.g. FreeIPA vs AD).

What I did to debug the issue is add log statements into this piece of code https://github.com/openvinotoolkit/cvat/blob/develop/cvat/apps/iam/signals.py#L34 to see what CVAT thought each user was in at that point I was able to see what LDAP was being queried for in the LDAP logs.

@RyanHir
Copy link
Contributor

RyanHir commented Jul 24, 2022

@vaskokj

I do not think it is an issue of environments, as I can recreate this on both FreeIPA and AD. I will look into adding logs.

@vaskokj
Copy link

vaskokj commented Jul 24, 2022

Fair enough. Can you check your cn=Users,dc=ad.dc=example,dc=com to make sure you are pulling your cn properly? cn being uid vs users vs accounts, etc.?

@RyanHir
Copy link
Contributor

RyanHir commented Jul 24, 2022

Whoops, that was a typo. I corrected that earlier, but forgot to put that down. From the best I can tell, I am pulling the correct properties.

@RyanHir
Copy link
Contributor

RyanHir commented Jul 24, 2022

I found after putting logs that DJANGO_AUTH_TYPE needs to be replaced with IAM_TYPE. And I later discovered that in my config, the group name was incorrect cvat_admin vs cvat_admins.

@vaskokj
Copy link

vaskokj commented Jul 24, 2022

@RyanHir Glad you figured it out. I missed that too in your question but looks like I had it in my comment #311 (comment). This section of code is really sketch and probably needs to be reevaluated.

@darth-veitcher
Copy link

Thanks to everyone else in this thread.

In case it helps others I've successfully integrated this with authentik using the below settings.py:

"""LDAP authentication override for CVAT

See: 
* https://github.com/opencv/cvat/issues/311 for helpful information with cvat
* https://version-2024-2.goauthentik.io/docs/providers/ldap/ for canonical authentik reference
* https://django-auth-ldap.readthedocs.io/en/latest/authentication.html for Django LDAP docs
"""
import os
from cvat.settings.production import *

# add custom apps here
import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType, NestedActiveDirectoryGroupType

# ========================
# AUTHENTIK
#
# You can find this info from the `LDAP Provider` page in authentik once you have created it
# ========================
BASE_DN: str = os.environ.get("BASE_DN","ou=cvat,dc=ldap,dc=goauthentik,dc=io")  # also called `Search base` in authentik
USERS_DN: str = os.environ.get("USERS_DN",f"ou=users,{BASE_DN}")
GROUPS_DN: str = os.environ.get("GROUPS_DN",f"ou=groups,{BASE_DN}")
AUTH_LDAP_BIND_DN: str = os.environ.get("BIND_DN",f"cn=akadmin,{USERS_DN}")  # Credentials for LDAP server
AUTH_LDAP_BIND_PASSWORD: str = os.environ.get("AUTH_LDAP_BIND_PASSWORD")  # Credentials for LDAP server
if not AUTH_LDAP_BIND_PASSWORD:
    raise Exception("AUTH_LDAP_BIND_PASSWORD environment variable not found.")
# ========================

IAM_TYPE = 'LDAP'
AUTH_LOGIN_NOTE = '''<p>
    For successful login please make sure you are member of cvat_users group
</p>'''

# Baseline configuration.
AUTH_LDAP_SERVER_URI = os.environ.get('AUTH_LDAP_SERVER_URI', 'ldap://authentik_ldap:3389')
if not AUTH_LDAP_SERVER_URI:
    raise Exception("AUTH_LDAP_SERVER_URI environment variable not found.")
ldap.set_option(ldap.OPT_REFERRALS, 0)  # disable referrals

# Set up basic user search
AUTH_LDAP_USER_SEARCH = LDAPSearch(USERS_DN,
    ldap.SCOPE_SUBTREE, "(cn=%(user)s)")

# Set up the basic group parameters.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(GROUPS_DN,
    ldap.SCOPE_SUBTREE, "(objectClass=groupofnames)")
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()

# Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP = {
    "user_name": "cn",
    "first_name": "cn",
    "last_name": "sn",
    "email": "mail",
}

AUTH_LDAP_ALWAYS_UPDATE_USER = True

# Cache group memberships for an hour to minimize LDAP traffic
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600
AUTH_LDAP_AUTHORIZE_ALL_USERS = False

# Keep ModelBackend around for per-user permissions and maybe a local
# superuser.
AUTHENTICATION_BACKENDS += ['django_auth_ldap.backend.LDAPBackend']

# example 'cn=cvat_admin,cn=groups,cn=accounts,dc=example,dc=com'
# change your cn to match whatever groups you have in your LDAP
AUTH_LDAP_ADMIN_GROUPS = [
    f'cn=cvat_admins,{GROUPS_DN}'
]

AUTH_LDAP_WORKER_GROUPS = [
    f'cn=cvat_workers,{GROUPS_DN}'
]

AUTH_LDAP_USER_GROUPS = [
    f'cn=cvat_users,{GROUPS_DN}'
]

AUTH_LDAP_BUSINESS_GROUPS = [
    f'cn=cvat_managers,{GROUPS_DN}'
]

DJANGO_AUTH_LDAP_GROUPS = {
    "admin": AUTH_LDAP_ADMIN_GROUPS, 
    "business": AUTH_LDAP_WORKER_GROUPS, 
    "user": AUTH_LDAP_USER_GROUPS, 
    "worker":AUTH_LDAP_BUSINESS_GROUPS
}

The docker-compose-ldap.override.yaml I used on top of the basic one provided in the repository (note the external ldap network that my authentik outpost is connected to). Note you'll need to use a .env file to pass through the necessary environment variables to the settings.py above.

You'll run this with a command similar to docker-compose -f cvat/docker-compose.yml -f docker-compose-dev.override.yaml -f docker-compose-ldap.override.yaml up (where I'm using both some development environment overrides as well as the LDAP one finally).

# file: docker-compose-ldap.override.yaml
services:
  cvat_server:
    env_file: .env
    environment:
      DJANGO_SETTINGS_MODULE: settings
    volumes:
      - ../settings.py:/home/django/settings.py:ro
    networks:
      ldap:

networks:
  ldap:
    name: ldap
    external: true

And then finally the additional LDAP service I needed to add in my authentik docker-compose file.

# file: authentik/docker-compose.yaml
services:
  ...
  # LDAP Outpost
  authentik_ldap:
    env_file: .env
    image: ghcr.io/goauthentik/ldap
    hostname: ldap.${ROOT_DOMAIN}
    # Optionally specify which networks the container should be
    # might be needed to reach the core authentik server
    networks:
      - default
      - ldap
    ports:
      - 389 # 389:3389 | LDAP server
      - 636 # 636:6636 | LDAP SSL server
      - 9300 # Metrics server
    environment:
      AUTHENTIK_HOST: http://auth.${ROOT_DOMAIN}
      AUTHENTIK_INSECURE: "true"
      AUTHENTIK_TOKEN: ${LDAP_TOKEN}
      AUTHENTIK_DEBUG: true # unset/false in production

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Documentation should be updated
Projects
Development

No branches or pull requests

10 participants