Skip to content

Commit

Permalink
Create documentation to authenticate with LDAP (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
RyanHir authored Jul 24, 2022
1 parent fbcf758 commit fdbb675
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ yarn-error.log*
/site/resources/
/site/node_modules/
/site/tech-doc-hugo
/site/.hugo_build.lock

# Ignore all the installed packages
node_modules
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Tests for import/export annotation, dataset, backup from/to cloud storage
- Added Python SDK package (`cvat-sdk`)
- Previews for jobs
- Documentation for LDAP authentication (<https://github.com/cvat-ai/cvat/pull/39>)

### Changed
- Bumped nuclio version to 1.8.14
Expand Down
211 changes: 211 additions & 0 deletions site/content/en/docs/administration/advanced/ldap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
<!--lint disable maximum-heading-length-->

---

title: 'LDAP Backed Authentication'
linkTitle: 'LDAP Login'
weight: 5
description: 'Allow users to login with credentials from a central source'

---

<!--lint disable maximum-line-length-->

### The creation of `settings.py`
When integrating LDAP login, we need to create an overlay to the default CVAT
settings located in
[cvat/settings/production.py](https://github.com/cvat-ai/cvat/blob/develop/cvat/settings/production.py).
This overlay is where we will configure Django to connect to the LDAP server.

The main issue with using LDAP is that different LDAP implementations have
different parameters. So the options used for Active Directory backed
authentication will differ if you were to be using FreeIPA.

### Update `docker-compose.override.yml`

In your override config you need to passthrough your settings and tell CVAT to
use them by setting the `DJANGO_SETTINGS_MODULE` variable.

```yml
version: '3.3'

services:
cvat:
environment:
DJANGO_SETTINGS_MODULE: settings
volumes:
- ./settings.py:/home/django/settings.py:ro
```
### Active Directory Example
The following example should allow for users to authenticate themselves against
Active Directory. This example requires a dummy user named `cvat_bind`. The
configuration for the bind account does not need any special permissions.

When updating `AUTH_LDAP_BIND_DN`, you can write out the account info in two
ways. Both are documented in the config below.

This config is known to work with Windows Server 2022, but should work for older
versions and Samba's implementation of Active Directory.

```py
# 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 NestedActiveDirectoryGroupType
# Notify CVAT that we are using LDAP authentication
IAM_TYPE = 'LDAP'
# Talking to the LDAP server
AUTH_LDAP_SERVER_URI = "ldap://ad.example.com" # IP Addresses also work
ldap.set_option(ldap.OPT_REFERRALS, 0)
_BASE_DN = "CN=Users,DC=ad,DC=example,DC=com"
# Authenticating with the LDAP server
AUTH_LDAP_BIND_DN = "CN=cvat_bind,%s" % _BASE_DN
# AUTH_LDAP_BIND_DN = "cvat_bind@ad.example.com"
AUTH_LDAP_BIND_PASSWORD = "SuperSecurePassword^21"
AUTH_LDAP_USER_SEARCH = LDAPSearch(
_BASE_DN,
ldap.SCOPE_SUBTREE,
"(sAMAccountName=%(user)s)"
)
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
_BASE_DN,
ldap.SCOPE_SUBTREE,
"(objectClass=group)"
)
# Mapping Django field names to Active Directory attributes
AUTH_LDAP_USER_ATTR_MAP = {
"user_name": "sAMAccountName",
"first_name": "givenName",
"last_name": "sn",
"email": "mail",
}
# Group Management
AUTH_LDAP_GROUP_TYPE = NestedActiveDirectoryGroupType()
# Register Django LDAP backend
AUTHENTICATION_BACKENDS += ['django_auth_ldap.backend.LDAPBackend']
# Map Active Directory groups to Django/CVAT groups.
AUTH_LDAP_ADMIN_GROUPS = [
'CN=CVAT Admins,%s' % _BASE_DN,
]
AUTH_LDAP_BUSINESS_GROUPS = [
'CN=CVAT Managers,%s' % _BASE_DN,
]
AUTH_LDAP_WORKER_GROUPS = [
'CN=CVAT Workers,%s' % _BASE_DN,
]
AUTH_LDAP_USER_GROUPS = [
'CN=CVAT Users,%s' % _BASE_DN,
]
DJANGO_AUTH_LDAP_GROUPS = {
"admin": AUTH_LDAP_ADMIN_GROUPS,
"business": AUTH_LDAP_BUSINESS_GROUPS,
"user": AUTH_LDAP_USER_GROUPS,
"worker": AUTH_LDAP_WORKER_GROUPS,
}
```
### FreeIPA Example

The following example should allow for users to authenticate themselves against
FreeIPA. This example requires a dummy user named `cvat_bind`. The configuration
for the bind account does not need any special permissions.

When updating `AUTH_LDAP_BIND_DN`, you can only write the user info in one way,
unlike with [Active Directory](#active-directory-example)

This config is known to work with AlmaLinux 8, but may work for other
versions and flavors of Enterprise Linux.

```py
# 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
IAM_TYPE = 'LDAP'
_BASE_DN = "CN=Accounts,DC=ipa,DC=example,DC=com"
# 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 = "UID=cvat_bind,CN=Users,%s" % _BASE_DN
AUTH_LDAP_BIND_PASSWORD = "SuperSecurePassword^21"
AUTH_LDAP_USER_SEARCH = LDAPSearch(
"CN=Users,%s" % _BASE_DN,
ldap.SCOPE_SUBTREE,
"(uid=%(user)s)"
)
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
"CN=Groups,%s" % _BASE_DN,
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,%s' % _BASE_DN,
]
AUTH_LDAP_BUSINESS_GROUPS = [
'CN=cvat_managers,CN=Groups,%s' % _BASE_DN,
]
AUTH_LDAP_WORKER_GROUPS = [
'CN=cvat_workers,CN=Groups,%s' % _BASE_DN,
]
AUTH_LDAP_USER_GROUPS = [
'CN=cvat_users,CN=Groups,%s' % _BASE_DN,
]
DJANGO_AUTH_LDAP_GROUPS = {
"admin": AUTH_LDAP_ADMIN_GROUPS,
"business": AUTH_LDAP_BUSINESS_GROUPS,
"user": AUTH_LDAP_USER_GROUPS,
"worker": AUTH_LDAP_WORKER_GROUPS,
}
```

### Resources
- [Microsoft - LDAP Distinguished Names](https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ldap/distinguished-names)
- Elements that make up a distinguished name. Used with user/group searches.
- [Django LDAP Reference Manual](https://django-auth-ldap.readthedocs.io/en/latest/reference.html)
- Other options that can be used for LDAP authentication in Django.
- [Django LDAP guide using Active Directory (Unofficial)](https://techexpert.tips/django/django-ldap-authentication-active-directory)
- This is not specific to CVAT but can provide insight about firewall rules.

0 comments on commit fdbb675

Please sign in to comment.