Merge branch 'hotfix/0.2.2'

This commit is contained in:
baccenfutter 2013-10-29 18:18:01 +01:00
commit a4e2598e44
7 changed files with 123 additions and 23 deletions

View file

@ -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:

View file

@ -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')

View 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)

View file

@ -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>

View file

@ -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)

View file

@ -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()})

View file

@ -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