Usage ExamplesΒΆ
Start a new django application ad_example
python manage.py startapp ad_exampleEdit /var/www/$PROJECT_NAME/$PROJECT_NAME/settings.py. Add ad_example to INSTALLED_APPS
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django_adtools', 'ad_example', ]Edit /var/www/$PROJECT_NAME/$PROJECT_NAME/settings.py. Add ADTOOLS setting
# DJANGO_ADTOOLS ADTOOLS_DOMAIN: str = 'example.com' #: name of a windows domain # set list of dns servers if your server work under Windows # ADTOOLS_NAMESERVERS: List[str] = ['127.0.0.1'] #: list of dns servers to discover ip addresses of domain controllers ADTOOLS_TEST_USERNAME: str = 'test@example.com' #: test ad username ADTOOLS_TEST_PASSWORD: str = 'somepassword' #: test ad password ADTOOLS_TEST_GROUP: str = 'test-users' #: test ad groupCreate and apply migrations
python manage.py makemigrations django_adtools python manage.py migrateConfigure discovering of a Domain Controller. For more information look at Deploying under Linux Centos 7 using Apache
sudo sed -i /etc/crontab -e "\\$a\*/30 \* \* \* \* apache /var/www/$PROJECT_NAME/venv/bin/python /var/www/$PROJECT_NAME/manage.py discover" sudo systemctl reload crond sudo -u apache /var/www/$PROJECT_NAME/venv/bin/python /var/www/$PROJECT_NAME/manage.py discoverCreate folder /var/www/$PROJECT_NAME/ad_example/templates/ad_example
mkdir /var/www/$PROJECT_NAME/ad_example/templates/ad_exampleCreate base.html template
touch /var/www/$PROJECT_NAME/ad_example/templates/ad_example/base.htmlEdit base.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> </head> <body> {% block content %} {% endblock %} </body> </html>Create index.html template
touch /var/www/$PROJECT_NAME/ad_example/templates/ad_example/index.htmlEdit index.html template
{% extends package|add:'/base.html' %} {% block title %}Hello - {{ user }}{% endblock %} {% block content %} <h1>Hello - {{ user }}</h1> <a href="{% url package|add:':logout' %}">Logout</a> {% endblock %}Create login.html template
touch /var/www/$PROJECT_NAME/ad_example/templates/ad_example/login.htmlEdit login.html template
{% extends package|add:'/base.html' %} {% block title %}Login{% endblock %} {% block content %} <h1>Login</h1> {% if login_failed %} <div>Login failed!!!</div> {% endif %} <form method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="Submit"> </form> {% endblock %}Create forms.py file
touch /var/www/$PROJECT_NAME/ad_example/forms.pyEdit forms.py
from django import forms class LoginForm(forms.Form): username = forms.CharField() password = forms.CharField(widget=forms.PasswordInput)Edit views.py
from django.shortcuts import render, redirect from django.views import View from django.urls import reverse, reverse_lazy from django.contrib.auth.mixins import LoginRequiredMixin from .forms import LoginForm from django_adtools.models import DomainController from django_adtools.ad_tools import ad_login, ad_clear_username from django.conf import settings from django.contrib.auth.models import User from django.contrib.auth import login, logout class Index(LoginRequiredMixin, View): login_url = reverse_lazy(f'{__package__}:login') redirect_field_name = None def get(self, request): context = {'package': __package__} return render(request, f"{__package__}/index.html", context) class Login(View): def get(self, request): form = LoginForm() context = {'package': __package__, 'form': form} return render(request, f"{__package__}/login.html", context) def post(self, request): form = LoginForm(request.POST) if form.is_valid(): if ad_login( dc=DomainController.get(), username=form.cleaned_data['username'], password=form.cleaned_data['password'], domain=settings.ADTOOLS_DOMAIN, group=settings.ADTOOLS_GROUP, ): # get full domain username like user@domain.ru username_without_domain = ad_clear_username(form.cleaned_data['username']) username = f"{username_without_domain}@{settings.ADTOOLS_DOMAIN}" try: # looking for existing user profile (case insensitive) user = User.objects.get(username__iexact=username) except User.DoesNotExist: # create an user profile if it does not exist user = User(username=username) user.save() login(request=request, user=user) return redirect(reverse(f'{__package__}:index')) context = {'package': __package__, 'form': form, 'login_failed': True, } return render(request, f"{__package__}/login.html", context) class Logout(View): def get(self, request): logout(request) return redirect(reverse(f'{__package__}:login'))Create urls.py file
touch /var/www/$PROJECT_NAME/ad_example/urls.pyEdit /var/www/$PROJECT_NAME/ad_example/urls.py
from .views import * from django.urls import path app_name = __package__ urlpatterns = [ path('', Index.as_view(), name='index'), path('login/', Login.as_view(), name='login'), path('logout/', Logout.as_view(), name='logout'), ]Edit /var/www/$PROJECT_NAME/$PROJECT_NAME/urls.py
from django.contrib import admin from django.urls import path from django.urls import include # add this urlpatterns = [ path('admin/', admin.site.urls), path('', include('ad_example.urls')), # add this ]Run your project
python manage.py runserverOpen http://localhost:8000 in your browser, then try to login using an Active Directory username and password.
Also, you can create tests.
touch /var/www/$PROJECT_NAME/ad_example/tests.pyEdit tests.py
from django.test import TestCase from django.test.client import Client from django.shortcuts import reverse from bs4 import BeautifulSoup from django.conf import settings from django_adtools.discover_dc import DCList from django_adtools.models import DomainController # Create your tests here. class TestExample(TestCase): def test_ad_example(self): # reading 'username' and 'password' for the test user from config username = getattr(settings, 'ADTOOLS_TEST_USERNAME', None) self.assertIsNotNone(username) password = getattr(settings, 'ADTOOLS_TEST_PASSWORD', None) self.assertIsNotNone(password) # set an ip address of a Domain Controller dc = DCList( domain=settings.ADTOOLS_DOMAIN, name_servers=getattr(settings, 'ADTOOLS_NAMESERVERS', None), ).get_available_dc_ip() self.assertIsNotNone(dc) self.assertIsNot(dc, '') DomainController.set(dc) # get login page address client = Client(enforce_csrf_checks=True) # creating the client with csrf_checks are enabled response = client.get(reverse(f'{__package__}:index')) self.assertIsNotNone(response) self.assertEqual(response.status_code, 302) login_url = response.url # get csrf token response = client.get(login_url) self.assertIsNotNone(response) self.assertEqual(response.status_code, 200) soup = BeautifulSoup(response.content.decode(), 'html.parser') csrf_element = soup.select_one("form[method='post'] input[name='csrfmiddlewaretoken']") self.assertIsNotNone(csrf_element) csrf_value = csrf_element.attrs['value'] # try to login response = client.post(reverse(f'{__package__}:login'), data={ 'csrfmiddlewaretoken': csrf_value, 'username': username, 'password': password, }) # check that the response is a redirect (302) to the index page (login success) self.assertIsNotNone(response) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, reverse(f"{__package__}:index"))