Compare commits

..

No commits in common. "master" and "uid-validation" have entirely different histories.

31 changed files with 89 additions and 798 deletions

View File

@ -1,16 +0,0 @@
FROM python:3.10.0-alpine3.15
WORKDIR /usr/src/app
RUN apk add --update --no-cache\
build-base \
openldap-dev\
python3-dev\
&& rm -rf /var/cache/apk/*
# FIX https://github.com/python-ldap/python-ldap/issues/432
RUN echo 'INPUT ( libldap.so )' > /usr/lib/libldap_r.so
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY ungleichuser/ .

View File

@ -4,80 +4,17 @@ This service runs on [account.ungleich.ch](https://account.ungleich.ch/) and
allows customers manage their ungleich account (register, edit mail & password,
...).
## Status v2
* See below ungleichuser/
* register view created
* Not solved:
* email verification *before* user is created
* Solved
* Finding highest uid, increasing by 1
## Todos for v2:
* Rewrite/create new app Django 4.0 based (ungleichuser)
* Do not use django-auth-ldap, because it uses python-ldap
* Update the template HTML to bootstrap5
* Use ldap3
* Check/verify the ldap registration
* Ensure multiple ldap servers are supported
* Cleanup this readme
* Use the following "captcha" for all forms:
* Extra form field named "random"
* Present the user the following text:
* Create Dockerfile / ensure it works in kubernetes
## Next steps
* Override/use custom form to allow captcha
Makes use of Django 2.2 LTS (not compatible with 3.0 at the moment) which is
supported until early 2022.
## Development Setup
```
python3 -m venv venv
. ./venv/bin/activate
pip install -r requirements.txt
``
## Functionality
x Allow user to register in a specific subtree
x Verify that user does not exist in another subtree
x Assign an id
- Allow password reset [via Mail?]
- DB usage: for password reset?
## Parameters
Via environment variables:
* LDAPSERVERS=".." -- White space separated list of LDAP-Servers
* ADMIN_DN="" -- we use this DN to connect to LDAP
* ADMIN_PASSWORD="" -- we use this password to connect to LDAP
* SECRET_KEY
* DEBUG
* ALLOWED_HOSTS
## Views
### Register view
Form: [get]
* username
* password1
* password2
Post receiver: [post]
* E-Mail verification
E-Mail verify: [get]
* Create user
### Password reset view
* captcha
* username or email
* Clone this repository and enter top-level directory.
* (Optional) Setup a Python virtualenv and install dependencies via pip:
- `virtualenv .venv`
- `source .venv/bin/activate`
- `pip install -r requirements.txt`
- Note: you might have to install some OS dependencies (i.e. libldap2, libsasl).
* Configure the `dal` django app (uses the [decouple](https://pypi.org/project/python-decouple/) library underneath)
- Copy `dal/env.sample` to `dal/.env`
- Populate `dal/.env`

View File

@ -65,7 +65,6 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'bootstrap3',
'dal',
'rest_framework'
]
MIDDLEWARE = [
@ -209,10 +208,3 @@ if config('ENABLE_DEBUG_LOG', default=False, cast=bool):
set_library_log_detail_level, OFF, BASIC, NETWORK, EXTENDED
)
set_library_log_detail_level(BASIC)
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
)
}

View File

@ -11,13 +11,14 @@
<meta name="description" content="">
<meta name="author" content="ungleich glarus ag">
<title> Ungleich User Service </title>
<title> Ungleich userservice </title>
<!-- Bootstrap Core CSS -->
<link href="{% static 'datacenterlight/css/bootstrap-3.3.7.min.css' %}" rel="stylesheet">
<!-- Custom CSS -->
<!--<link href=" static 'hosting/css/pricing.css' %}" rel="stylesheet">-->
<link href="{% static 'hosting/css/landing-page.css' %}" rel="stylesheet">
<!-- Custom Fonts -->
@ -33,8 +34,19 @@
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- with 'hosting/img/'|add:hosting|add:'-intro-bg.png' as image_static
<style media="screen" type="text/css">
.intro-header {
background: url(" static image_static %}") no-repeat center center;
}
</style>
-->
<!-- endwith %}-->
<!-- Google analytics -->
<!-- include "google_analytics.html" %} -->
<!-- End Google Analytics -->
</head>
<body>

View File

@ -35,8 +35,6 @@
<button type="submit" class="btn choice-btn btn-block">
{% trans "Change Password" %}
</button>
<hr>
<a class="btn choice-btn btn-block" href="{% url 'index' %}" role="button">Back to Index</a><br>
</div>
</form>
</div>

View File

@ -34,13 +34,7 @@
{% trans "Change User Data" %}
</button>
</div>
<hr>
<div class="text-center">
<a class="btn choice-btn btn-block" href="{% url 'index' %}" role="button">Back to Index</a>
</div>
</form>
</div>
</div>
</div>

View File

@ -1,29 +0,0 @@
{% extends "base_short.html" %}
{% load i18n staticfiles bootstrap3 %}
{% block title %}
<title> Verify your email. </title>
{% endblock %}
{% block content %}
<div class="auth-container">
<div class="auth-bg"></div>
<div class="auth-center">
<div class="auth-content">
<div class="auth-box">
<h1 class="section-heading allcaps">{% trans " Check your email " %}</h1>
<p class="text-center">{% trans "In order to complete the sign up process, please check your email and follow the activation instructions." %}</p>
<form action="{% url 'index' %}" method="get" class="form" novalidated>
<div class="text-center">
<button type="submit" class="btn choice-btn btn-block">
{% trans "Back to indexpage" %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -27,7 +27,6 @@
</div>
<hr>
<div class="text-center">
<a class="btn choice-btn btn-block" href="{% url 'index' %}" role="button">Back to Index</a><br>
<button type="submit" class="btn choicered-btn btn-block">
{% trans "Delete Account" %}
</button>

View File

@ -1,37 +0,0 @@
{% extends "base_short.html" %}
{% load i18n staticfiles bootstrap3 %}
{% block title %}
<title>Options for {{user}}</title>
{% endblock %}
{% block content %}
<div class="auth-container">
<div class="auth-bg"></div>
<div class="auth-center">
<div class="auth-content">
<div class="auth-box">
<h1 class="section-heading allcaps">{% trans "Seeds of," %} {{user}}</h1><br><br>
<table class="table table-hover text-center">
<tbody>
{% for i in seed %}
<tr>
<td>{{ i.realm }}</td>
<td>{{ i.seed }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<br>
<hr>
<form class="form" novalidate>
<div class="text-center">
<a class="btn choice-btn btn-block" href="{% url 'index' %}" role="button">Back to Index</a><br>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -16,7 +16,6 @@
<form class="form">
<a class="btn choice-btn btn-block" href="{% url 'change_data' %}" role="button">{% trans "Change your userdata" %}</a><br>
<a class="btn choice-btn btn-block" href="{% url 'change_password' %}" role="button">Change your password</a><br>
<a class="btn choice-btn btn-block" href="{% url 'user_seeds' %}" role="button">Show seeds</a><br>
<a class="btn choicered-btn btn-block" href="{% url 'logout' %}" role="button">{% trans "Logout" %}</a><br><br>
</form>
<br>

View File

@ -91,7 +91,7 @@ class LdapManager:
logger.debug("{uid} does not exist. Using it".format(uid=uidNumber))
self._set_max_uid(uidNumber)
try:
uid = user # user.encode("utf-8")
uid = user.encode("utf-8")
conn.add("uid={uid},{customer_dn}".format(
uid=uid, customer_dn=settings.LDAP_CUSTOMER_DN
),

View File

@ -13,25 +13,19 @@ from .views import (
Index,
LogOut,
ResetRequest,
UserCreateAPI,
ActivateAccount,
Seeds,
SeedRetrieveCreate
UserCreateAPI
)
urlpatterns = [
path('register/', Register.as_view(), name="register"),
path('create/', UserCreateAPI.as_view(), name="create"),
path('changedata/', ChangeData.as_view(), name="change_data"),
path('seeds/', Seeds.as_view(), name="user_seeds"),
path('resetpassword/', ResetPassword.as_view(), name="reset_password"),
path('changepassword/', ChangePassword.as_view(), name="change_password"),
path('deleteaccount/', DeleteAccount.as_view(), name="account_delete"),
path('index/', Index.as_view(), name="index"),
path('logout/', LogOut.as_view(), name="logout"),
path('reset/<str:user>/<str:token>/', ResetRequest.as_view()),
path('activate/<str:user>/<str:pwd>/<str:firstname>/<str:lastname>/<str:email>/<str:token>/', ActivateAccount.as_view()),
path('reset/', ResetRequest.as_view(), name="reset"),
path('otp/', SeedRetrieveCreate.as_view(), name="seed"),
path('', Index.as_view(), name="login_index"),
]

View File

@ -14,8 +14,6 @@ from rest_framework.response import Response
from .models import ResetToken
from .forms import LoginForm
from .ungleich_ldap import LdapManager
from decouple import config, Csv
from pyotp import TOTP
import logging
import re
@ -29,8 +27,6 @@ from datetime import datetime
from random import choice, randint
import string
import requests
import json
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
@ -39,54 +35,6 @@ from django.contrib.auth.mixins import LoginRequiredMixin
def is_username_valid(username):
return re.fullmatch(r"^[a-z|0-9|\-|_]+$", username)
admin_seed = config('ADMIN_SEED')
admin_name = config('ADMIN_NAME')
admin_realm = config('ADMIN_REALM')
user_realm = config('USER_REALM')
otp_url = config('OTPSERVER')
def activate_account_link(base_url, user, pwd, firstname, lastname, email, epochutc):
tokengen = PasswordResetTokenGenerator()
pseudouser = PseudoUser()
token = tokengen.make_token(pseudouser)
buser = bytes(user, 'utf-8')
bpwd = bytes(pwd, 'utf-8')
bfirstname = bytes(firstname, 'utf-8')
blasttname = bytes(lastname, 'utf-8')
bemail = bytes(email, 'utf-8')
userpart = b64encode(buser)
pwdpart = b64encode(bpwd)
fnpart = b64encode(bfirstname)
lnpart = b64encode(blasttname)
mailpart = b64encode(bemail)
# create entry into the database
newdbentry = ResetToken(user=user, token=token, creation=epochutc)
newdbentry.save()
# set up the link
link = "{base_url}/activate/{user}/{pwd}/{fn}/{ln}/{mail}/{token}/".format(
base_url=base_url, user=userpart.decode('utf-8'),
pwd=pwdpart.decode('utf-8'),
fn=fnpart.decode('utf-8'),
ln=lnpart.decode('utf-8'),
mail=mailpart.decode('utf-8'),
token=token
)
return link
def clean_db():
"""Revoves outdated tokens"""
# cutoff time is set to 24h hours
# using utcnow() to have no headache with timezones
cutoff = int(datetime.utcnow().timestamp()) - (24*60*60)
# Get all tokens older than 24 hours
oldtokens = ResetToken.objects.all().filter(creation__lt=cutoff)
for token in oldtokens:
# delete all tokens older than 24 hours
token.delete()
return True
class Index(FormView):
template_name = "landing.html"
form_class = LoginForm
@ -157,30 +105,34 @@ class Register(View):
pwd = r'%s' % password1
try:
creationtime = int(datetime.utcnow().timestamp())
base_url = "{0}://{1}".format(self.request.scheme,
self.request.get_host())
link = activate_account_link(base_url, username, pwd, firstname, lastname, email, creationtime)
email_from = settings.EMAIL_FROM_ADDRESS
to = ['%s <%s>' % (username, email)]
subject = 'Activate your ungleich account'.format(firstname)
body = 'You can activate your ungleich account account by clicking <a href="{link}">here</a>.' \
' You can also copy and paste the following link into the address bar of your browser and follow' \
' the link in order to activate your account.\n\n{link}'.format(link=link)
# Build the email
mail = EmailMessage(
subject=subject,
body=body,
from_email=email_from,
to=to
ldap_manager = LdapManager()
ldap_manager.create_user(
username, pwd, firstname, lastname, email
)
mail.send()
except Exception as e:
return render(request, 'error.html', { 'urlname': urlname,
'service': service,
'error': e } )
return render(request, 'confirm_email.html')
# Finally, we send the send user credentials via email
creationtime = int(datetime.utcnow().timestamp())
# Construct the data for the email
email_from = settings.EMAIL_FROM_ADDRESS
to = ['%s <%s>' % (username, email)]
subject = '{}, Welcome to datacenterlight'.format(firstname)
body = 'The username {} was successfully created.\n'.format(username)
# Build the email
mail = EmailMessage(
subject=subject,
body=body,
from_email=email_from,
to=to
)
try:
mail.send()
except Exception as e:
print(e)
pass
return render(request, 'usercreated.html', { 'user': username } )
class ChangeData(LoginRequiredMixin, View):
login_url = reverse_lazy('login_index')
@ -358,7 +310,7 @@ class ResetRequest(View):
# Cleans up outdated tokens
# If we expect quite a bit of old tokens, maybe somewhere else is better,
# but for now we don't really expect many unused tokens
clean_db()
self.clean_db()
# If user and token are not supplied by django, it was called from somewhere else, so it's
# invalid
if user == None or token == None:
@ -397,10 +349,10 @@ class ResetRequest(View):
if password1 == "" or not password1 or password2 == "" or not password2:
return render(request, 'error.html', { 'service': service, 'error': 'Please supply a password and confirm it.' } )
if password1 != password2:
return render(request, 'error.html', {'service': service, 'error': 'The supplied passwords do not match.'})
return render(request, 'error.html', { 'service': service, 'error': 'The supplied passwords do not match.' } )
if len(password1) < 8:
return render(request, 'error.html', {'service': service,
'error': 'The password is too short, please use a longer one. At least 8 characters.'})
return render(request, 'error.html', { 'service': service, 'error': 'The password is too short, please use a longer one. At least 8 characters.' } )
# everything checks out, now change the password
ldap_manager = LdapManager()
result = ldap_manager.change_password(
@ -414,7 +366,17 @@ class ResetRequest(View):
else:
return render(request, 'error.html', { 'service': service, 'error': result } )
# Cleans up outdated tokens
def clean_db(self):
# cutoff time is set to 24h hours
# using utcnow() to have no headache with timezones
cutoff = int(datetime.utcnow().timestamp()) - (24*60*60)
# Get all tokens older than 24 hours
oldtokens = ResetToken.objects.all().filter(creation__lt=cutoff)
for token in oldtokens:
# delete all tokens older than 24 hours
token.delete()
return True
# The logged in user can change the password here
@ -539,58 +501,6 @@ class PseudoUser():
pk = ''.join(choice(string.ascii_letters + string.digits) for _ in range(20))
password = ''.join(choice(string.ascii_letters + string.digits) for _ in range(30))
class ActivateAccount(View):
def get(self, request, user=None, pwd=None, firstname=None, lastname=None, email=None, token=None):
clean_db()
if token is None:
return HttpResponse('Invalid URL', status=404)
elem_list = [user, pwd, firstname, lastname, email]
clean_list = []
for value in elem_list:
try:
value_temp = bytes(value, 'utf-8')
value_decode = b64decode(value_temp)
value_clean = value_decode.decode('utf-8')
clean_list.append(value_clean)
except Exception as e:
return HttpResponse('Invalid URL', status=404)
checks_out = False
dbentries = ResetToken.objects.all().filter(user=clean_list[0])
for entry in dbentries:
if entry.token == token:
# found the token, now delete it since it's used
checks_out = True
entry.delete()
# No token was found
if not checks_out:
return HttpResponse('Invalid URL.', status=404)
# Token was found, create user
try:
ldap_manager = LdapManager()
ldap_manager.create_user(
clean_list[0], clean_list[1], clean_list[2], clean_list[3], clean_list[4]
)
req = requests.post(otp_url, data=json.dumps(
{
'auth_token': TOTP(admin_seed).now(),
'auth_name': admin_name,
'auth_realm': admin_realm,
'name': clean_list[0],
'realm': user_realm
}), headers={'Content-Type': 'application/json'})
if req.status_code != 201:
logger.error("User {} failed to create its otp seed".format(clean_list[0]))
#Send welcome email
except Exception as e:
return render(request, 'error.html', {'urlname': 'register',
'service': 'register an user',
'error': e})
return render(request, 'usercreated.html', { 'user': clean_list[0] } )
class UserCreateAPI(APIView):
def post(self, request):
@ -614,24 +524,25 @@ class UserCreateAPI(APIView):
pwd = r'%s' % User.objects.make_random_password()
base_url = "{0}://{1}".format(self.request.scheme,
self.request.get_host())
creationtime = int(datetime.utcnow().timestamp())
link = activate_account_link(base_url, username, pwd, firstname, lastname, email, creationtime)
try:
ldap_manager = LdapManager()
ldap_manager.create_user(
username, pwd, firstname, lastname, email
)
except Exception as e:
return Response('While trying to create the user, an error was encountered: %s' % e, 400)
# send user credentials via email
creationtime = int(datetime.utcnow().timestamp())
# Construct the data for the email
email_from = settings.EMAIL_FROM_ADDRESS
to = ['%s <%s>' % (username, email)]
subject = 'Ungleich account creation.'
body = 'A request has been sent to our servers to register you as a ungleich user.\n'
body += 'In order to complete the registration process you must ' \
'click <a href="{link}">here</a> or copy & paste the following link into the address bar of ' \
'your browser.\n{link}\n'.format(link=link)
subject = 'Your datacenterlight credentials'
body = 'Your user was successfully created.\n'
body += 'Your credentials are:\n'
body += 'Username: %s\n\n' % username
body += 'Password: %s\n\n' % pwd
body += 'We strongly recommend after the activation to log in and change your password.\n'
body += 'This link will remain active for 24 hours.\n'
body += 'We strongly recommend you to after log in change your password.\n'
# Build the email
mail = EmailMessage(
subject=subject,
@ -641,71 +552,6 @@ class UserCreateAPI(APIView):
)
try:
mail.send()
except Exception as e:
return Response('Failed to send the email, please try again', 400)
return Response('An email with activation link has been sent in order to complete your registration. Please check your inbox.', 200)
class SeedRetrieveCreate(APIView):
def post(self, request):
try:
username = request.data['username']
password = request.data[r'password']
realm = request.data['realm']
print(password)
except KeyError:
return Response('You need to specify username, password, and realm values', 400)
# authenticate the user against ldap
user = authenticate(username=username, password=password)
if user is not None:
req = requests.get(otp_url, data=json.dumps(
{
'auth_token': TOTP(admin_seed).now(),
'auth_name': admin_name,
'auth_realm': admin_realm}), headers={'Content-Type': 'application/json'})
response_data = json.loads(req.text)
for elem in response_data:
if elem['name'] == username and elem['realm'] == realm:
return Response(elem, 200)
# If doesn't find a match then check if the realm is allowed and create the user
allowed_realms = config('ALLOWED_REALMS', cast=Csv())
if realm not in allowed_realms:
return Response('Not allowed to perform this action.', 403)
else:
req = requests.post(otp_url, data=json.dumps(
{
'auth_token': TOTP(admin_seed).now(),
'auth_name': admin_name,
'auth_realm': admin_realm,
'name': username,
'realm': realm
}), headers={'Content-Type': 'application/json'})
if req.status_code == 201:
msg = json.loads(req.text)
return Response(msg, 201)
else:
return Response(json.loads(req.text), req.status_code)
else:
return Response('Invalid Credentials', 400)
class Seeds(LoginRequiredMixin, View):
login_url = reverse_lazy('login_index')
def get(self, request):
seedlist = []
response = requests.get(
otp_url,
headers={'Content-Type': 'application/json'},
data=json.dumps(
{'auth_name': admin_name, 'auth_realm': admin_realm, 'auth_token': TOTP(admin_seed).now()}))
response_data = json.loads(response.text)
for i in range(len(response_data)):
if response_data[i]['name'] == request.user.username:
value = {'realm': response_data[i]['realm'], 'seed': response_data[i]['seed']}
seedlist.append(value)
return render(request, 'seed_list.html', {'seed': seedlist})
except:
return Response('User was created, but failed to send the email', 201)
return Response('User successfully created', 200)

2
requirements-os.txt Normal file
View File

@ -0,0 +1,2 @@
# Debian/Devuanp
apt install libldap2-dev libsasl2-dev

8
requirements.txt Normal file
View File

@ -0,0 +1,8 @@
django < 3
django-auth-ldap
python-ldap
django-bootstrap3
django-filter==2.1.0
python-decouple
ldap3
djangorestframework

View File

@ -1,22 +0,0 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ungleichuser.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

View File

@ -1,14 +0,0 @@
django==4.0
ldap3
django-crispy-forms
bootstrap4
#django-auth-ldap
# To check
# django-bootstrap3
# django-filter==2.1.0
# python-decouple
# djangorestframework
# requests

View File

@ -1,19 +0,0 @@
body {
margin: 0;
padding: 0;
background-color: #17a2b8;
height: 100vh;
}
#login .container #login-row #login-column #login-box {
margin-top: 120px;
max-width: 600px;
height: 320px;
border: 1px solid #9C9C9C;
background-color: #EAEAEA;
}
#login .container #login-row #login-column #login-box #login-form {
padding: 20px;
}
#login .container #login-row #login-column #login-box #login-form #register-link {
margin-top: -85px;
}

View File

@ -1,3 +0,0 @@
{% block content %}
Your content here
{% endblock %}

View File

@ -1,36 +0,0 @@
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<body>
<div id="login">
<h3 class="text-center text-white pt-5">Login form</h3>
<div class="container">
<div id="login-row" class="row justify-content-center align-items-center">
<div id="login-column" class="col-md-6">
<div id="login-box" class="col-md-12">
<form id="login-form" class="form" action="" method="post">
<h3 class="text-center text-info">Login</h3>
<div class="form-group">
<label for="username" class="text-info">Username:</label><br>
<input type="text" name="username" id="username" class="form-control">
</div>
<div class="form-group">
<label for="password" class="text-info">Password:</label><br>
<input type="text" name="password" id="password" class="form-control">
</div>
<div class="form-group">
<label for="remember-me" class="text-info"><span>Remember me</span> <span><input id="remember-me" name="remember-me" type="checkbox"></span></label><br>
<input type="submit" name="submit" class="btn btn-info btn-md" value="submit">
</div>
<div id="register-link" class="text-right">
<a href="#" class="text-info">Register here</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</body>

View File

@ -1,42 +0,0 @@
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
<tr>
<td>{{ form.random.label_tag }}</td>
<td>{{ form.random }}</td>
</tr>
</table>
<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>
{# Assumes you setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>
{% endblock %}

View File

@ -1,16 +0,0 @@
"""
ASGI config for ungleichuser project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/dev/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ungleichuser.settings')
application = get_asgi_application()

View File

@ -1,22 +0,0 @@
import django.contrib.auth.forms as forms
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
# class UngleichAuthenticationForm(forms.AuthenticationForm):
# address = forms.CharField(max_length=45)
class NewUserForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ("username", "email", "password1", "password2")
def save(self, commit=True):
user = super(NewUserForm, self).save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user

View File

@ -1,128 +0,0 @@
"""
Django settings for ungleichuser project.
Generated by 'django-admin startproject' using Django 4.0rc1.
For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-(9@_07zxslciu-%wnc7f$qx%=8esu!fuv(72m!6r4f(&#u8$9s'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'crispy_forms',
'ungleichuser'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'ungleichuser.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'ungleichuser.wsgi.application'
# Database
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/dev/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/dev/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/dev/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
CRISPY_TEMPLATE_PACK = 'bootstrap4'

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>

View File

@ -1,18 +0,0 @@
{% extends "ungleichuser/header.html" %}
{% block content %}
{% load crispy_forms_tags %}
<!--Register-->
<div class="container py-5">
<h1>Register</h1>
<form method="POST">
{% csrf_token %}
{{ register_form|crispy }}
<button class="btn btn-primary" type="submit">Register</button>
</form>
<p class="text-center">If you already have an account, <a href="/login">login</a> instead.</p>
</div>
{% endblock %}

View File

@ -1,26 +0,0 @@
"""ungleichuser URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/dev/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
import django.contrib.auth
from django.urls import path, include
from . import views
urlpatterns = [
# path('admin/', admin.site.urls),
# path("", views.homepage, name="homepage"),
path("register", views.register_request, name="register"),
path('accounts/', include('django.contrib.auth.urls')),
]

View File

@ -1,9 +0,0 @@
import ipaddress
import random
v4_addr = ipaddress.IPv4Address(random.randint(0, 2**32))
v6_addr = ipaddress.IPv6Address(random.randint(0, 2**128))
if __name__ == '__main__':
addr_type = random.choice(["ipv6", "ipv4"])
if addr_type == "ipv6":

View File

@ -1,21 +0,0 @@
from django.shortcuts import render, redirect
from .forms import NewUserForm
from django.contrib.auth import login
from django.contrib import messages
def register_request(request):
if request.method == "POST":
form = NewUserForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
messages.success(request, "Registration successful." )
return redirect("main:homepage")
messages.error(request, "Unsuccessful registration. Invalid information.")
form = NewUserForm()
return render (request=request,
template_name="ungleichuser/register.html",
context={"register_form":form})

View File

@ -1,16 +0,0 @@
"""
WSGI config for ungleichuser project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ungleichuser.settings')
application = get_wsgi_application()