diff --git a/account_manager/forms.py b/account_manager/forms.py index 8de90da..14454e0 100644 --- a/account_manager/forms.py +++ b/account_manager/forms.py @@ -4,9 +4,6 @@ from .models import LdapUser, LdapGroup class AddLDAPUserForm(forms.Form): username = forms.CharField(label='Nutzername', max_length=400) - first_name = forms.CharField(label='Vorname', max_length=400) - last_name = forms.CharField(label='Nachname', max_length=400) - password = forms.CharField(label='Passwort', widget=forms.PasswordInput, required=False) email = forms.EmailField(label='E-Mail', required=False) diff --git a/account_manager/main_views.py b/account_manager/main_views.py index f51cfda..c5c470d 100644 --- a/account_manager/main_views.py +++ b/account_manager/main_views.py @@ -27,7 +27,7 @@ def realm_list(request): realms = Realm.objects.filter(admin_group__user__username__contains=user.username) if len(realms) == 0: user = LdapUser.objects.get(username=user.username) - realm_base_dn = re.compile('(uid=[a-zA-Z_]*),(ou=[a-zA-Z_]*),(.*)').match(user.dn).group(3) + realm_base_dn = re.compile('(uid=[a-zA-Z0-9_]*),(ou=[a-zA-Z_]*),(.*)').match(user.dn).group(3) realm = Realm.objects.get(ldap_base_dn=realm_base_dn) return redirect('realm-user-detail', realm.id, user.dn) elif len(realms) == 1: diff --git a/account_manager/models.py b/account_manager/models.py index 4343634..68eeb26 100644 --- a/account_manager/models.py +++ b/account_manager/models.py @@ -1,7 +1,17 @@ # Create your models here. -from django.db import models from ldapdb.models import fields as ldap_fields from ldapdb.models.base import Model +from django.dispatch import receiver +from django.db.models.signals import post_save, pre_save + +from django.utils.encoding import force_bytes +from django.utils.http import urlsafe_base64_encode +from django.template.loader import render_to_string +from core.tokens import account_activation_token +from django.core.mail import EmailMessage +from django.contrib.auth.models import User +from django.contrib.auth.tokens import default_token_generator +import re class LdapUser(Model): @@ -30,6 +40,35 @@ class LdapUser(Model): def __unicode__(self): return self.full_name + @staticmethod + def create_with_django_user_creation_and_welcome_mail(protocol, domain, username, email): + # current_site = get_current_site(request) + ldap_user = LdapUser.objects.create(username=username, email=email, first_name=" ", last_name=" ") + user, _ = User.objects.get_or_create(username=username, email=email) + # user.save() + mail_subject = 'Activate your blog account.' + message = render_to_string('registration/welcome_email.jinja2', { + 'user': user, + 'domain': domain, + 'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(), + 'token': default_token_generator.make_token(user=user), + 'protocol': protocol, + 'email': email + }) + email = EmailMessage( + mail_subject, message, to=[user.email] + ) + email.send() + return ldap_user + + @staticmethod + def password_reset(user, raw_password): + LdapUser.base_dn = LdapUser.ROOT_DN + ldap_user = LdapUser.objects.get(username=user.username) + ldap_user.password = raw_password + LdapUser.base_dn = re.compile('(uid=[a-zA-Z0-9_]*),(.*)').match(ldap_user.dn).group(2) + ldap_user.save() + class LdapGroup(Model): """ diff --git a/account_manager/urls.py b/account_manager/urls.py index 3acb570..7a55b72 100644 --- a/account_manager/urls.py +++ b/account_manager/urls.py @@ -1,4 +1,4 @@ -from django.urls import path +from django.urls import path, re_path import account_manager.views.group_views import account_manager.views.user_views @@ -36,6 +36,8 @@ urlpatterns = [ name='user-update'), path('user//delete/realm//', account_manager.views.user_views.user_delete, name='user-delete'), + path('reset///', account_manager.views.user_views.LdapPasswordResetConfirmView.as_view(), + name='ldap_password_reset_confirm'), # Extra path('permission-denied/', main_views.permission_denied, name='permission-denied'), diff --git a/account_manager/views/user_views.py b/account_manager/views/user_views.py index cd53b34..8ea192e 100644 --- a/account_manager/views/user_views.py +++ b/account_manager/views/user_views.py @@ -6,7 +6,11 @@ from account_manager.forms import AddLDAPUserForm from account_manager.models import LdapUser, LdapGroup from django.contrib.auth.models import User from account_manager.main_views import is_realm_admin -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import ObjectDoesNotExist, ValidationError +from django.utils.http import urlsafe_base64_decode +from django.contrib.auth.views import PasswordResetConfirmView +from django.contrib.sites.shortcuts import get_current_site +from django.contrib.auth import login @login_required @@ -42,14 +46,14 @@ def user_add(request, realm_id): # check whether it's valid: if form.is_valid(): username = form.cleaned_data['username'] - password = form.cleaned_data['password'] - first_name = form.cleaned_data['first_name'] - last_name = form.cleaned_data['last_name'] email = form.cleaned_data['email'] + current_site = get_current_site(request) + protocol = 'http' + if request.is_secure(): + protocol = 'https' LdapUser.base_dn = f'ou=people,{realm_obj.ldap_base_dn}' - LdapUser.objects.create(username=username, - password=password, first_name=first_name, - last_name=last_name, email=email) + LdapUser.create_with_django_user_creation_and_welcome_mail(protocol=protocol, domain=current_site.domain, + username=username, email=email) return redirect('realm-user-list', realm_id) # if a GET (or any other method) we'll create a blank form @@ -140,3 +144,13 @@ def user_delete_controller(request, ldap_user, realm_id, redirect_name): except ObjectDoesNotExist: pass return redirect(redirect_name, realm_id) + + +class LdapPasswordResetConfirmView(PasswordResetConfirmView): + + def form_valid(self, form): + user = form.save() + password = form.cleaned_data['new_password1'] + print(password) + LdapUser.password_reset(user, password) + return super().form_valid(form) diff --git a/core/settings.py b/core/settings.py index 19c4126..69fb8b3 100644 --- a/core/settings.py +++ b/core/settings.py @@ -31,6 +31,7 @@ ALLOWED_HOSTS = [] # Application definition LOGIN_URL = 'login' LOGIN_REDIRECT_URL = 'realm-home' +PASSWORD_RESET_TIMEOUT_DAYS = 3 INSTALLED_APPS = [ 'django.contrib.admin', @@ -41,6 +42,9 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'account_manager', 'account_helper', + 'rest_framework', + 'rest_framework.authtoken', + 'djoser', ] MIDDLEWARE = [ @@ -149,16 +153,16 @@ AUTHENTICATION_BACKENDS = [ AUTH_LDAP_1_SERVER_URI = "ldap://localhost:1389" AUTH_LDAP_1_USER_DN_TEMPLATE = "uid=%(user)s,ou=people,ou=fs_wiai,ou=fachschaften,dc=stuve,dc=de" AUTH_LDAP_1_GROUP_SEARCH = LDAPSearch("dc=stuve,dc=de", - ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)" - ) + ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)" + ) AUTH_LDAP_1_GROUP_TYPE = GroupOfNamesType(name_attr='cn') AUTH_LDAP_1_MIRROR_GROUPS = True AUTH_LDAP_2_SERVER_URI = "ldap://localhost:1389" AUTH_LDAP_2_USER_DN_TEMPLATE = "uid=%(user)s,ou=people,ou=fs_sowi,ou=fachschaften,dc=stuve,dc=de" AUTH_LDAP_2_GROUP_SEARCH = LDAPSearch("dc=stuve,dc=de", - ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)" - ) + ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)" + ) AUTH_LDAP_2_GROUP_TYPE = GroupOfNamesType(name_attr='cn') AUTH_LDAP_2_MIRROR_GROUPS = True @@ -168,3 +172,14 @@ AUTH_LDAP_USER_ATTR_MAP = { 'email': 'mail', } AUTH_PROFILE_MODULE = 'account_manager.UserProfile' + +######################################################################################################################## +# EMAIL Config # +######################################################################################################################## +EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' +EMAIL_FILE_PATH = os.path.join(BASE_DIR, "sent_emails") +# EMAIL_HOST = 'smtp.gmail.com' +# EMAIL_PORT = 587 +# EMAIL_HOST_USER = 'info.mgserver3@gmail.com' +# EMAIL_HOST_PASSWORD = 'HaUTQh;tw6Z3"gZNK.UY' +# EMAIL_USE_TLS = True diff --git a/core/tokens.py b/core/tokens.py new file mode 100644 index 0000000..d1501a6 --- /dev/null +++ b/core/tokens.py @@ -0,0 +1,13 @@ +from django.contrib.auth.tokens import PasswordResetTokenGenerator +from django.utils import six + + +class TokenGenerator(PasswordResetTokenGenerator): + def _make_hash_value(self, user, timestamp): + return ( + six.text_type(user.pk) + six.text_type(timestamp) + + six.text_type(user.is_active) + ) + + +account_activation_token = TokenGenerator() diff --git a/core/urls.py b/core/urls.py index 8bff7be..090b7d0 100644 --- a/core/urls.py +++ b/core/urls.py @@ -15,10 +15,9 @@ Including another URLconf """ from django.contrib import admin from django.urls import path, include -from django.contrib.auth import views as auth_views urlpatterns = [ path('', include('account_manager.urls')), path('admin/', admin.site.urls), - path('account/', include('django.contrib.auth.urls')), + path('accounts/', include('django.contrib.auth.urls')), ] diff --git a/templates/base.jinja2 b/templates/base.jinja2 index d0997e7..c7fccb5 100644 --- a/templates/base.jinja2 +++ b/templates/base.jinja2 @@ -14,15 +14,15 @@ {% block js_extra %}{% endblock %} - - - - - - - - - +{# #} +{# #} +{# #} +{# #} +{# #} +{# #} +{# #} +{# #} +{# #} {# #} @@ -32,16 +32,19 @@ {# ===== Body ===== #} {% if request.user.is_authenticated %} - Login as {{ request.user.username }} - Logout + Hi {{ request.user.username }}! +

Logout

+

Passwort zurücksetzen

{% else %} +

Du bist nicht eingelogt

Login {% endif %} {% block body %}
-
{% block bottom_nav %}{% endblock %}
-
- {% block content %}{% endblock %} +
{% block bottom_nav %}{% endblock %}
+
+ {% block content %}{% endblock %} +
{% endblock %} diff --git a/templates/registration/password_reset_email.html b/templates/registration/password_reset_email.html new file mode 100644 index 0000000..3c7d99d --- /dev/null +++ b/templates/registration/password_reset_email.html @@ -0,0 +1,3 @@ +Someone asked for password reset for email {{ email }}. Follow the link below: +{{ protocol }}://{{ domain }}{{ url('password_reset_confirm', kwargs={'uidb64':uid, 'token':token}) }} + diff --git a/templates/registration/welcome_email.jinja2 b/templates/registration/welcome_email.jinja2 new file mode 100644 index 0000000..b6f79f5 --- /dev/null +++ b/templates/registration/welcome_email.jinja2 @@ -0,0 +1,8 @@ +

Willkommen bei den StuVe Services, {{ user.username }}!

+

Es wurde ein Account für dich angelegt.

+

Dein Nutzername lautet: {{ user.username }}

+

Uns ist folgende E-Mail bekannt: {{ email }}

+

Um deinen Account zu aktivieren

+

Über den folgenden Link kannst du deinen Account + aktivieren: {{ protocol }}://{{ domain }}{{ url('ldap_password_reset_confirm', kwargs={'uidb64':uid, 'token':token}) }}

+