Skip to content

Commit fb43081

Browse files
committed
Merge pull request #3174 from phspagiari/feature_auth_ldap
feat(controller): Adding LDAP/AD auth support
2 parents 4094b81 + 9eb9472 commit fb43081

8 files changed

Lines changed: 117 additions & 4 deletions

File tree

controller/build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ DEBIAN_FRONTEND=noninteractive
1616
# HACK: install git so we can install bacongobbler's fork of django-fsm
1717
# install openssh-client for temporary fleetctl wrapper
1818
apt-get update && \
19-
apt-get install -yq python-dev libffi-dev libpq-dev libyaml-dev git
19+
apt-get install -yq python-dev libffi-dev libpq-dev libyaml-dev git libldap2-dev libsasl2-dev
2020

2121
# install pip
2222
curl -sSL https://raw.githubusercontent.com/pypa/pip/6.0.8/contrib/get-pip.py | python -

controller/deis/settings.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
import string
99
import sys
1010
import tempfile
11+
import ldap
12+
13+
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType
14+
1115

1216
PROJECT_ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__), '..'))
1317

@@ -138,6 +142,7 @@
138142
'django.contrib.sites',
139143
'django.contrib.staticfiles',
140144
# Third-party apps
145+
'django_auth_ldap',
141146
'guardian',
142147
'json_field',
143148
'gunicorn',
@@ -151,6 +156,7 @@
151156
)
152157

153158
AUTHENTICATION_BACKENDS = (
159+
"django_auth_ldap.backend.LDAPBackend",
154160
"django.contrib.auth.backends.ModelBackend",
155161
"guardian.backends.ObjectPermissionBackend",
156162
)
@@ -324,6 +330,16 @@
324330
# server - Hostname based on CoreOS server hostname
325331
UNIT_HOSTNAME = 'default'
326332

333+
# LDAP DEFAULT SETTINGS (Overrided by confd later)
334+
LDAP_ENDPOINT = ""
335+
BIND_DN = ""
336+
BIND_PASSWORD = ""
337+
USER_BASEDN = ""
338+
USER_FILTER = ""
339+
GROUP_BASEDN = ""
340+
GROUP_FILTER = ""
341+
GROUP_TYPE = ""
342+
327343
# Create a file named "local_settings.py" to contain sensitive settings data
328344
# such as database configuration, admin email, or passwords and keys. It
329345
# should also be used for any settings which differ between development
@@ -334,9 +350,41 @@
334350
except ImportError:
335351
pass
336352

337-
338353
# have confd_settings within container execution override all others
339354
# including local_settings (which may end up in the container)
340355
if os.path.exists('/templates/confd_settings.py'):
341356
sys.path.append('/templates')
342357
from confd_settings import * # noqa
358+
359+
# LDAP Backend Configuration
360+
# Should be always after the confd_settings import.
361+
LDAP_USER_SEARCH = LDAPSearch(
362+
base_dn=USER_BASEDN,
363+
scope=ldap.SCOPE_SUBTREE,
364+
filterstr="(%s=%%(user)s)" % USER_FILTER
365+
)
366+
LDAP_GROUP_SEARCH = LDAPSearch(
367+
base_dn=GROUP_BASEDN,
368+
scope=ldap.SCOPE_SUBTREE,
369+
filterstr="(%s=%s)" % (GROUP_FILTER, GROUP_TYPE)
370+
)
371+
AUTH_LDAP_SERVER_URI = LDAP_ENDPOINT
372+
AUTH_LDAP_BIND_DN = BIND_DN
373+
AUTH_LDAP_BIND_PASSWORD = BIND_PASSWORD
374+
AUTH_LDAP_USER_SEARCH = LDAP_USER_SEARCH
375+
AUTH_LDAP_GROUP_SEARCH = LDAP_GROUP_SEARCH
376+
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
377+
AUTH_LDAP_USER_ATTR_MAP = {
378+
"first_name": "givenName",
379+
"last_name": "sn",
380+
"email": "mail",
381+
"username": USER_FILTER,
382+
}
383+
AUTH_LDAP_GLOBAL_OPTIONS = {
384+
ldap.OPT_X_TLS_REQUIRE_CERT: False,
385+
ldap.OPT_REFERRALS: False
386+
}
387+
AUTH_LDAP_ALWAYS_UPDATE_USER = True
388+
AUTH_LDAP_MIRROR_GROUPS = True
389+
AUTH_LDAP_FIND_GROUP_PERMS = True
390+
AUTH_LDAP_CACHE_GROUPS = False

controller/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ django-cors-headers==1.0.0
99
django-fsm==2.2.0
1010
django-guardian==1.2.5
1111
django-json-field==0.5.7
12+
django-auth-ldap==1.2.5
1213
djangorestframework==3.0.5
1314
docker-py==0.7.2
1415
gunicorn==19.3.0
@@ -19,3 +20,4 @@ PyYAML==3.11
1920
setproctitle==1.1.8
2021
static==1.1.1
2122
South==1.0.2
23+
python-ldap==2.4.19

controller/templates/confd_settings.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,16 @@
4545
WEB_ENABLED = bool({{ getv "/deis/controller/webEnabled" }})
4646
{{ end }}
4747
UNIT_HOSTNAME = '{{ if exists "/deis/controller/unitHostname" }}{{ getv "/deis/controller/unitHostname" }}{{ else }}default{{ end }}'
48+
49+
# AUTH
50+
# LDAP
51+
{{ if exists "/deis/controller/auth/ldap/endpoint" }}
52+
LDAP_ENDPOINT = '{{ if exists "/deis/controller/auth/ldap/endpoint" }}{{ getv "/deis/controller/auth/ldap/endpoint"}}{{ else }} {{ end }}'
53+
BIND_DN = '{{ if exists "/deis/controller/auth/ldap/bind/dn" }}{{ getv "/deis/controller/auth/ldap/bind/dn"}}{{ else }} {{ end }}'
54+
BIND_PASSWORD = '{{ if exists "/deis/controller/auth/ldap/bind/password" }}{{ getv "/deis/controller/auth/ldap/bind/password"}}{{ else }} {{ end }}'
55+
USER_BASEDN = '{{ if exists "/deis/controller/auth/ldap/user/basedn" }}{{ getv "/deis/controller/auth/ldap/user/basedn"}}{{ else }} {{ end }}'
56+
USER_FILTER = '{{ if exists "/deis/controller/auth/ldap/user/filter" }}{{ getv "/deis/controller/auth/ldap/user/filter"}}{{ else }} {{ end }}'
57+
GROUP_BASEDN = '{{ if exists "/deis/controller/auth/ldap/group/basedn" }}{{ getv "/deis/controller/auth/ldap/group/basedn"}}{{ else }} {{ end }}'
58+
GROUP_FILTER = '{{ if exists "/deis/controller/auth/ldap/group/filter" }}{{ getv "/deis/controller/auth/ldap/group/filter"}}{{ else }} {{ end }}'
59+
GROUP_TYPE = '{{ if exists "/deis/controller/auth/ldap/group/type" }}{{ getv "/deis/controller/auth/ldap/group/type"}}{{ else }} {{ end }}'
60+
{{ end }}

docs/customizing_deis/controller_settings.rst

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,51 @@ server
105105

106106
Changes to ``/deis/controller/unitHostname`` requires either pushing a new build to
107107
every application or scaling them down and up.
108-
The change is only detected when a container unit is deployed.
108+
The change is only detected when a container unit is deployed.
109+
110+
Using a LDAP Auth
111+
-----------------
112+
Deis Controller supports Single Sign On access control, for now Deis is able to authenticate using LDAP or Active Directory.
113+
114+
Settings used by LDAP
115+
^^^^^^^^^^^^^^^^^^^^^
116+
========================================= =================================================================================
117+
setting description
118+
========================================= =================================================================================
119+
/deis/controller/auth/ldap/endpoint The full LDAP endpoint. (Ex.: ldap://ldap.company.com)
120+
/deis/controller/auth/ldap/bind/dn Full user for bind. (Ex.: user@company.com. For Anonymous bind leave blank)
121+
/deis/controller/auth/ldap/bind/password Password of the user for bind. (For anonymous bind leave blank)
122+
/deis/controller/auth/ldap/user/basedn The BASE DN where your LDAP Users are placed. (Ex.: OU=TeamX,DC=Company,DC=com)
123+
/deis/controller/auth/ldap/user/filter The field that we will match with username of Deis. (In most cases is uuid, AD uses sAMAccountName)
124+
/deis/controller/auth/ldap/group/basedn The BASE DN where the groups of your LDAP are are located. (Ex.: OU=Groups,OU=TeamX,DC=Company,DC=com)
125+
/deis/controller/auth/ldap/group/filter The field that we will locate your groups with LDAPSearch. (In most cases is objectClass)
126+
/deis/controller/auth/ldap/group/type The Groups type of LDAP. (Use groupOfNames if you don't know)
127+
========================================= =================================================================================
128+
129+
Configuring LDAP on Controller
130+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
131+
132+
.. important::
133+
134+
It's important that you register the first user of the default auth in order to have an admin ( see :ref:`Register a User <register-user>` ) without this you don't have any deis admin because LDAP users haven't this permission, you will need to set this later.
135+
After this you need to disable the registration ( see :ref:`disable_user_registration` ) avoiding that "ghost" users register and access your Deis. The auth model of controller by default allows multiple source auths so LDAP and non-LDAP users will be able to login.
136+
137+
138+
.. code-block:: console
139+
140+
$ deisctl config controller set auth/ldap/endpoint=<ldap-endpoint>
141+
$ deisctl config controller set auth/ldap/bind/dn=<bind-dn-full-user>
142+
$ deisctl config controller set auth/ldap/bind/password=<bind-dn-user-password>
143+
$ deisctl config controller set auth/ldap/user/basedn=<user-base-dn>
144+
$ deisctl config controller set auth/ldap/user/filter=<user-filter>
145+
$ deisctl config controller set auth/ldap/group/basedn=<group-base-dn>
146+
$ deisctl config controller set auth/ldap/group/filter=<group-filter>
147+
$ deisctl config controller set auth/ldap/group/type=<group-type>
148+
149+
.. note::
150+
151+
You can set a LDAP user as admin by using ``deis perms:create <LDAP User> --admin`` with the admin created before.
152+
153+
.. note::
154+
155+
LDAP support was contributed by community member Pedro Spagiari (`@phspagiari <http://github.com/phspagiari/>`_) and is unsupported by the Deis core team.

docs/docs_requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ django-cors-headers==1.0.0
1313
django-fsm==2.2.0
1414
django-guardian==1.2.5
1515
django-json-field==0.5.7
16+
django-auth-ldap==1.2.5
1617
djangorestframework==3.0.5
1718
docker-py==0.7.2
1819
gunicorn==19.3.0
1920
paramiko==1.15.2
2021
python-etcd==0.3.2
2122
PyYAML==3.11
2223
South==1.0.2
24+
python-ldap==2.4.19
2325

2426
# Deis client requirements
2527
docopt==0.6.2

docs/using_deis/register-user.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
:title: Register a new Deis user using the client
22
:description: First steps for developers using Deis to deploy and scale applications.
33

4+
.. _register-user:
45

56
Register a User
67
===============

tests/bin/setup-node.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile
3333
echo "You must reboot for the global $PATH changes to take effect."
3434

3535
# install test suite requirements
36-
apt-get install -yq curl mercurial python-dev libffi-dev libpq-dev libyaml-dev git postgresql postgresql-client
36+
apt-get install -yq curl mercurial python-dev libffi-dev libpq-dev libyaml-dev git postgresql postgresql-client libldap2-dev libsasl2-dev
3737
curl -sSL https://raw.githubusercontent.com/pypa/pip/6.0.8/contrib/get-pip.py | python -
3838
pip install virtualenv
3939

0 commit comments

Comments
 (0)