Skip to content

Commit

Permalink
Merge pull request tildaslash#334 from rayvenshire/master
Browse files Browse the repository at this point in the history
LDAP User Auth with Local Groups
  • Loading branch information
Zemmiph0bia committed Apr 19, 2015
2 parents 8be41f0 + 70db9ff commit e77c90b
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 34 deletions.
7 changes: 6 additions & 1 deletion docs/example_config.ini
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,16 @@ password = s3cr3t
[ldap]
allowpasschange = false
server = ldap://localhost/
domain = domain.local
binddn =
bindpass =
usersearch = ou=users,dc=example,dc=com
groupsearch = ou=groups,dc=example,dc=com
grouptype = GroupOfNames
staffgroup = cn=staff,ou=groups,dc=example,dc=com
staff = cn=staff,ou=groups,dc=example,dc=com
requirecert = true
referrals = false
useldapgroups = true
useremail = mail
userfirstname = givenName
userlastname = sn
1 change: 1 addition & 0 deletions ratticweb/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def base_template_reqs(request):
'pageurl': request.path,
'LDAP_ENABLED': settings.LDAP_ENABLED,
'GOAUTH2_ENABLED': settings.GOAUTH2_ENABLED,
'USE_LDAP_GROUPS': settings.USE_LDAP_GROUPS,
'EXPORT_ENABLED': not settings.RATTIC_DISABLE_EXPORT,
'TEMPLATE_DEBUG': settings.TEMPLATE_DEBUG,
'ALLOWPWCHANGE': not (settings.LDAP_ENABLED
Expand Down
70 changes: 49 additions & 21 deletions ratticweb/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def confgetbool(section, var, default):
except NoOptionError:
return default


ADMINS = (
# ('Your Name', '[email protected]'),
)
Expand Down Expand Up @@ -242,15 +243,13 @@ def confgetbool(section, var, default):
CRED_ICON_DEFAULT = 'Key.png'

# django-auth-ldap
AUTH_LDAP_USER_ATTR_MAP = {"email": "mail", }
AUTH_LDAP_USER_FLAGS_BY_GROUP = {}
AUTH_LDAP_MIRROR_GROUPS=True

# celery
BROKER_URL = 'django://'
CELERY_TASK_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_RESULT_BACKEND='djcelery.backends.database:DatabaseBackend'
CELERY_RESULT_BACKEND = 'djcelery.backends.database:DatabaseBackend'

###############################
# External environment config #
Expand Down Expand Up @@ -323,41 +322,70 @@ def confgetbool(section, var, default):
LDAP_ENABLED = 'ldap' in config.sections()

if LDAP_ENABLED:
# Add LDAP to the auth modules
AUTHENTICATION_BACKENDS = (
'django_auth_ldap.backend.LDAPBackend',
'django.contrib.auth.backends.ModelBackend',
)

# Setup the LDAP Logging
LOGGING['loggers']['django_auth_ldap']['level'] = confget('ldap', 'loglevel', 'WARNING')

# Get config options for LDAP
AUTH_LDAP_SERVER_URI = config.get('ldap', 'uri')
# Needed if anonymous queries are not allowed
AUTH_LDAP_BIND_DN = confget('ldap', 'binddn', '')

AUTH_LDAP_BIND_PASSWORD = confget('ldap', 'bindpw', '')

if config.has_option('ldap', 'staff'):
AUTH_LDAP_USER_FLAGS_BY_GROUP['is_staff'] = config.get('ldap', 'staff')
# User attributes
AUTH_LDAP_USER_ATTR_MAP = {"email": "mail"}
if config.has_option('ldap', 'userfirstname'):
AUTH_LDAP_USER_ATTR_MAP["first_name"] = config.get('ldap', 'userfirstname')
if config.has_option('ldap', 'userfirstname'):
AUTH_LDAP_USER_ATTR_MAP["last_name"] = config.get('ldap', 'userlastname')

# Are we using LDAP groups or local groups? Default to using LDAP groups
USE_LDAP_GROUPS = confgetbool('ldap', 'useldapgroups', True)

# If we are not using LDAP groups, then do not update the user model's group membership
AUTH_LDAP_MIRROR_GROUPS = USE_LDAP_GROUPS

AUTH_LDAP_SERVER_URI = config.get('ldap', 'uri')

AUTH_LDAP_USER_BASE = config.get('ldap', 'userbase')

# Defaults to AUTH_LDAP_USER_BASE because it must be defined
AUTH_LDAP_GROUP_BASE = confget('ldap', 'groupbase', AUTH_LDAP_USER_BASE)

# Searching for things
AUTH_LDAP_USER_SEARCH = LDAPSearch(config.get('ldap', 'userbase'), ldap.SCOPE_SUBTREE, config.get('ldap', 'userfilter'))
AUTH_LDAP_USER_FILTER = config.get('ldap', 'userfilter')

# Groups lookup and mirroring
if config.has_option('ldap', 'groupfilter'):
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(config.get('ldap', 'groupbase'), ldap.SCOPE_SUBTREE, config.get('ldap', 'groupfilter'))
AUTH_LDAP_GROUP_TYPE = getattr(__import__('django_auth_ldap').config, config.get('ldap', 'grouptype'))()
else:
AUTH_LDAP_MIRROR_GROUPS = False
# Defaults to a bogus filter so that searching yields no errors in the log
AUTH_LDAP_GROUP_FILTER = confget('ldap', 'groupfilter', '(objectClass=_fake)')

AUTH_LDAP_USER_SEARCH = LDAPSearch(AUTH_LDAP_USER_BASE, ldap.SCOPE_SUBTREE,
AUTH_LDAP_USER_FILTER)

AUTH_LDAP_GROUP_SEARCH = LDAPSearch(AUTH_LDAP_GROUP_BASE, ldap.SCOPE_SUBTREE,
AUTH_LDAP_GROUP_FILTER)

# Defaults to PosixGroupType because it must match a pre-defined list of selections
AUTH_LDAP_GROUP_TYPE = getattr(__import__('django_auth_ldap').config, confget('ldap', 'grouptype', 'PosixGroupType'))()

# Booleans
AUTH_LDAP_ALLOW_PASSWORD_CHANGE = confgetbool('ldap', 'pwchange', False)

AUTH_LDAP_START_TLS = confgetbool('ldap', 'starttls', False)

AUTH_LDAP_GLOBAL_OPTIONS = {
ldap.OPT_X_TLS_REQUIRE_CERT: confgetbool('ldap', 'requirecert', True),
ldap.OPT_REFERRALS: confgetbool('ldap', 'referrals', False),
}

# Determines which LDAP users are staff, if not defined, privilege can be set manually
if config.has_option('ldap', 'staff'):
AUTH_LDAP_USER_FLAGS_BY_GROUP['is_staff'] = confget('ldap', 'staff', '')

AUTHENTICATION_BACKENDS = (
'django_auth_ldap.backend.LDAPBackend',
'django.contrib.auth.backends.ModelBackend',
)
else:
# No LDAP section means no LDAP groups
USE_LDAP_GROUPS = False

# [goauth2]
GOAUTH2_ENABLED = 'goauth2' in config.sections()

Expand Down
2 changes: 1 addition & 1 deletion ratticweb/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="rattic_url_root" content="{% url_root %}" />
{% if user.is_staff and not LDAP_ENABLED %}
{% if user.is_staff and USE_LDAP_GROUPS %}
<meta name="rattic_user_staff" content="true" />
{% else %}
<meta name="rattic_user_staff" content="false" />
Expand Down
2 changes: 1 addition & 1 deletion staff/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def read_detail(self, object_list, bundle):
return True

def create_list(self, object_list, bundle):
if settings.LDAP_ENABLED:
if settings.USE_LDAP_GROUPS:
raise Unauthorized("Please create groups in your LDAP server")

if bundle.request.user.is_staff:
Expand Down
2 changes: 1 addition & 1 deletion staff/templates/staff_groupdetail.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ <h1>{% trans "Delete Group" %}: {{ group.name }}</h1>
<div class="alert alert-error">{% blocktrans %}Deleting this group will delete every password underneath it.{% endblocktrans %}</div>
{% else %}
<h1>{% trans "Group" %} {{ group.name }}</h1>
{% if not LDAP_ENABLED %}
{% if not USE_LDAP_GROUPS %}
<div class="btn-group">
<a class="btn" href="{% url "staff.views.groupedit" group.id %}">{% trans "Edit" %}</a>
<a class="btn btn-danger" href="{% url "staff.views.groupdelete" group.id %}">{% trans "Delete" %}</a>
Expand Down
7 changes: 5 additions & 2 deletions staff/templates/staff_home.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ <h1>{% trans "Staff Manage" %}</h1>
<div class="btn-group">
{% if not LDAP_ENABLED %}
<a class="btn" href="{% url "user_add" %}">{% trans "Add User" %}</a>
{% endif %}

{% if not USE_LDAP_GROUPS %}
<a class="btn" href="{% url "staff.views.groupadd" %}">{% trans "Add Group" %}</a>
{% endif %}
<a class="btn" href="{% url "staff.views.upload_keepass" %}">{% trans "Import Keepass" %}</a>
Expand Down Expand Up @@ -41,11 +44,11 @@ <h2>{% trans "Users" %}</h2>

<h2>{% trans "Access Groups" %}</h2>
<table class="table table-striped table-bordered table-condensed">
<tr><th>{% trans "Name" %}</th>{% if not LDAP_ENABLED %}<th>{% trans "Edit" %}</th><th>{% trans "Delete" %}</th>{% endif %}</tr>
<tr><th>{% trans "Name" %}</th>{% if not USE_LDAP_GROUPS %}<th>{% trans "Edit" %}</th><th>{% trans "Delete" %}</th>{% endif %}</tr>
{% for g in grouplist %}
<tr>
<td><a href="{% url "staff.views.groupdetail" g.id %}">{{ g.name }}</a></td>
{% if not LDAP_ENABLED %}
{% if not USE_LDAP_GROUPS %}
<td><a href="{% url "staff.views.groupedit" g.id %}">{% trans "Edit" %}</a></td>
<td><a href="{% url "staff.views.groupdelete" g.id %}">{% trans "Delete" %}</a></td>
{% endif %}
Expand Down
2 changes: 1 addition & 1 deletion staff/templates/staff_keepassimport.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% load i18n %}

{% block headarea %}
{% if user.is_staff and not LDAP_ENABLED %}
{% if user.is_staff and not USE_LDAP_GROUPS %}
<meta name="rattic_attach_new_group_buttons" content="true" />
{% else %}
<meta name="rattic_attach_new_group_buttons" content="false" />
Expand Down
2 changes: 1 addition & 1 deletion staff/templates/staff_userdetail.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</div>
{% endif %}
<h1>{% trans "User" %}: {{ viewuser.username }}</h1>
{% if not LDAP_ENABLED %}
{% if not LDAP_ENABLED or not USE_LDAP_GROUPS %}
<div class="btn-group">
{% if delete %}
<form action="{% url "staff.views.userdelete" viewuser.id %}" method="post">{% csrf_token %}
Expand Down
13 changes: 9 additions & 4 deletions staff/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,21 @@
url(r'^credundelete/(?P<cred_id>\d+)/$', 'credundelete'),
)

# URLs that we don't want with LDAP
if not settings.LDAP_ENABLED:
# URLs we remove if using LDAP groups
if not settings.USE_LDAP_GROUPS:
urlpatterns += patterns('staff.views',
# Group Management
url(r'^groupadd/$', 'groupadd'),
url(r'^groupedit/(?P<gid>\d+)/$', 'groupedit'),
url(r'^groupdelete/(?P<gid>\d+)/$', 'groupdelete'),
url(r'^useredit/(?P<pk>\d+)/$', UpdateUser.as_view(), name="user_edit"),
url(r'^userdelete/(?P<uid>\d+)/$', 'userdelete'),
)

# User add is disabled only when LDAP config exists
if not settings.LDAP_ENABLED:
urlpatterns += patterns('staff.views',
# User Management
url(r'^useradd/$', NewUser.as_view(), name="user_add"),
url(r'^useredit/(?P<pk>\d+)/$', UpdateUser.as_view(), name="user_edit"),
url(r'^userdelete/(?P<uid>\d+)/$', 'userdelete'),

)
2 changes: 1 addition & 1 deletion staff/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def home(request):
@rattic_staff_required
def userdetail(request, uid):
user = get_object_or_404(User, pk=uid)
if settings.LDAP_ENABLED:
if settings.LDAP_ENABLED and settings.USE_LDAP_GROUPS:
from django_auth_ldap.backend import LDAPBackend
popuser = LDAPBackend().populate_user(user.username)
if popuser is None:
Expand Down

0 comments on commit e77c90b

Please sign in to comment.