4

I have Django project that has two apps App1 and App2) each app has only 1 view. . My project connected to openldap using django-auth-ldap. I have two groups(Group1, Group2).

I Added decorators before my views in app1 and app2 (@login_required) and the result as expected that all users from group1 and group2 will be able to login to both apps.

I want to be able to just allow group1 to access app1 only and group2 access app2 only.

I tried many codes but no one work with me.

Here is my code:

app1.views.py

from django.shortcuts import render
from django.template import loader
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from django.contrib.auth import views as auth_views
@login_required(login_url='/accounts/login/')
def index(request):
    #getting our template
    template = loader.get_template('main/index.html')
    #rendering the template in HttpResponse
    return HttpResponse(template.render())

Here is my ldap settings from settings.py:

#Generated by 'django-admin startproject' using Django 1.11.


import os
import django



AUTHENTICATION_BACKENDS = ('django_auth_ldap.backend.LDAPBackend',)

import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType


AUTH_LDAP_SERVER_URI = "ldap://mydomain.com"

AUTH_LDAP_BIND_DN = "cn=admin,dc=mydomain,dc=com"

AUTH_LDAP_BIND_PASSWORD = "mypass"

AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=ou_org_unit,dc=mydomain,dc=com",
ldap.SCOPE_SUBTREE, "(uid=%(user)s)")

AUTH_LDAP_GROUP_SEARCH = LDAPSearch("ou=ou_org_unit,cn=group1,cn=group2,dc=mydomain,dc=com",
    ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)"
)

AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()

AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail"
}

AUTH_LDAP_FIND_GROUP_PERMS = True
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600
Eyla
  • 5,751
  • 20
  • 71
  • 116

2 Answers2

4

First I would map a property to the user object that specifies which group the user is in:

AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenName",
    "last_name": "sn",
    "email": "mail",
    "ldap_group": "cn"   # not 100% sure if this is what's required, just guessing
}

Then make a decorator with user_passes_test:

from django.contrib.auth.decorators import user_passes_test

def ldap_group_required(group_name):
    """
    Checks if a user is in the specified LDAP group.
    """
    return user_passes_test(
        lambda u: hasattr(u, 'ldap_group') and u.ldap_group == group_name,
        login_url='/accounts/login/'
    )

Use it on a view like so:

@ldap_group_required('group1')
def index(request):
    #getting our template
    template = loader.get_template('main/index.html')
    #rendering the template in HttpResponse
    return HttpResponse(template.render())

If you check out the source code, this is effectively how login_required works.

mindcruzer
  • 834
  • 5
  • 9
  • Thank you for your reply. I tried your code and now I am not able to login at all. I think I need a way to check the group name – Eyla Sep 20 '17 at 14:22
  • 1
    I found this: https://django-auth-ldap.readthedocs.io/en/stable/users.html#direct-attribute-access (see the bottom of the page). You could instead remove `"ldap_group": "cn"` from the attribute map, and modify the group check to something like `hasattr(u, 'ldap_user') and group_name in u.ldap_user.group_names`. You'll have to play around with it a bit but it looks like getting a list of groups the user is in is possible. – mindcruzer Sep 20 '17 at 15:12
  • I tried your solution but still I am getting no result, there is no error and I am not able to login and I tried different configuration and always getting same result – Eyla Nov 13 '17 at 21:48
3

I would personally recommend a slightly different approach to this, using Django's built-in permissions.

What you can do is create custom permissions, for example, can_access_app1 and can_access_app2. Then, since django-auth-ldap will automatically copy all of your groups into the Django database for you, you can then assign those permissions to the appropriate groups.

Now that your groups and their respective permissions are set up, you would then decorate your views appropriately. For example:

# app1/views.py
from django.contrib.auth.decorators import permission_required
from django.http import HttpResponse
from django.shortcuts import render
from django.template import loader

@permission_required('app1.can_access_app1')
def index(request):
    #getting our template
    template = loader.get_template('main/index.html')
    #rendering the template in HttpResponse
    return HttpResponse(template.render())

This approach would be well-documented, not introduce any special trickery having to manipulate your user objects, and would also have the added advantage that you can assign these permissions to individuals as well if you want to give special access. In addition, any superuser account will automatically have both permissions for no extra effort!

Joey Wilhelm
  • 5,729
  • 1
  • 28
  • 42