From eab9d7b7148870b11eb8ee44d9ef8138c511539f Mon Sep 17 00:00:00 2001
From: Aatish Neupane
Date: Sat, 3 Nov 2018 10:09:11 +0545
Subject: [PATCH] add ldap authentication and function to create ldap user on
signup
---
.env.sample | 4 ++++
README.md | 10 +++++++++-
ipv6work/settings.py | 30 +++++++++++++++++++++++++++++-
ipv6work/urls.py | 3 +++
requirements.txt | 1 +
users/__init__.py | 0
users/admin.py | 3 +++
users/apps.py | 5 +++++
users/forms.py | 19 +++++++++++++++++++
users/ldap_funcs.py | 28 ++++++++++++++++++++++++++++
users/migrations/__init__.py | 0
users/models.py | 3 +++
users/templates/users/signup.html | 21 +++++++++++++++++++++
users/tests.py | 3 +++
users/views.py | 26 ++++++++++++++++++++++++++
15 files changed, 154 insertions(+), 2 deletions(-)
create mode 100644 users/__init__.py
create mode 100644 users/admin.py
create mode 100644 users/apps.py
create mode 100644 users/forms.py
create mode 100644 users/ldap_funcs.py
create mode 100644 users/migrations/__init__.py
create mode 100644 users/models.py
create mode 100644 users/templates/users/signup.html
create mode 100644 users/tests.py
create mode 100644 users/views.py
diff --git a/.env.sample b/.env.sample
index bea17eb..8996b35 100644
--- a/.env.sample
+++ b/.env.sample
@@ -1,2 +1,6 @@
DEBUG=True
ALLOWED_HOSTS=.localhost, .ipv6.work
+AUTH_LDAP_SERVER_URI=ldap://
+AUTH_LDAP_BIND_DN=cn=admin,dc=example,dc=com
+AUTH_LDAP_BIND_PASSWORD=admin
+AUTH_LDAP_USER_DN_TEMPLATE=uid=%(user)s,ou=users,dc=example,dc=com
\ No newline at end of file
diff --git a/README.md b/README.md
index 13e097f..e3c4d00 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,13 @@
+## Notes
+
+django-auth-ldap requires `openldap-devel`
+
+
+## Deployment
+
docker build -t ipv6dotwork .
sudo docker rm -f ipv6dotwork
-sudo docker run -d -p 127.0.0.1:8001:8000 --env-file .env --name ipv6dotwork ipv6dotwork
\ No newline at end of file
+sudo docker run -d -p 127.0.0.1:8001:8000 --env-file .env --name ipv6dotwork ipv6dotwork
+
diff --git a/ipv6work/settings.py b/ipv6work/settings.py
index f5e16ca..a007bb8 100644
--- a/ipv6work/settings.py
+++ b/ipv6work/settings.py
@@ -56,6 +56,7 @@ INSTALLED_APPS += [
# Our apps
INSTALLED_APPS += [
'jobs',
+ 'users',
]
MIDDLEWARE = [
@@ -120,7 +121,7 @@ AUTH_PASSWORD_VALIDATORS = [
AUTHENTICATION_BACKENDS = (
'rules.permissions.ObjectPermissionBackend',
- 'django.contrib.auth.backends.ModelBackend',
+ 'django_auth_ldap.backend.LDAPBackend',
)
LOGIN_REDIRECT_URL = '/'
@@ -153,3 +154,30 @@ MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles/')
MEDIA_URL = '/media/'
CRISPY_TEMPLATE_PACK = 'bootstrap4'
+
+
+AUTH_LDAP_SERVER_URI = config('AUTH_LDAP_SERVER_URI')
+AUTH_LDAP_BIND_DN = config('AUTH_LDAP_BIND_DN')
+AUTH_LDAP_BIND_PASSWORD = config('AUTH_LDAP_BIND_PASSWORD')
+AUTH_LDAP_USER_DN_TEMPLATE = config('AUTH_LDAP_USER_DN_TEMPLATE')
+AUTH_LDAP_USER_ATTR_MAP = {
+ 'first_name': 'givenName',
+ 'last_name': 'sn',
+ 'email': 'mail',
+}
+AUTH_LDAP_ALWAYS_UPDATE_USER = True
+LOGGING = {
+ 'disable_existing_loggers': False,
+ 'version': 1,
+ 'handlers': {
+ 'console': {
+ 'class': 'logging.StreamHandler',
+ },
+ },
+ 'loggers': {
+ 'django_auth_ldap': {
+ 'level': 'DEBUG',
+ 'handlers': ['console'],
+ },
+ },
+}
diff --git a/ipv6work/urls.py b/ipv6work/urls.py
index 159604e..2b75576 100644
--- a/ipv6work/urls.py
+++ b/ipv6work/urls.py
@@ -18,6 +18,8 @@ from django.contrib import admin
from django.urls import path, include, re_path
from django.contrib.auth import views as auth_views
+from users.views import signup
+
urlpatterns = [
re_path(
'login/',
@@ -27,6 +29,7 @@ urlpatterns = [
'logout/',
auth_views.LogoutView.as_view(),
name='logout'),
+ path('signup/', signup),
path('admin/', admin.site.urls),
path('', include('jobs.urls'))
]
diff --git a/requirements.txt b/requirements.txt
index f130312..c4aa70f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,3 +3,4 @@ django-crispy-forms==1.7.2
git+https://github.com/yourlabs/django-autocomplete-light.git#egg=django-autocomplete-light
rules==2.0
python-decouple==3.1
+ldap3==2.5.1
diff --git a/users/__init__.py b/users/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/users/admin.py b/users/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/users/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/users/apps.py b/users/apps.py
new file mode 100644
index 0000000..4ce1fab
--- /dev/null
+++ b/users/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class UsersConfig(AppConfig):
+ name = 'users'
diff --git a/users/forms.py b/users/forms.py
new file mode 100644
index 0000000..7a4b374
--- /dev/null
+++ b/users/forms.py
@@ -0,0 +1,19 @@
+from django import forms
+from django.contrib.auth.forms import UserCreationForm
+from django.contrib.auth import get_user_model
+
+User = get_user_model()
+
+
+class SignUpForm(UserCreationForm):
+ first_name = forms.CharField(
+ max_length=30, required=False, help_text='Optional.')
+ last_name = forms.CharField(
+ max_length=30, required=False, help_text='Optional.')
+ email = forms.EmailField(
+ max_length=254, help_text='Required. Inform a valid email address.')
+
+ class Meta:
+ model = User
+ fields = ('username', 'first_name', 'last_name',
+ 'email', 'password1', 'password2', )
diff --git a/users/ldap_funcs.py b/users/ldap_funcs.py
new file mode 100644
index 0000000..7a9ea52
--- /dev/null
+++ b/users/ldap_funcs.py
@@ -0,0 +1,28 @@
+from django.conf import settings
+from ldap3 import Server, ServerPool, Connection, ObjectDef, AttrDef, Reader, Writer
+
+server = Server(settings.AUTH_LDAP_SERVER_URI)
+
+
+
+def create_user(user, password, firstname, lastname, email):
+ conn = Connection(server, settings.AUTH_LDAP_BIND_DN,
+ settings.AUTH_LDAP_BIND_PASSWORD)
+ if not conn.bind():
+ raise Exception('Could not connect to LDAP Server')
+ obj_new_user = ObjectDef(
+ ['inetOrgPerson'], conn)
+ w = Writer(conn, obj_new_user)
+ dn = 'uid=%s,ou=users,dc=example,dc=com' % user
+ w.new(dn)
+ w[0].givenName = firstname
+ w[0].sn = lastname
+ w[0].cn = firstname + " " + lastname
+ w[0].mail = email
+ w[0].userPassword = password
+
+ if not w.commit():
+ conn.unbind()
+ raise Exception("Couldn't write user")
+ conn.unbind()
+ return True
\ No newline at end of file
diff --git a/users/migrations/__init__.py b/users/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/users/models.py b/users/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/users/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/users/templates/users/signup.html b/users/templates/users/signup.html
new file mode 100644
index 0000000..0663021
--- /dev/null
+++ b/users/templates/users/signup.html
@@ -0,0 +1,21 @@
+{% extends 'base.html' %}
+
+{% block body_content %}
+Sign up
+
+ {% endfor %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/users/tests.py b/users/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/users/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/users/views.py b/users/views.py
new file mode 100644
index 0000000..9671505
--- /dev/null
+++ b/users/views.py
@@ -0,0 +1,26 @@
+from django.conf import settings
+from django.contrib.auth import login, authenticate
+from django.http import HttpResponseRedirect
+from django.shortcuts import render
+
+from .forms import SignUpForm
+from .ldap_funcs import create_user
+
+
+def signup(request):
+ if request.method == 'POST':
+ form = SignUpForm(request.POST)
+ if form.is_valid():
+ username = form.cleaned_data.get('username')
+ raw_password = form.cleaned_data.get('password1')
+ first_name = form.cleaned_data.get('first_name')
+ last_name = form.cleaned_data.get('last_name')
+ email = form.cleaned_data.get('email')
+ create_user(username, raw_password, first_name, last_name, email)
+ form.save()
+ user = authenticate(username=username, password=raw_password)
+ login(request, user, backend='django_auth_ldap.backend.LDAPBackend')
+ return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
+ else:
+ form = SignUpForm()
+ return render(request, 'users/signup.html', {'form': form})