Merge branch 'develop' into hotfix/0.2.2
This commit is contained in:
commit
cfd8d0c15d
7 changed files with 123 additions and 23 deletions
|
|
@ -5,6 +5,7 @@ import ldap
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from password_encryption import get_ldap_password
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Example configuration:
|
Example configuration:
|
||||||
|
|
@ -14,8 +15,11 @@ CBASE_BASE_DN = 'ou=crew,dc=c-base,dc=org'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def retrieve_member(request):
|
def retrieve_member(request):
|
||||||
# TODO: Put password in encrypted session storage
|
ldap_password = get_ldap_password(request)
|
||||||
return MemberValues(request.user.username, request.session['ldap_password'])
|
session = dict(request.session)
|
||||||
|
print "session:", session
|
||||||
|
print "cookies:", request.COOKIES
|
||||||
|
return MemberValues(request.user.username, ldap_password)
|
||||||
|
|
||||||
|
|
||||||
class MemberValues(object):
|
class MemberValues(object):
|
||||||
|
|
@ -80,7 +84,8 @@ class MemberValues(object):
|
||||||
|
|
||||||
print "modattrs: ",mod_attrs
|
print "modattrs: ",mod_attrs
|
||||||
result = l.modify_s(dn, mod_attrs)
|
result = l.modify_s(dn, mod_attrs)
|
||||||
print "result is: ", result
|
#
|
||||||
|
# print "result is: ", result
|
||||||
l.unbind_s()
|
l.unbind_s()
|
||||||
|
|
||||||
def change_password(self, new_password):
|
def change_password(self, new_password):
|
||||||
|
|
@ -145,15 +150,26 @@ class MemberValues(object):
|
||||||
l.passwd_s(self._get_bind_dn(username), None, new_password)
|
l.passwd_s(self._get_bind_dn(username), None, new_password)
|
||||||
l.unbind_s()
|
l.unbind_s()
|
||||||
|
|
||||||
|
def get_number_of_members(self):
|
||||||
|
"""
|
||||||
|
Returns the total number of c-base members with active user accounts.
|
||||||
|
"""
|
||||||
|
return len(self.list_users())
|
||||||
|
|
||||||
def list_users(self):
|
def list_users(self):
|
||||||
|
"""
|
||||||
|
Returns a list of strings with all usernames in the group 'crew'.
|
||||||
|
The list is sorted alphabetically.
|
||||||
|
"""
|
||||||
l = ldap.initialize(settings.CBASE_LDAP_URL)
|
l = ldap.initialize(settings.CBASE_LDAP_URL)
|
||||||
user_dn = self._get_bind_dn()
|
user_dn = self._get_bind_dn()
|
||||||
l.simple_bind_s(user_dn, self._password)
|
l.simple_bind_s(user_dn, self._password)
|
||||||
try:
|
try:
|
||||||
ldap_result_id = l.search(settings.CBASE_BASE_DN, ldap.SCOPE_SUBTREE, "memberOf=cn=crew,ou=groups,dc=c-base,dc=org", None)
|
result_id = l.search(settings.CBASE_BASE_DN, ldap.SCOPE_SUBTREE,
|
||||||
|
"memberOf=cn=crew,ou=groups,dc=c-base,dc=org", None)
|
||||||
result_set = []
|
result_set = []
|
||||||
while 1:
|
while True:
|
||||||
result_type, result_data = l.result(ldap_result_id, 0)
|
result_type, result_data = l.result(result_id, 0)
|
||||||
if (result_data == []):
|
if (result_data == []):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
class LoginForm(forms.Form):
|
class LoginForm(forms.Form):
|
||||||
username = forms.CharField(max_length=255)
|
username = forms.CharField(max_length=255)
|
||||||
password = forms.CharField(max_length=255, widget=forms.PasswordInput)
|
password = forms.CharField(max_length=255, widget=forms.PasswordInput,
|
||||||
|
help_text=_('Cookies must be enabled.'))
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
username = self.cleaned_data.get('username')
|
username = self.cleaned_data.get('username')
|
||||||
|
|
|
||||||
64
account/password_encryption.py
Normal file
64
account/password_encryption.py
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import base64
|
||||||
|
|
||||||
|
from Crypto import Random
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
|
ENCRYPTED_LDAP_PASSWORD = 'encrypted_ldap_password'
|
||||||
|
|
||||||
|
def encrypt_ldap_password(cleartext_pw):
|
||||||
|
"""
|
||||||
|
Encrypts the cleartext_pw with a randomly generated key.
|
||||||
|
|
||||||
|
Returns the key and the encrypted message containing the password.
|
||||||
|
The key is supposed to be stored into the 'session_key' cookie field we can
|
||||||
|
later use it to decrypt the password and connect to the LDAP server with it.
|
||||||
|
"""
|
||||||
|
# 16 bytes of key => AES-128
|
||||||
|
random = Random.new()
|
||||||
|
key = random.read(16)
|
||||||
|
|
||||||
|
# initialization vector
|
||||||
|
iv = random.read(16)
|
||||||
|
|
||||||
|
# do the encryption
|
||||||
|
aes = AES.new(key, AES.MODE_CFB, iv)
|
||||||
|
message = iv + aes.encrypt(cleartext_pw)
|
||||||
|
return base64.b64encode(message), base64.b64encode(key)
|
||||||
|
|
||||||
|
def decrypt_ldap_password(message, key):
|
||||||
|
"""
|
||||||
|
Takes an encrypted, base64 encoded password and the base64 encoded key.
|
||||||
|
Returns the cleartext password.
|
||||||
|
"""
|
||||||
|
decoded_message = base64.b64decode(message)
|
||||||
|
decoded_key = base64.b64decode(key)
|
||||||
|
|
||||||
|
# first 16 bytes of the message are the initialization vector
|
||||||
|
iv = decoded_message[:16]
|
||||||
|
|
||||||
|
# the rest is the encrypted password
|
||||||
|
ciphertext = decoded_message[16:]
|
||||||
|
|
||||||
|
# decrypt it
|
||||||
|
aes = AES.new(decoded_key, AES.MODE_CFB, iv)
|
||||||
|
cleartext_pw = aes.decrypt(ciphertext)
|
||||||
|
return cleartext_pw
|
||||||
|
|
||||||
|
def store_ldap_password(request, password):
|
||||||
|
"""
|
||||||
|
Stores the password in an encrypted session storage and returns the key.
|
||||||
|
"""
|
||||||
|
encrypted_pw, key = encrypt_ldap_password(password)
|
||||||
|
request.session[ENCRYPTED_LDAP_PASSWORD] = encrypted_pw
|
||||||
|
request.session.save()
|
||||||
|
return key
|
||||||
|
|
||||||
|
def get_ldap_password(request):
|
||||||
|
cookies = request.COOKIES
|
||||||
|
key = cookies.get('sessionkey', None)
|
||||||
|
if not key:
|
||||||
|
raise Exception('sessionkey not found in cookies.')
|
||||||
|
return decrypt_ldap_password(request.session[ENCRYPTED_LDAP_PASSWORD], key)
|
||||||
|
|
@ -5,7 +5,9 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="span12">
|
<div class="span12">
|
||||||
<h2>{% trans "Welcome to the c-base member interface" %}</h2>
|
<h2>{% trans "Welcome to the c-base member interface" %}</h2>
|
||||||
<p class="lead">{% blocktrans %}Here you can change
|
<p class="leas">You are one of currently {{ number_of_members }}
|
||||||
|
c-base members.</p>
|
||||||
|
<p>{% blocktrans %}Here you can change
|
||||||
some parameters of your c-base member account.{% endblocktrans %}</p>
|
some parameters of your c-base member account.{% endblocktrans %}</p>
|
||||||
|
|
||||||
<h3>{% trans "Basic information about your account" %}</h3>
|
<h3>{% trans "Basic information about your account" %}</h3>
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,24 @@ Replace this with more appropriate tests for your application.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from password_encryption import encrypt_ldap_password, decrypt_ldap_password
|
||||||
|
|
||||||
|
class PasswordEncryptionTest(TestCase):
|
||||||
|
"""
|
||||||
|
Test for the cbmi apps.
|
||||||
|
"""
|
||||||
|
TEST_LDAP_PASSWD = 'correcthorsebatterystaple'
|
||||||
|
|
||||||
|
def encrypt_it(self):
|
||||||
|
return encrypt_ldap_password(self.TEST_LDAP_PASSWD)
|
||||||
|
|
||||||
|
def test_encrypt_ldap_password(self):
|
||||||
|
message, key = self.encrypt_it()
|
||||||
|
print 'key:', key
|
||||||
|
print 'message:', message
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
def test_decrypt_ldap_password(self):
|
||||||
def test_basic_addition(self):
|
message, key = self.encrypt_it()
|
||||||
"""
|
decrypted = decrypt_ldap_password(message, key)
|
||||||
Tests that 1 + 1 always equals 2.
|
self.assertEqual(self.TEST_LDAP_PASSWD, decrypted)
|
||||||
"""
|
|
||||||
self.assertEqual(1 + 1, 2)
|
|
||||||
|
|
@ -5,6 +5,7 @@ import os
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
|
|
@ -20,6 +21,7 @@ from django.utils.translation import ugettext as _
|
||||||
from forms import GastroPinForm, WlanPresenceForm, LoginForm, PasswordForm, \
|
from forms import GastroPinForm, WlanPresenceForm, LoginForm, PasswordForm, \
|
||||||
RFIDForm, NRF24Form, SIPPinForm, CLabPinForm, AdminForm
|
RFIDForm, NRF24Form, SIPPinForm, CLabPinForm, AdminForm
|
||||||
from cbase_members import retrieve_member
|
from cbase_members import retrieve_member
|
||||||
|
from password_encryption import *
|
||||||
|
|
||||||
def landingpage(request):
|
def landingpage(request):
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
|
|
@ -36,8 +38,6 @@ def landingpage(request):
|
||||||
except:
|
except:
|
||||||
admins = []
|
admins = []
|
||||||
|
|
||||||
# values = get_user_values(request.user.username, request.session['ldap_password'])
|
|
||||||
#return render_to_response("dashboard.html", locals())
|
|
||||||
return render(request, 'base.html', {'form': form, 'admins': admins})
|
return render(request, 'base.html', {'form': form, 'admins': admins})
|
||||||
|
|
||||||
def auth_login(request):
|
def auth_login(request):
|
||||||
|
|
@ -57,11 +57,9 @@ def auth_login(request):
|
||||||
member.save()
|
member.save()
|
||||||
|
|
||||||
# save password in the session for later use with LDAP
|
# save password in the session for later use with LDAP
|
||||||
request.session['ldap_password'] = password
|
key = store_ldap_password(request, password)
|
||||||
# TODO: Change the
|
|
||||||
|
|
||||||
response = HttpResponseRedirect(redirect_to)
|
response = HttpResponseRedirect(redirect_to)
|
||||||
response.set_cookie('sessionkey', 'bla')
|
response.set_cookie('sessionkey', key)
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
return render(request, 'login.html', {'form': form})
|
return render(request, 'login.html', {'form': form})
|
||||||
|
|
@ -74,11 +72,14 @@ def auth_login(request):
|
||||||
@login_required
|
@login_required
|
||||||
def home(request):
|
def home(request):
|
||||||
member = retrieve_member(request)
|
member = retrieve_member(request)
|
||||||
context = {'member': member.to_dict(), 'groups': request.user.groups.all()}
|
number_of_members = member.get_number_of_members()
|
||||||
|
context = {'member': member.to_dict(), 'groups': request.user.groups.all(),
|
||||||
|
'number_of_members': number_of_members}
|
||||||
return render(request, 'home.html', context)
|
return render(request, 'home.html', context)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def auth_logout(request):
|
def auth_logout(request):
|
||||||
|
request.session.pop(ENCRYPTED_LDAP_PASSWORD)
|
||||||
redirect_to = request.GET.get('next', '') or '/'
|
redirect_to = request.GET.get('next', '') or '/'
|
||||||
logout(request)
|
logout(request)
|
||||||
response = HttpResponseRedirect(redirect_to)
|
response = HttpResponseRedirect(redirect_to)
|
||||||
|
|
@ -154,6 +155,7 @@ def clabpin(request):
|
||||||
@login_required
|
@login_required
|
||||||
def password(request):
|
def password(request):
|
||||||
"""
|
"""
|
||||||
|
View that changes the password on the LDAP server.
|
||||||
"""
|
"""
|
||||||
member = retrieve_member(request)
|
member = retrieve_member(request)
|
||||||
|
|
||||||
|
|
@ -163,12 +165,13 @@ def password(request):
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
new_password = form.cleaned_data['password1']
|
new_password = form.cleaned_data['password1']
|
||||||
member.change_password(new_password)
|
member.change_password(new_password)
|
||||||
request.session['ldap_password'] = new_password
|
key = store_ldap_password(request, new_password)
|
||||||
request.session.save()
|
request.session.save()
|
||||||
new_form = PasswordForm()
|
new_form = PasswordForm()
|
||||||
return render(request, 'password.html',
|
response = render(request, 'password.html',
|
||||||
{'message': _('Your password was changed. Thank you!'),
|
{'message': _('Your password was changed. Thank you!'),
|
||||||
'form': new_form, 'member': member.to_dict()})
|
'form': new_form, 'member': member.to_dict()})
|
||||||
|
response.set_cookie('sessionkey', key)
|
||||||
else:
|
else:
|
||||||
return render(request, 'password.html',
|
return render(request, 'password.html',
|
||||||
{'form': form, 'member': member.to_dict()})
|
{'form': form, 'member': member.to_dict()})
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,4 @@ MySQL-python==1.2.4
|
||||||
django-auth-ldap==1.1.4
|
django-auth-ldap==1.1.4
|
||||||
django-json-rpc==0.6.1
|
django-json-rpc==0.6.1
|
||||||
django-crispy-forms==1.4.0
|
django-crispy-forms==1.4.0
|
||||||
|
pycrypto==2.6.1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue