lucterios2 / django_auth_ldap3_ad Goto Github PK
View Code? Open in Web Editor NEWSimple LDAP/AD auth module for django
Home Page: https://pypi.python.org/pypi/django-auth-ldap3-ad
License: GNU General Public License v3.0
Simple LDAP/AD auth module for django
Home Page: https://pypi.python.org/pypi/django-auth-ldap3-ad
License: GNU General Public License v3.0
When a user logs in, all groups in the domain are fetched and each one is iterated to find if the user is a member. The LDAP query only fetched the first 1000. If a user is a member of a group that's not included in those first 1000 groups, logon will be denied.
This could be solved by adding all groups in LDAP_SUPERUSER_GROUPS, LDAP_STAFF_GROUPS and LDAP_GROUPS_MAP to LDAP_GROUPS_SEARCH_FILTER in a dynamic way. Filtering out all irrelevant groups.
Proposed solution:
Not sure how to do a pull request. I updated line 84 to be case insensitive.
uid = User.objects.filter(username__iexact=username).values_list('pk', flat=True)
usr = User.objects.get(pk=uid[0])
Hi,
After install it and configured my Django Server. Is it possible to run a verification that it works?
Thanks
Chris
I have a working AD server,
your module works and I can log into admin area of django with my administrators group member.
how can I Import all users and groups to django ?
my config
#Active Directory
LDAP_SERVERS = [
{
'host': '10.172.90.3',
'port': 389,
'use_ssl': False,
},
]
LDAP_ENGINE = "AD"
LDAP_BIND_USER = "cn=intranet,ou=EFEKTUM,dc=ad,dc=efektum,dc=pl"
LDAP_BIND_PASSWORD = ""
LDAP_SEARCH_BASE = "dc=ad,dc=efektum,dc=pl"
LDAP_USER_SEARCH_FILTER = "(&(|(userPrincipalName={0})(sAMAccountName={0}))(objectClass=user))"
DAP_USE_LDAP_GROUPS = True
LDAP_GROUPS_SEARCH_BASE = "dc=ad,dc=efektum,dc=pl"
LDAP_GROUPS_SEARCH_FILTER = "(&(objectClass=group))"
LDAP_GROUP_MEMBER_ATTRIBUTE = "member"
LDAP_SUPERUSER_GROUPS = ["CN=Administratorzy,DC=ad,DC=efektum,DC=pl", ]
LDAP_STAFF_GROUPS = ["CN=IT,OU=PROJEKTY,OU=EFEKTUM,DC=ad,DC=efektum,DC=pl", ]
LDAP_GROUPS_MAP = {
'DPD': "CN=DPD,OU=PROJEKTY,OU=EFEKTUM,DC=ad,DC=efektum,DC=pl",
}
LDAP_ATTRIBUTES_MAP = {
'username': 'sAMAccountName',
'first_name': 'givenName',
'last_name': 'sn',
'email': 'mail',
}
Hi,
I set up
LDAP_STORE_BUSINESS_UNIT = { 'CN=xxxx,DC=au': 'XXX', }
in settings.py
And I got a KeyError when I use request.session['LDAP_USER_BU']
request.session['LDAP_USER_DN']
just fine.
Cheers
for example if I have a python ldap3 that considers this a deny if found:
conn.search(search_base="DC=adomain,DC=com",
search_filter="(&(objectCategory=person)(sAMAccountName=" + connection_information['AD_Accnt'].split("\",1)[1] + ")(objectclass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=App-X-Deny,OU=Security Groups,DC= adomain,DC=com))",
search_scope=SUBTREE,
attributes = ["sAMAccountName","displayName","mail"],
size_limit=0)
how does one set that up in the settings file? it seems that would be a good addition to the doc. I easily figured out how to grant access, I am not clear on how to deny.
along that line if you look at the doc for the older https://django-auth-ldap.readthedocs.io/en/latest/
it has a specific way to state that with
AUTH_LDAP_REQUIRE_GROUP = "cn=enabled,ou=groups,dc=example,dc=com"
AUTH_LDAP_DENY_GROUP = "cn=disabled,ou=groups,dc=example,dc=com"
or
AUTH_LDAP_REQUIRE_GROUP = (
LDAPGroupQuery("cn=enabled,ou=groups,dc=example,dc=com")
| LDAPGroupQuery("cn=also_enabled,ou=groups,dc=example,dc=com")
) & ~LDAPGroupQuery("cn=disabled,ou=groups,dc=example,dc=com")
having something like this as a feature would be nice.
When Django saves the user in the DB for all attributes it is chopping all but the first character. This ultimately causes authentication to fail and when trying to login again it tries to create another user and runs into a unique constraint error.
I'm currently using Django 1.11 and Python 2.7.
I will try with some previous versions of Django to see if I get the same results. I'll also dig around/debug and see if I can find anything that pops out at me.
Is there an example configuration available?
Hi,
Any chance to consider the license to be the same of django (BSD), or Apache or MIT?
Regards,
Pedro
In auth.py, update_user does:
if isinstance(attributes[settings.LDAP_ATTRIBUTES_MAP[attr]], str):
attribute_value = attributes[settings.LDAP_ATTRIBUTES_MAP[attr]]
else:
attribute_value = attributes[settings.LDAP_ATTRIBUTES_MAP[attr]][0]
This looks like it's meant to accept either a string or a list in attributes[settings.LDAP_ATTRIBUTES_MAP[attr]].
But the "str" in there is treacherous. On python 2, that's the name of the "bytes" type, while the Unicode string type is called "unicode".
So, on python2, this code will see a string and think it's some kind of list. And because a string is indexable, it reduces the username to just the first letter!
Some possible ways of fixing this:
When creating new users, only the first character of the field gets saved in auth_users. For instance:
In LDAP when givenName=Andrew, only 'A' gets saved.
The line of code causing it is 309 in auth.py:
setattr(user, attr, attributes[settings.LDAP_ATTRIBUTES_MAP[attr]][0])
From my settings.py
LDAP_ATTRIBUTES_MAP = {
'username': 'sAMAccountName',
'first_name': 'givenName',
'last_name': 'sn',
'email': 'mail',
}
Changing line 309 to this fixes it for me
setattr(user, attr, attributes[settings.LDAP_ATTRIBUTES_MAP[attr]])
Thx,
Andy
Hi,
Thanks for the very useful library :)
I noticed that Django's last_login
attribute is not set upon authentication. Could you add this?
Thanks
kali@kali:~/AD/LDAP/ldapdomaindump$ sudo ldapdomaindump lkdaps://192.168.202.132 -u 'ADLAB\s1account' -p User1@123
/usr/local/bin/ldapdomaindump:4: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
import('pkg_resources').run_script('ldapdomaindump==0.9.4', 'ldapdomaindump')
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/ldap3/core/server.py", line 114, in init
port = int(hostport) or port
^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: '//192.168.202.132'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/bin/ldapdomaindump", line 4, in
import('pkg_resources').run_script('ldapdomaindump==0.9.4', 'ldapdomaindump')
File "/usr/lib/python3/dist-packages/pkg_resources/init.py", line 722, in run_script
self.require(requires)[0].run_script(script_name, ns)
File "/usr/lib/python3/dist-packages/pkg_resources/init.py", line 1561, in run_script
exec(code, namespace, namespace)
File "/usr/local/lib/python3.11/dist-packages/ldapdomaindump-0.9.4-py3.11.egg/EGG-INFO/scripts/ldapdomaindump", line 3, in
ldapdomaindump.main()
File "/usr/local/lib/python3.11/dist-packages/ldapdomaindump-0.9.4-py3.11.egg/ldapdomaindump/init.py", line 940, in main
s = Server(args.host, get_info=ALL)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/ldap3/core/server.py", line 118, in init
raise LDAPInvalidPortError('port must be an integer')
ldap3.core.exceptions.LDAPInvalidPortError: port must be an integer
Please modify auth.py to give the option to disable saving LDAP passwords locally or to use a dummy password. I've modified line 171 in auth.py to use a dummy password at the moment with no ill effect.
django 3.1
python 3.9.6
...lib\site-packages\ldap3\core\server.py", line 118
try:
port = int(hostport) or port
except ValueError:
if log_enabled(ERROR):
log(ERROR, 'port <%s> must be an integer', port)
raise LDAPInvalidPortError('port must be an integer')
settings:
LDAP_SERVERS = [
{
'host': 'confidential',
'port': 389, #also tried init(389), still fails
'use_ssl': False,
'get_info': 'NONE',
},
]
class Login(View):
template = 'login.html'
def get(self, request):
_form = AuthenticationForm()
return render(request, self.template, {'form': _form})
def post(self, request, *args, **kwargs):
_form = AuthenticationForm(request.POST)
_username = request.POST['username']
_password = request.POST['password']
_user = authenticate(request, username=_username, password=_password)
if _user is not None:
login(request, _user)
return HttpResponseRedirect('/')
else:
return render(request, self.template, {'form': _form})
I think I got the code working, but it can't login.
Is it possible to debug what's going on?
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
'loggers': {
'django': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': True,
},
},
}
This doesn't give my any idea what's going on.
Testing this LDAP/AD module, but after the successful login we get an error.
ProgrammingError at /login/
function upper(text[]) does not exist
LINE 1: ...user" WHERE UPPER("auth_user"."username"::text) = UPPER(ARRA...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Followed the error with the python debugger and it crashes within the authentication() method. This is because the result is a list and not the user itself.
try:
# try to retrieve user from database and update it
username_field = getattr(settings, 'LDAP_USER_MODEL_USERNAME_FIELD', 'username')
lookup_username = user_attribs[settings.LDAP_ATTRIBUTES_MAP[username_field]]
usr = user_model.objects.get(**{"{0}__iexact".format(username_field): lookup_username})
Changing lookup_username to lookup_username[0] solves the issue, but is this the solution?
Do other people encounter the same issue?
Hello. I already wrote all needed information to settings.py, but unfortunatly I do not understand what I should wright in views.py file. Can you help me and provide view file example?
I'm getting the error about a duplicate entry (Duplicate entry 'USERS.NAME' for key 'username') if I try to login after having already logged in once and populated the db with my user name. If I delete the user row from the auto_user table then it will let me log in again.
I've also noticed that none of the AD groups are being created in the django db. I'm not sure if this is expected behavior or not; I'm very new to django.
Here's my config:
LDAP_ENGINE = 'AD'
LDAP_BIND_USER = "DN FOR ACCOUNT"
LDAP_BIND_PWD = "PASSWORD"
LDAP_SEARCH_BASE = "DN FOR LOCATION"
LDAP_USER_SEARCH_FILTER = "(&(sAMAccountName=%s)(objectClass=user))"
LDAP_ATTRIBUTES_MAP = {
'username': 'sAMAccountName',
'first_name': 'givenName',
'last_name': 'sn',
'email': 'mail',
}
LDAP_STORE_USER_DN = True
LDAP_SERVERS = [
{
'host': 'IP.ADDR',
'port': 389,
'use_ssl': False,
},
{
'host': 'IP.ADDR',
'port': 389,
'use_ssl': False,
},
]
LDAP_USE_LDAP_GROUPS = True
LDAP_GROUPS_SEARCH_BASE = "DN FOR LOCATION"
LDAP_GROUPS_SEARCH_FILTER = "(&(objectClass=group))"
LDAP_GROUP_MEMBER_ATTRIBUTE = "member"
LDAP_SUPERUSER_GROUPS = ["DN FOR ACCOUNT", ]
LDAP_STAFF_GROUPS = ["DN FOR ACCOUNT", ]
LDAP_GROUPS_MAP = {
'my_admins': "DN FOR ACCOUNT",
'my_users': "DN FOR ACCOUNT",
}
Hi, I am new to django, appreicate any help in using AD authentication, thanks much!
\lib\site-packages\django_auth_ldap3_ad\auth.py in init_and_get_ldap_user, line 91
We use the newest version 1.6.33
We have an exception when logging in,
IndexError: list index out of range
, in
django_auth_ldap3_ad/auth.py in init_and_get_ldap_user at line 162
The value of user_attribs[attrib]
is []
, i.e. the empty list.
I think in that case, we'd need to set None
. The code in question has been introduced with #30
Hello,
First thanks a lot for this great module, vert usefull.
I juste face some issue that take le some Time to correct.
The LDAP search is case insensitive, and the comparison which is uses in the LDAP_GROUP_MAP is not.
So there is case where the group will be find in the LDAP and user not added in the Django group.
Maybe the comparison should uses a .lower() somewhere :
if resp['dn'].lower() == settings.LDAP_GROUPS_MAP[grp].lower()
For exemple .
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.