Merge branch 'master' into 'master'
Make user service functional See merge request ungleich-public/ungleich-user!1
41
.gitignore
vendored
|
@ -1 +1,42 @@
|
|||
*.log
|
||||
db.sqlite3
|
||||
*.pyc
|
||||
*.DS_Store
|
||||
build/
|
||||
*.egg_info
|
||||
#editors && utilites.
|
||||
*.swp
|
||||
*~
|
||||
__pycache__/
|
||||
.ropeproject/
|
||||
#django
|
||||
local_settings.py
|
||||
|
||||
!.keep
|
||||
media/
|
||||
!media/keep
|
||||
/CACHE/
|
||||
/static/
|
||||
|
||||
\#*#
|
||||
.\#*
|
||||
*~
|
||||
|
||||
secret-key
|
||||
|
||||
node_modules/
|
||||
*.db
|
||||
ungleich.db
|
||||
*~*
|
||||
|
||||
secret-key
|
||||
|
||||
*.psd
|
||||
|
||||
.idea/
|
||||
|
||||
.env
|
||||
*.mo
|
||||
|
||||
venv/
|
||||
dal/ldap_max_uid_file
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
from django.db import models
|
||||
|
||||
# Basic DB to correlate tokens, users and creation time
|
||||
|
||||
class ResetToken(models.Model):
|
||||
|
||||
# users wouldn't use usernames >100 chars
|
||||
user = models.CharField(max_length=100)
|
||||
# Not so sure about tokens, better make it big
|
||||
# should be <100, but big usernames make bigger tokens
|
||||
# if I read that correctly
|
||||
token = models.CharField(max_length=255)
|
||||
# creation time in epoch (UTC)
|
||||
# BigInt just so we are save for the next few decades ;)
|
||||
creation = models.BigIntegerField()
|
|
@ -1,44 +0,0 @@
|
|||
{% load i18n %}
|
||||
|
||||
<style>
|
||||
.col-lg-12 {
|
||||
background-color: grey;
|
||||
color: white;
|
||||
}
|
||||
.list-inline {
|
||||
background-color: grey;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<ul class="list-inline">
|
||||
<li class="col-lg-12">
|
||||
<a href="#">Home</a>
|
||||
</li>
|
||||
<li class="footer-menu-divider">⋅</li>
|
||||
<li>
|
||||
<a href="#about">How it works</a></li>
|
||||
<li class="footer-menu-divider">⋅</li>
|
||||
<li>
|
||||
<a href="#about">Your infrastructure</a></li>
|
||||
<li>⋅</li>
|
||||
<li>
|
||||
<a href="#about">Our infrastructure</a></li>
|
||||
<li class="footer-menu-divider">⋅</li>
|
||||
<li>
|
||||
<a href="#services">Pricing</a>
|
||||
</li>
|
||||
<li class="footer-menu-divider">⋅</li>
|
||||
<li>
|
||||
<a href="#contact">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="copyright text-muted small">Copyright © ungleich glarus ag {% now "Y" %}. {% trans "All Rights Reserved" %}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
|
@ -1,43 +0,0 @@
|
|||
{% extends "base_short.html" %}
|
||||
{% load staticfiles %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
<style>
|
||||
.auth-footer {
|
||||
color: black;
|
||||
}
|
||||
a:link { color: #000000 }
|
||||
</style>
|
||||
<div class="auth_container">
|
||||
<div class="auth_bg"></div>
|
||||
<div class="auth_center">
|
||||
<div class="auth_content">
|
||||
<div class="auth-box">
|
||||
<h2 class="section-heading allcaps"> Login </h2>
|
||||
{% include 'includes/_messages.html' %}
|
||||
<form action={% url 'index' %} method="post" class="form" nonvalidated>
|
||||
{% csrf_token %}
|
||||
<div class="text-center">
|
||||
<div class="form-group"><label class="sr-only control-label" for="username">Username</label><input class="form-control" type="text" name="username" id="username" placeholder="Username"></div>
|
||||
<div class="form-group"><label class="sr-only control-label" for="password">Password</label><input class="form-control" type="password" name="password" id="password" placeholder="Password"></div>
|
||||
<br><br>
|
||||
<button type="submit" class="btn choice-btn"> Log in </button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="auth-footer">
|
||||
<div>
|
||||
Don't have an account yet?
|
||||
<a href={% url 'register' %}> Sign up </a>
|
||||
</div>
|
||||
<div>
|
||||
or <a href={% url 'reset_password' %}> Reset your password </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
31
dal/forms.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
from django import forms
|
||||
from django.contrib.auth import authenticate
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class LoginForm(forms.Form):
|
||||
email = forms.CharField(widget=forms.TextInput())
|
||||
password = forms.CharField(widget=forms.PasswordInput())
|
||||
|
||||
class Meta:
|
||||
fields = ['email', 'password']
|
||||
|
||||
def clean(self):
|
||||
email = self.cleaned_data.get('email')
|
||||
password = self.cleaned_data.get('password')
|
||||
if self.errors:
|
||||
return self.cleaned_data
|
||||
is_auth = authenticate(username=email, password=password)
|
||||
if not is_auth:
|
||||
raise forms.ValidationError(
|
||||
_("Your username and/or password were incorrect.")
|
||||
)
|
||||
# elif is_auth.validated == 0:
|
||||
# raise forms.ValidationError(
|
||||
# _("Your account is not activated yet.")
|
||||
# )
|
||||
return self.cleaned_data
|
||||
|
||||
def clean_email(self):
|
||||
email = self.cleaned_data.get('email')
|
||||
return email
|
37
dal/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Generated by Django 2.1.7 on 2019-02-24 17:35
|
||||
|
||||
import dal.models
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ResetToken',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('user', models.CharField(max_length=100)),
|
||||
('token', models.CharField(max_length=255)),
|
||||
('creation', models.BigIntegerField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserAccountValidationDetail',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('validated', models.IntegerField(choices=[(0, 'Not validated'), (1, 'Validated')], default=0)),
|
||||
('validation_slug', models.CharField(db_index=True, default=dal.models.get_validation_slug, max_length=50, unique=True)),
|
||||
('date_validation_started', models.DateTimeField(auto_now_add=True)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
0
dal/migrations/__init__.py
Normal file
32
dal/models.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
from django.db import models
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
# Basic DB to correlate tokens, users and creation time
|
||||
|
||||
class ResetToken(models.Model):
|
||||
|
||||
# users wouldn't use usernames >100 chars
|
||||
user = models.CharField(max_length=100)
|
||||
# Not so sure about tokens, better make it big
|
||||
# should be <100, but big usernames make bigger tokens
|
||||
# if I read that correctly
|
||||
token = models.CharField(max_length=255)
|
||||
# creation time in epoch (UTC)
|
||||
# BigInt just so we are save for the next few decades ;)
|
||||
creation = models.BigIntegerField()
|
||||
|
||||
|
||||
def get_validation_slug():
|
||||
return make_password(None)
|
||||
|
||||
|
||||
class UserAccountValidationDetail(models.Model):
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
VALIDATED_CHOICES = ((0, 'Not validated'), (1, 'Validated'))
|
||||
validated = models.IntegerField(choices=VALIDATED_CHOICES, default=0)
|
||||
validation_slug = models.CharField(
|
||||
db_index=True, unique=True, max_length=50,
|
||||
default=get_validation_slug
|
||||
)
|
||||
date_validation_started = models.DateTimeField(auto_now_add=True)
|
|
@ -11,29 +11,50 @@ https://docs.djangoproject.com/en/1.10/ref/settings/
|
|||
"""
|
||||
|
||||
import os
|
||||
import dotenv
|
||||
from decouple import config, Csv
|
||||
import ldap
|
||||
from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion
|
||||
|
||||
# get config
|
||||
dotenv.read_dotenv()
|
||||
|
||||
# LDAP setup
|
||||
AUTH_LDAP_SERVER_URI = os.environ['LDAPSERVER']
|
||||
AUTH_LDAP_BIND_DN = os.environ['LDAPSEARCHUSER']
|
||||
AUTH_LDAP_BIND_PASSWORD = os.environ['LDAPSEARCHUSERPASSWORD']
|
||||
LDAP_SERVER = config('LDAP_SERVER')
|
||||
AUTH_LDAP_SERVER_URI = config('LDAPSERVER')
|
||||
|
||||
LDAP_ADMIN_DN = config('LDAP_ADMIN_DN')
|
||||
LDAP_ADMIN_PASSWORD = config('LDAP_ADMIN_PASSWORD')
|
||||
AUTH_LDAP_BIND_DN = LDAP_ADMIN_DN
|
||||
AUTH_LDAP_BIND_PASSWORD = LDAP_ADMIN_PASSWORD
|
||||
AUTH_LDAP_SERVER = AUTH_LDAP_SERVER_URI
|
||||
|
||||
LDAP_CUSTOMER_DN = config('LDAP_CUSTOMER_DN')
|
||||
LDAP_USERS_DN = config('LDAP_USERS_DN')
|
||||
LDAP_CUSTOMER_GROUP_ID = config('LDAP_CUSTOMER_GROUP_ID', cast=int)
|
||||
|
||||
LDAP_MAX_UID_FILE_PATH = config(
|
||||
'LDAP_MAX_UID_FILE_PATH',
|
||||
default=os.path.join(os.path.abspath(
|
||||
os.path.dirname(__file__)), 'ldap_max_uid_file'
|
||||
)
|
||||
)
|
||||
LDAP_DEFAULT_START_UID = config('LDAP_DEFAULT_START_UID', cast=int)
|
||||
|
||||
# Search union over OUs
|
||||
search_base = os.environ['LDAPSEARCH'].split()
|
||||
search_base = config('LDAPSEARCH').split()
|
||||
search_base_ldap = [ LDAPSearch(x, ldap.SCOPE_SUBTREE, "(uid=%(user)s)") for x in search_base ]
|
||||
AUTH_LDAP_USER_SEARCH = LDAPSearchUnion(*search_base_ldap)
|
||||
|
||||
if os.environ['LDAP_USE_TLS']:
|
||||
AUTH_LDAP_START_TLS=True
|
||||
AUTH_LDAP_START_TLS = config('LDAP_USE_TLS', default=False, cast=bool)
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
DEBUG = config('DEBUG', default=False, cast=bool)
|
||||
|
||||
EMAIL_FROM_ADDRESS = config('EMAIL_FROM_ADDRESS')
|
||||
|
||||
EMAIL_HOST = config("EMAIL_HOST", default="localhost")
|
||||
EMAIL_PORT = config("EMAIL_PORT", default=25, cast=int)
|
||||
EMAIL_USE_TLS = config("EMAIL_USE_TLS", default=True, cast=bool)
|
||||
|
||||
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
|
@ -42,6 +63,7 @@ INSTALLED_APPS = [
|
|||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'bootstrap3',
|
||||
'dal',
|
||||
]
|
||||
|
||||
|
@ -120,7 +142,7 @@ STATIC_URL = '/static/'
|
|||
|
||||
############################# To be fixed
|
||||
|
||||
STATIC_ROOT = os.path.dirname('/home/downhill/ungleich/vuejsuserservice/dal/dal/static/')
|
||||
STATIC_ROOT= os.path.join(BASE_DIR, 'static/')
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases
|
||||
|
@ -131,7 +153,58 @@ DATABASES = {
|
|||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
}
|
||||
}
|
||||
SECRET_KEY = 'rn=f&ecp#&#escxpk!0e%a$i3sbm$z@5+g4h9q+w7-83*f2f-i'
|
||||
SECRET_KEY = config('SECRET_KEY')
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
AUTH_LDAP_USER_ATTR_MAP = {
|
||||
"first_name": "givenName",
|
||||
"last_name": "sn",
|
||||
"email": "mail"
|
||||
}
|
||||
|
||||
ENTIRE_SEARCH_BASE = config("ENTIRE_SEARCH_BASE")
|
||||
|
||||
LOGGING = {
|
||||
'disable_existing_loggers': False,
|
||||
'version': 1,
|
||||
'formatters': {
|
||||
'standard': {
|
||||
'format': '%(asctime)s %(levelname)s %(name)s %(funcName)s %(lineno)d: %(message)s'
|
||||
}
|
||||
},
|
||||
'handlers': {
|
||||
'default': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.handlers.RotatingFileHandler',
|
||||
'filename': 'logs/debug.log',
|
||||
'maxBytes': 1024*1024*5,
|
||||
'backupCount': 10,
|
||||
'formatter': 'standard',
|
||||
},
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if config('ENABLE_DEBUG_LOG', default=False, cast=bool):
|
||||
loggers_dict = {}
|
||||
modules_to_log_list = config(
|
||||
'MODULES_TO_LOG', default='django', cast=Csv()
|
||||
)
|
||||
for custom_module in modules_to_log_list:
|
||||
logger_item = {
|
||||
custom_module: {
|
||||
'handlers': ['default'],
|
||||
'level': 'INFO',
|
||||
'propagate': True
|
||||
}
|
||||
}
|
||||
loggers_dict.update(logger_item)
|
||||
|
||||
LOGGING['loggers'] = loggers_dict
|
||||
|
||||
if 'ldap3' in modules_to_log_list:
|
||||
from ldap3.utils.log import (
|
||||
set_library_log_detail_level, OFF, BASIC, NETWORK, EXTENDED
|
||||
)
|
||||
set_library_log_detail_level(BASIC)
|
4
dal/static/datacenterlight/font-awesome/css/font-awesome.min.css
vendored
Normal file
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 434 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 394 KiB After Width: | Height: | Size: 394 KiB |
Before Width: | Height: | Size: 298 KiB After Width: | Height: | Size: 298 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 685 KiB After Width: | Height: | Size: 685 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 276 KiB |
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 166 KiB |
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 208 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 778 KiB After Width: | Height: | Size: 778 KiB |
Before Width: | Height: | Size: 327 KiB After Width: | Height: | Size: 327 KiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 185 KiB |
Before Width: | Height: | Size: 618 KiB After Width: | Height: | Size: 618 KiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 246 KiB |
Before Width: | Height: | Size: 1,021 KiB After Width: | Height: | Size: 1,021 KiB |
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 333 KiB |