diff --git a/README b/README index 2246116..aa7b084 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ # Installation - apt-get install libldap2-dev python-dev libmysqlclient-dev libsasl2-dev libldap2-dev libssl-dev + apt-get install libldap2-dev python-dev libmysqlclient-dev libsasl2-dev libldap2-dev libssl-dev ldap-utils virtualenv venv . venv/bin/activate pip install -r requirements.txt @@ -10,9 +10,11 @@ python manage.py syncdb --database=radius python manage.py runserver -# Apache: - - Make a Vhost - - add WSGIScriptAlias / /path/to/project/neuf-userinfo/userinfosite/wsgi.py +## LDAP + sudo docker run -e LDAP_DOMAIN=neuf.no -e LDAP_ORGANISATION="Neuf" -e LDAP_ROOTPASS="toor" -p 389:389 -d osixia/openldap + ldapadd -D "cn=admin,dc=neuf,dc=no" -w "toor" -f testdata.ldif + # Verify import + ldapsearch -x -b dc=neuf,dc=no # External dependencies: - LDAP: Read the tutorial on [Howto setup a LDAP server with Docker](https://edb.neuf.no/wiki/index.php?title=Howto_setup_a_LDAP_server_with_Docker) diff --git a/main/backends.py b/main/backends.py new file mode 100644 index 0000000..860e1cd --- /dev/null +++ b/main/backends.py @@ -0,0 +1,30 @@ +from django_auth_ldap.backend import LDAPBackend, _LDAPUser + + +class LDAPUsernameBackend(LDAPBackend): + settings_prefix = "AUTH_LDAP_U_" + + +class LDAPEmailBackend(LDAPBackend): + settings_prefix = "AUTH_LDAP_E_" + + def get_or_create_user(self, email, ldap_user): + """ + Use the PosixUser uid field as username instead of email. + + This must return a (User, created) 2-tuple for the given LDAP user. + username is the Django-friendly username of the user. ldap_user.dn is + the user's DN and ldap_user.attrs contains all of their LDAP attributes. + """ + model = self.get_user_model() + username_field = getattr(model, 'USERNAME_FIELD', 'username') + + kwargs = { + username_field + '__iexact': ldap_user.attrs['uid'][0], + 'defaults': { + username_field: ldap_user.attrs['uid'][0].lower(), + 'email': email + } + } + + return model.objects.get_or_create(**kwargs) \ No newline at end of file diff --git a/test/testdata.ldif b/test/testdata.ldif new file mode 100644 index 0000000..472a6ee --- /dev/null +++ b/test/testdata.ldif @@ -0,0 +1,63 @@ +# Root dn for all user accounts +dn: ou=People,dc=neuf,dc=no +objectClass: top +objectClass: organizationalUnit +ou: People + +# Account test with password "test" +dn: uid=test,ou=People,dc=neuf,dc=no +objectClass: inetOrgPerson +objectClass: posixAccount +objectClass: shadowAccount +uid: testesen +gecos: testesen +loginShell: /bin/bash +shadowExpire: -1 +shadowFlag: 0 +shadowWarning: 7 +shadowMin: 8 +shadowMax: 999999 +homeDirectory: /home/test +uidNumber: 1002 +gidNumber: 10005 +displayName: Test Testesen +cn: Test Testesen +sn: Testesen +givenName: Test +mail: test@example.com +userPassword: {SSHA}I3aQhofsUZi+TfWdOPhkr70GJ2FwuSv4 + +# Root dn for all groups +dn: ou=Groups,dc=neuf,dc=no +objectClass: top +objectClass: organizationalUnit +ou: Groups + +# Private group +dn: cn=test,ou=Groups,dc=neuf,dc=no +objectClass: posixGroup +cn: test +gidNumber: 10005 +description: Group account + +# Sample groups (matches settings-sample.py) +dn: cn=dns-alle,ou=Groups,dc=neuf,dc=no +objectClass: posixGroup +cn: dns-alle +gidNumber: 1 +description: Group account +memberUid: test + +dn: cn=edb,ou=Groups,dc=neuf,dc=no +objectClass: posixGroup +cn: edb +gidNumber: 2 +description: Group account +memberUid: test + +dn: cn=edbadmin,ou=Groups,dc=neuf,dc=no +objectClass: posixGroup +cn: edbadmin +gidNumber: 3 +description: Group account +memberUid: test diff --git a/userinfosite/settings-sample.py b/userinfosite/settings-sample.py index c4a60c6..72f201a 100644 --- a/userinfosite/settings-sample.py +++ b/userinfosite/settings-sample.py @@ -131,7 +131,8 @@ EMAIL_PORT = 25 DEFAULT_FROM_EMAIL = 'noreply@neuf.no' AUTHENTICATION_BACKENDS = ( - 'django_auth_ldap.backend.LDAPBackend', + 'main.backends.LDAPEmailBackend', + 'main.backends.LDAPUsernameBackend', 'django.contrib.auth.backends.ModelBackend', ) # No cleaningladies. @@ -139,46 +140,58 @@ SESSION_EXPIRE_AT_BROWSER_CLOSE = True SESSION_COOKIE_AGE = 60 * 15 # in seconds # LDAP server URI and BIND_DN, same as db-settings -AUTH_LDAP_SERVER_URI = DATABASES['ldap']['NAME'] -AUTH_LDAP_BIND_DN = DATABASES['ldap']['USER'] -AUTH_LDAP_BIND_PASSWORD = DATABASES['ldap']['PASSWORD'] +AUTH_LDAP_U_SERVER_URI = DATABASES['ldap']['NAME'] +AUTH_LDAP_U_BIND_DN = DATABASES['ldap']['USER'] +AUTH_LDAP_U_BIND_PASSWORD = DATABASES['ldap']['PASSWORD'] import ldap from django_auth_ldap.config import LDAPSearch, PosixGroupType # Basic user auth -AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=People,dc=neuf,dc=no", - ldap.SCOPE_ONELEVEL, "(uid=%(user)s)") -AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=People,dc=neuf,dc=no" +AUTH_LDAP_U_USER_SEARCH = LDAPSearch("ou=People,dc=neuf,dc=no", ldap.SCOPE_ONELEVEL, "(uid=%(user)s)") # Basic groups -AUTH_LDAP_GROUP_SEARCH = LDAPSearch("ou=Groups,dc=neuf,dc=no", - ldap.SCOPE_ONELEVEL, "(objectClass=posixGroup)" -) -AUTH_LDAP_GROUP_TYPE = PosixGroupType() +AUTH_LDAP_U_GROUP_SEARCH = LDAPSearch("ou=Groups,dc=neuf,dc=no", ldap.SCOPE_ONELEVEL, "(objectClass=posixGroup)") +AUTH_LDAP_U_GROUP_TYPE = PosixGroupType() # Mirror groups on each auth -AUTH_LDAP_MIRROR_GROUPS = True +AUTH_LDAP_U_MIRROR_GROUPS = True # Group to user flag mappings -AUTH_LDAP_USER_FLAGS_BY_GROUP = { +AUTH_LDAP_U_USER_FLAGS_BY_GROUP = { "is_active": "cn=dns-alle,ou=Groups,dc=neuf,dc=no", "is_staff": "cn=edb,ou=Groups,dc=neuf,dc=no", "is_superuser": "cn=edbadmin,ou=Groups,dc=neuf,dc=no" } # Group to profile flag mappings, not used. -AUTH_LDAP_PROFILE_FLAGS_BY_GROUP = { +AUTH_LDAP_U_PROFILE_FLAGS_BY_GROUP = { #"is_edb": "cn=edb,ou=Groups,dc=neuf,dc=no" } # User attribute mappings -AUTH_LDAP_USER_ATTR_MAP = { +AUTH_LDAP_U_USER_ATTR_MAP = { "first_name": "givenName", "last_name": "sn", "email": "mail", } # User profile attribute mappings -AUTH_LDAP_PROFILE_ATTR_MAP = { +AUTH_LDAP_U_PROFILE_ATTR_MAP = { "home_directory": "homeDirectory" } # Allways update the django user object on authentication. -AUTH_LDAP_ALWAYS_UPDATE_USER = True +AUTH_LDAP_U_ALWAYS_UPDATE_USER = True + +# Email LDAP auth +AUTH_LDAP_E_SERVER_URI = AUTH_LDAP_U_SERVER_URI +AUTH_LDAP_E_BIND_DN = AUTH_LDAP_U_BIND_DN +AUTH_LDAP_E_BIND_PASSWORD = AUTH_LDAP_U_BIND_PASSWORD + +AUTH_LDAP_E_USER_SEARCH = LDAPSearch("ou=People,dc=neuf,dc=no", ldap.SCOPE_ONELEVEL, "(mail=%(user)s)") + +AUTH_LDAP_E_GROUP_SEARCH = AUTH_LDAP_U_GROUP_SEARCH +AUTH_LDAP_E_GROUP_TYPE = AUTH_LDAP_U_GROUP_TYPE +AUTH_LDAP_E_MIRROR_GROUPS = AUTH_LDAP_U_MIRROR_GROUPS +AUTH_LDAP_E_USER_FLAGS_BY_GROUP = AUTH_LDAP_U_USER_FLAGS_BY_GROUP +AUTH_LDAP_E_PROFILE_FLAGS_BY_GROUP = AUTH_LDAP_U_PROFILE_FLAGS_BY_GROUP +AUTH_LDAP_E_USER_ATTR_MAP = AUTH_LDAP_U_USER_ATTR_MAP +AUTH_LDAP_E_PROFILE_ATTR_MAP = AUTH_LDAP_U_PROFILE_ATTR_MAP +AUTH_LDAP_E_ALWAYS_UPDATE_USER = AUTH_LDAP_U_ALWAYS_UPDATE_USER # Debug logging import logging