diff options
author | Michał Górny <mgorny@gentoo.org> | 2013-07-11 11:41:17 +0200 |
---|---|---|
committer | Michał Górny <mgorny@gentoo.org> | 2013-07-12 11:09:05 +0200 |
commit | 7c33de9705fd2bd1f8e606274c7b001c924e1f6c (patch) | |
tree | b64fa1343c242bf7365ca7a96ef940d487e0cf02 | |
parent | SReg: initial support for choosing fields to send. (diff) | |
parent | Merge pull request #24 from tampakrap/ldapdb (diff) | |
download | identity.gentoo.org-7c33de9705fd2bd1f8e606274c7b001c924e1f6c.tar.gz identity.gentoo.org-7c33de9705fd2bd1f8e606274c7b001c924e1f6c.tar.bz2 identity.gentoo.org-7c33de9705fd2bd1f8e606274c7b001c924e1f6c.zip |
Merge branch 'master' into openid-week4
And fix the PEP8 conflicts.
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | okupy/__init__.py | 2 | ||||
-rw-r--r-- | okupy/accounts/forms.py | 40 | ||||
-rw-r--r-- | okupy/accounts/models.py | 78 | ||||
-rw-r--r-- | okupy/accounts/openid_store.py | 51 | ||||
-rw-r--r-- | okupy/accounts/urls.py | 6 | ||||
-rw-r--r-- | okupy/accounts/views.py | 203 | ||||
-rw-r--r-- | okupy/common/exceptions.py | 1 | ||||
-rw-r--r-- | okupy/common/log.py | 7 | ||||
-rw-r--r-- | okupy/common/testcase.py | 18 | ||||
-rw-r--r-- | okupy/settings/__init__.py | 13 | ||||
-rw-r--r-- | okupy/settings/local.py.sample | 24 | ||||
-rw-r--r-- | okupy/templates/base.html | 42 | ||||
-rw-r--r-- | okupy/templates/devlist.html | 46 | ||||
-rw-r--r-- | okupy/templates/index.html | 80 | ||||
-rw-r--r-- | okupy/tests/__init__.py | 2 | ||||
-rw-r--r-- | okupy/tests/integration/index.py | 3 | ||||
-rw-r--r-- | okupy/tests/integration/login.py | 17 | ||||
-rw-r--r-- | okupy/tests/integration/signup.py | 5 | ||||
-rw-r--r-- | okupy/tests/settings.py | 121 | ||||
-rw-r--r-- | okupy/tests/tests.py | 33 | ||||
-rw-r--r-- | requirements.txt | 1 | ||||
-rwxr-xr-x | setup.py | 5 |
23 files changed, 505 insertions, 295 deletions
@@ -13,3 +13,5 @@ okupy/settings/development.py .coverage .coveralls.yml /htmlcov +.ropeproject +.virtualenv diff --git a/okupy/__init__.py b/okupy/__init__.py index 52234b5..7e9bacb 100644 --- a/okupy/__init__.py +++ b/okupy/__init__.py @@ -1,4 +1,6 @@ # vim:fileencoding=utf8:et:ts=4:sts=4:sw=4:ft=python + + def get_package_version(): return '0.0.1-dev' diff --git a/okupy/accounts/forms.py b/okupy/accounts/forms.py index ac59684..358670e 100644 --- a/okupy/accounts/forms.py +++ b/okupy/accounts/forms.py @@ -4,17 +4,23 @@ from django import forms from .models import OpenID_Attributes + class LoginForm(forms.Form): - username = forms.CharField(max_length = 100, label = 'Username:') - password = forms.CharField(max_length = 30, widget = forms.PasswordInput(), label = 'Password:') + username = forms.CharField(max_length=100, label='Username:') + password = forms.CharField(max_length=30, widget=forms.PasswordInput(), + label='Password:') + class SignupForm(forms.Form): - first_name = forms.CharField(max_length = 100, label = 'First Name:') - last_name = forms.CharField(max_length = 100, label = 'Last Name:') - email = forms.EmailField(max_length = 254, label = 'Email: ') - username = forms.CharField(max_length = 100, label = 'Username:') - password_origin = forms.CharField(max_length = 30, widget = forms.PasswordInput(), label = 'Password:') - password_verify = forms.CharField(max_length = 30, widget = forms.PasswordInput(), label = 'Verify Password:') + first_name = forms.CharField(max_length=100, label='First Name:') + last_name = forms.CharField(max_length=100, label='Last Name:') + email = forms.EmailField(max_length=254, label='Email: ') + username = forms.CharField(max_length=100, label='Username:') + password_origin = forms.CharField( + max_length=30, widget=forms.PasswordInput(), label='Password:') + password_verify = forms.CharField( + max_length=30, widget=forms.PasswordInput(), label='Verify Password:') + # OpenID forms. @@ -22,13 +28,13 @@ class SiteAuthForm(forms.ModelForm): class Meta: model = OpenID_Attributes widgets = { - 'nickname': forms.CheckboxInput, - 'email': forms.CheckboxInput, - 'fullname': forms.CheckboxInput, - 'dob': forms.CheckboxInput, - 'gender': forms.CheckboxInput, - 'postcode': forms.CheckboxInput, - 'country': forms.CheckboxInput, - 'language': forms.CheckboxInput, - 'timezone': forms.CheckboxInput, + 'nickname': forms.CheckboxInput, + 'email': forms.CheckboxInput, + 'fullname': forms.CheckboxInput, + 'dob': forms.CheckboxInput, + 'gender': forms.CheckboxInput, + 'postcode': forms.CheckboxInput, + 'country': forms.CheckboxInput, + 'language': forms.CheckboxInput, + 'timezone': forms.CheckboxInput, } diff --git a/okupy/accounts/models.py b/okupy/accounts/models.py index 7527b48..e3abfdf 100644 --- a/okupy/accounts/models.py +++ b/okupy/accounts/models.py @@ -1,6 +1,10 @@ # vim:fileencoding=utf8:et:ts=4:sts=4:sw=4:ft=python +from django.conf import settings from django.db import models +from ldapdb.models.fields import CharField, IntegerField, ListField +import ldapdb.models + class Queue(models.Model): username = models.CharField(max_length=100, unique=True) @@ -10,27 +14,81 @@ class Queue(models.Model): email = models.EmailField(max_length=254, unique=True) token = models.CharField(max_length=40) + +class LDAPUser(ldapdb.models.Model): + """ Class representing an LDAP user entry """ + # LDAP metadata + base_dn = settings.AUTH_LDAP_USER_BASE_DN + object_classes = settings.AUTH_LDAP_USER_OBJECTCLASS + \ + settings.AUTH_LDAP_DEV_OBJECTCLASS + # top + object_class = ListField(db_column='objectClass') + # person + last_name = CharField(db_column='sn') + full_name = CharField(db_column='cn') + description = CharField(db_column='description') + phone = CharField(db_column='telephoneNumber', blank=True) + password = ListField(db_column='userPassword') + # inetOrgPerson + first_name = CharField(db_column='givenName') + email = ListField(db_column='mail') + username = CharField(db_column='uid', primary_key=True) + # posixAccount + uid = IntegerField(db_column='uidNumber', unique=True) + gid = IntegerField(db_column='gidNumber') + gecos = CharField(db_column='gecos') + home_directory = CharField(db_column='homeDirectory') + login_shell = CharField(db_column='loginShell', default='/bin/bash') + # ldapPublicKey + ssh_key = ListField(db_column='sshPublicKey') + # gentooGroup + ACL = ListField(db_column='gentooACL') + birthday = CharField(db_column='birthday') + gentoo_join_date = ListField(db_column='gentooJoin') + gentoo_retire_date = ListField(db_column='gentooRetire') + developer_bug = ListField(db_column='gentooDevBug') + gpg_fingerprint = ListField(db_column='gentooGPGFingerprint') + gpg_key = ListField(db_column='gentooGPGKey') + latitude = IntegerField(db_column='gentooLatitude') + longitude = IntegerField(db_column='gentooLongitude') + location = CharField(db_column='gentooLocation') + mentor = ListField(db_column='gentooMentor') + im = ListField(db_column='gentooIM') + # gentooDevGroup + roles = CharField(db_column='gentooRoles') + alias = ListField(db_column='gentooAlias') + spf = ListField(db_column='gentooSPF') + + def __str__(self): + return self.username + + def __unicode__(self): + return self.username + + # Models for OpenID data store class OpenID_Nonce(models.Model): + server_uri = models.URLField(max_length=2048) + ts = models.DateTimeField() + salt = models.CharField(max_length=40) + class Meta: unique_together = ('server_uri', 'ts', 'salt') - server_uri = models.URLField(max_length = 2048) - ts = models.DateTimeField() - salt = models.CharField(max_length = 40) class OpenID_Association(models.Model): + server_uri = models.URLField(max_length=2048) + handle = models.CharField(max_length=255) + # TODO: BinaryField in newer versions of django + secret = models.CharField(max_length=128) + issued = models.DateTimeField() + expires = models.DateTimeField() + assoc_type = models.CharField(max_length=64) + class Meta: unique_together = ('server_uri', 'handle') - server_uri = models.URLField(max_length = 2048) - handle = models.CharField(max_length = 255) - # XXX: BinaryField in newer versions of django - secret = models.CharField(max_length = 128) - issued = models.DateTimeField() - expires = models.DateTimeField() - assoc_type = models.CharField(max_length = 64) class OpenID_Attributes(models.Model): """ An attribute choice for submission to the site requesting auth. diff --git a/okupy/accounts/openid_store.py b/okupy/accounts/openid_store.py index d2c1446..45cd715 100644 --- a/okupy/accounts/openid_store.py +++ b/okupy/accounts/openid_store.py @@ -1,6 +1,9 @@ # vim:fileencoding=utf8:et:ts=4:sts=4:sw=4:ft=python -import base64, calendar, datetime, time +import base64 +import calendar +import datetime +import time from django.utils import timezone @@ -10,30 +13,32 @@ from openid.store import nonce from . import models as db_models + class DjangoDBOpenIDStore(OpenIDStore): + def storeAssociation(self, server_uri, assoc): issued_dt = datetime.datetime.utcfromtimestamp(assoc.issued) issued_dt = timezone.make_aware(issued_dt, timezone.utc) - expire_delta = datetime.timedelta(seconds = assoc.lifetime) + expire_delta = datetime.timedelta(seconds=assoc.lifetime) a = db_models.OpenID_Association( - server_uri = server_uri, - handle = assoc.handle, - secret = base64.b64encode(assoc.secret), - issued = issued_dt, - expires = issued_dt + expire_delta, - assoc_type = assoc.assoc_type) + server_uri=server_uri, + handle=assoc.handle, + secret=base64.b64encode(assoc.secret), + issued=issued_dt, + expires=issued_dt + expire_delta, + assoc_type=assoc.assoc_type) a.save() - def _db_getAssocs(self, server_uri, handle = None): + def _db_getAssocs(self, server_uri, handle=None): objs = db_models.OpenID_Association.objects - objs = objs.filter(server_uri = server_uri) + objs = objs.filter(server_uri=server_uri) if handle is not None: - objs = objs.filter(handle = handle) + objs = objs.filter(handle=handle) return objs - def getAssociation(self, server_uri, handle = None): + def getAssociation(self, server_uri, handle=None): assert(server_uri is not None) objs = self._db_getAssocs(server_uri, handle) @@ -50,11 +55,11 @@ class DjangoDBOpenIDStore(OpenIDStore): return None return Association( - a.handle, - base64.b64decode(a.secret), - calendar.timegm(a.issued.utctimetuple()), - int((a.expires - a.issued).total_seconds()), - a.assoc_type) + a.handle, + base64.b64decode(a.secret), + calendar.timegm(a.issued.utctimetuple()), + int((a.expires - a.issued).total_seconds()), + a.assoc_type) def removeAssociation(self, server_uri, handle): assert(server_uri is not None) @@ -75,22 +80,22 @@ class DjangoDBOpenIDStore(OpenIDStore): objs = db_models.OpenID_Nonce.objects n, created = objs.get_or_create( - server_uri = server_uri, - ts = nonce_dt, - salt = salt) + server_uri=server_uri, + ts=nonce_dt, + salt=salt) # if it was created, it is unique and everything's fine. # if we found one existing, it is duplicate and we return False. return created def cleanupNonces(self): - skew_td = datetime.timedelta(seconds = nonce.SKEW) + skew_td = datetime.timedelta(seconds=nonce.SKEW) expire_dt = timezone.now() - skew_td - db_models.OpenID_Nonce.objects.filter(ts__lt = expire_dt).delete() + db_models.OpenID_Nonce.objects.filter(ts__lt=expire_dt).delete() return 0 def cleanupAssociations(self): db_models.OpenID_Association.objects.filter( - expires__lt = timezone.now()).delete() + expires__lt=timezone.now()).delete() return 0 diff --git a/okupy/accounts/urls.py b/okupy/accounts/urls.py index e5a0d41..f9eb2dd 100644 --- a/okupy/accounts/urls.py +++ b/okupy/accounts/urls.py @@ -1,13 +1,15 @@ # vim:fileencoding=utf8:et:ts=4:sts=4:sw=4:ft=python from django.conf.urls import patterns, url -from .views import (login, logout, index, signup, activate, formerdevlist, - foundationlist, openid_endpoint, user_page, openid_auth_site) +from .views import (login, logout, index, signup, activate, devlist, + formerdevlist, foundationlist, openid_endpoint, user_page, + openid_auth_site) accounts_urlpatterns = patterns('', url(r'^$', index), url(r'^login/$', login), url(r'^logout/$', logout), + url(r'^devlist/$', devlist), url(r'^former-devlist/$', formerdevlist), url(r'^foundation-members/$', foundationlist), url(r'^signup/$', signup), diff --git a/okupy/accounts/views.py b/okupy/accounts/views.py index 249309f..06294b9 100644 --- a/okupy/accounts/views.py +++ b/okupy/accounts/views.py @@ -2,41 +2,80 @@ from django.conf import settings from django.contrib import messages -from django.contrib.auth import login as _login, logout as _logout, authenticate +from django.contrib.auth import (login as _login, logout as _logout, + authenticate) from django.contrib.auth.decorators import login_required from django.core.mail import send_mail from django.core.urlresolvers import reverse from django.db import IntegrityError from django.http import HttpResponse from django.shortcuts import redirect, render -from django.template import RequestContext from django.views.decorators.csrf import csrf_exempt +from edpwd import random_string +from openid.extensions.sreg import SRegRequest +from openid.server.server import (Server, ProtocolError, EncodingError, + CheckIDRequest, ENCODE_URL, + ENCODE_KVFORM, ENCODE_HTML_FORM) +from passlib.hash import ldap_md5_crypt + from .forms import LoginForm, SignupForm, SiteAuthForm from .models import Queue from .openid_store import DjangoDBOpenIDStore - from ..common.exceptions import OkupyError from ..common.log import log_extra_data -from edpwd import random_string -from passlib.hash import ldap_md5_crypt +# the following two are for exceptions +import openid.yadis.discover +import openid.fetchers import ldap import ldap.modlist as modlist import logging -from openid.extensions.sreg import SRegRequest -from openid.server.server import (Server, ProtocolError, EncodingError, - CheckIDRequest, ENCODE_URL, ENCODE_KVFORM, ENCODE_HTML_FORM) -# for exceptions -import openid.yadis.discover, openid.fetchers - logger = logging.getLogger('okupy') logger_mail = logging.getLogger('mail_okupy') + @login_required def index(request): - return render(request, 'index.html', {}) + anon_ldap_user = ldap.initialize(settings.AUTH_LDAP_SERVER_URI) + results = anon_ldap_user.search_s(settings.AUTH_LDAP_USER_DN_TEMPLATE % { + 'user': request.user}, ldap.SCOPE_SUBTREE, '(uid=%s)' % (request.user)) + attrs = results[0][1] + personal_attributes = { + 'cn': 'Real Name', 'uid': 'Nickname', 'gentooLocation': 'Location'} + contact_attributes = {'mail': 'Email', 'gentooIM': 'IM Nickname'} + gentoo_attributes = { + 'herd': 'Herds', 'gentooRoles': 'Roles', 'gentooJoin': 'Date Joined', + 'gentooMentor': 'Mentor', 'gentooDevBug': 'Recruitment Bug', + 'gentooRetired': 'Retired'} + ldap_personal_info = {} + ldap_contact_info = {} + ldap_gentoo_info = {} + + for k, v in personal_attributes.items(): + attrs[k] = attrs.get(k, ['Empty, when it should be']) + ldap_personal_info[v] = attrs[k][0] + + for k, v in contact_attributes.items(): + attrs[k] = attrs.get(k, ['']) + ldap_contact_info[v] = attrs[k][0] + + for k, v in gentoo_attributes.items(): + if k == 'gentooRetired' and k not in attrs: + continue + else: + attrs[k] = attrs.get(k, ['']) + ldap_gentoo_info[v] = attrs[k][0] + + anon_ldap_user.unbind_s() + + return render(request, 'index.html', { + 'ldap_personal_info': ldap_personal_info, + 'ldap_contact_info': ldap_contact_info, + 'ldap_gentoo_info': ldap_gentoo_info + }) + def login(request): """ The login page """ @@ -72,18 +111,19 @@ def login(request): it was successful. If it retrieves None then it failed to login """ try: - user = authenticate(username = username, password = password) + user = authenticate(username=username, password=password) except Exception as error: logger.critical(error, extra=log_extra_data(request)) logger_mail.exception(error) - raise OkupyError("Can't contact the LDAP server or the database") + raise OkupyError( + "Can't contact the LDAP server or the database") if not user: raise OkupyError('Login failed') if user.is_active: _login(request, user) request.session.set_expiry(900) return redirect(request.GET.get('next', index)) - except OkupyError, error: + except OkupyError as error: messages.error(request, str(error)) else: if request.user.is_authenticated(): @@ -96,11 +136,13 @@ def login(request): 'openid_request': oreq, }) + def logout(request): """ The logout page """ _logout(request) return redirect(login) + def signup(request): """ The signup page """ signup_form = None @@ -108,31 +150,37 @@ def signup(request): signup_form = SignupForm(request.POST) if signup_form.is_valid(): try: - if signup_form.cleaned_data['password_origin'] != signup_form.cleaned_data['password_verify']: + if signup_form.cleaned_data['password_origin'] != \ + signup_form.cleaned_data['password_verify']: raise OkupyError("Passwords don't match") try: - anon_ldap_user = ldap.initialize(settings.AUTH_LDAP_SERVER_URI) - anon_ldap_user.simple_bind_s(settings.AUTH_LDAP_BIND_DN, settings.AUTH_LDAP_BIND_PASSWORD) + anon_ldap_user = ldap.initialize( + settings.AUTH_LDAP_SERVER_URI) + anon_ldap_user.simple_bind_s( + settings.AUTH_LDAP_BIND_DN, + settings.AUTH_LDAP_BIND_PASSWORD) except Exception as error: logger.critical(error, extra=log_extra_data(request)) logger_mail.exception(error) raise OkupyError("Can't contact LDAP server") if anon_ldap_user.search_s( settings.AUTH_LDAP_USER_BASE_DN, ldap.SCOPE_ONELEVEL, - filterstr = '(uid=%s)' % signup_form.cleaned_data['username']): + filterstr='(uid=%s)' % + signup_form.cleaned_data['username']): raise OkupyError('Username already exists') if anon_ldap_user.search_s( settings.AUTH_LDAP_USER_BASE_DN, ldap.SCOPE_ONELEVEL, - filterstr = '(mail=%s)' % signup_form.cleaned_data['email']): + filterstr='(mail=%s)' % + signup_form.cleaned_data['email']): raise OkupyError('Email already exists') anon_ldap_user.unbind_s() queued_user = Queue( - username = signup_form.cleaned_data['username'], - first_name = signup_form.cleaned_data['first_name'], - last_name = signup_form.cleaned_data['last_name'], - email = signup_form.cleaned_data['email'], - password = signup_form.cleaned_data['password_origin'], - token = random_string(40), + username=signup_form.cleaned_data['username'], + first_name=signup_form.cleaned_data['first_name'], + last_name=signup_form.cleaned_data['last_name'], + email=signup_form.cleaned_data['email'], + password=signup_form.cleaned_data['password_origin'], + token=random_string(40), ) try: queued_user.save() @@ -144,13 +192,15 @@ def signup(request): raise OkupyError("Can't contact the database") send_mail( '%sAccount Activation' % settings.EMAIL_SUBJECT_PREFIX, - 'To confirm your email address, please click the following link:\n%s' % queued_user.token, + 'To confirm your email address, please click the \ + following link:\n%s' % queued_user.token, '%s' % settings.SERVER_EMAIL, [signup_form.cleaned_data['email']] ) - messages.info(request, "You will shortly receive an activation mail") + messages.info( + request, "You will shortly receive an activation mail") return redirect(login) - except OkupyError, error: + except OkupyError as error: messages.error(request, str(error)) else: signup_form = SignupForm() @@ -158,6 +208,7 @@ def signup(request): 'signup_form': signup_form, }) + def activate(request, token): """ The page that users get to activate their accounts @@ -177,7 +228,9 @@ def activate(request, token): # add account to ldap try: admin_ldap_user = ldap.initialize(settings.AUTH_LDAP_SERVER_URI) - admin_ldap_user.simple_bind_s(settings.AUTH_LDAP_ADMIN_BIND_DN, settings.AUTH_LDAP_ADMIN_BIND_PASSWORD) + admin_ldap_user.simple_bind_s( + settings.AUTH_LDAP_ADMIN_BIND_DN, + settings.AUTH_LDAP_ADMIN_BIND_PASSWORD) except Exception as error: logger.critical(error, extra=log_extra_data(request)) logger_mail.exception(error) @@ -188,11 +241,13 @@ def activate(request, token): 'mail': [str(queued_user.email)], 'givenName': [str(queued_user.first_name)], 'sn': [str(queued_user.last_name)], - 'gecos': ['%s %s' % (queued_user.first_name, queued_user.last_name)], + 'gecos': ['%s %s' % (queued_user.first_name, + queued_user.last_name)], 'objectClass': settings.AUTH_LDAP_USER_OBJECTCLASS, } if 'person' in new_user['objectClass']: - new_user['cn'] = ['%s %s' % (queued_user.first_name, queued_user.last_name)] + new_user['cn'] = ['%s %s' % ( + queued_user.first_name, queued_user.last_name)] if 'posixAccount' in new_user['objectClass']: try: max_uidnumber = admin_ldap_user.search_s( @@ -203,51 +258,63 @@ def activate(request, token): max_uidnumber = 0 new_user['uidNumber'] = [str(int(max_uidnumber) + 1)] new_user['gidNumber'] = ['100'] - new_user['homeDirectory'] = ['/home/%s' % str(queued_user.username)] + new_user['homeDirectory'] = [ + '/home/%s' % str(queued_user.username)] ldif = modlist.addModlist(new_user) - admin_ldap_user.add_s('uid=%s,%s' % (queued_user.username, settings.AUTH_LDAP_USER_BASE_DN), ldif) + admin_ldap_user.add_s('uid=%s,%s' % ( + queued_user.username, settings.AUTH_LDAP_USER_BASE_DN), ldif) admin_ldap_user.unbind_s() # remove queued account from DB queued_user.delete() - messages.success(request, "Your account has been activated successfully") - except OkupyError, error: + messages.success( + request, "Your account has been activated successfully") + except OkupyError as error: messages.error(request, str(error)) return redirect(login) + +def devlist(request): + return render(request, 'devlist.html', {}) + + def formerdevlist(request): return render(request, 'former-devlist.html', {}) + def foundationlist(request): return render(request, 'foundation-members.html', {}) # OpenID-specific + def endpoint_url(request): return request.build_absolute_uri(reverse(openid_endpoint)) + def get_openid_server(request): store = DjangoDBOpenIDStore() return Server(store, endpoint_url(request)) -def render_openid_response(request, oresp, srv = None): + +def render_openid_response(request, oresp, srv=None): if srv is None: srv = get_openid_server(request) try: eresp = srv.encodeResponse(oresp) except EncodingError as e: - # XXX: do we want some different heading for it? - return render(request, 'openid_endpoint.html', - { - 'error': str(e) - }, status = 500) + # TODO: do we want some different heading for it? + return render(request, 'openid_endpoint.html', { + 'error': str(e), + }, status=500) - dresp = HttpResponse(eresp.body, status = eresp.code) + dresp = HttpResponse(eresp.body, status=eresp.code) for h, v in eresp.headers.items(): dresp[h] = v return dresp + @csrf_exempt def openid_endpoint(request): if request.method == 'POST': @@ -265,12 +332,11 @@ def openid_endpoint(request): elif e.whichEncoding() == ENCODE_HTML_FORM: return HttpResponse(e.toHTML()) elif e.whichEncoding() == ENCODE_KVFORM: - return HttpResponse(e.encodeToKVForm(), status = 400) + return HttpResponse(e.encodeToKVForm(), status=400) else: - return render(request, 'openid_endpoint.html', - { - 'error': str(e) - }, status = 400) + return render(request, 'openid_endpoint.html', { + 'error': str(e) + }, status=400) if oreq is None: return render(request, 'openid_endpoint.html') @@ -288,20 +354,22 @@ def openid_endpoint(request): return render_openid_response(request, oresp, srv) + def user_page(request, username): return render(request, 'user-page.html', { - 'endpoint_uri': endpoint_url(request) + 'endpoint_uri': endpoint_url(request), }) + @login_required def openid_auth_site(request): try: oreq = request.session['openid_request'] except KeyError: - return render(request, 'openid-auth-site.html', - { - 'error': 'No OpenID request associated. The request may have expired.' - }, status = 400) + return render(request, 'openid-auth-site.html', { + 'error': 'No OpenID request associated. The request may have \ + expired.', + }, status=400) sreg = SRegRequest.fromOpenIDRequest(oreq) @@ -310,7 +378,7 @@ def openid_auth_site(request): # can it be invalid somehow? assert(form.is_valid()) - attrs = form.save(commit = False) + attrs = form.save(commit=False) # nullify fields that were not requested for fn in form.cleaned_data: @@ -320,22 +388,20 @@ def openid_auth_site(request): # TODO: actually send the data if 'accept' in request.POST: - oresp = oreq.answer(True, - identity=request.build_absolute_uri( - reverse(user_page, args=(request.user.username,)))) + oresp = oreq.answer(True, identity=request.build_absolute_uri( + reverse(user_page, args=(request.user.username,)))) elif 'reject' in request.POST: oresp = oreq.answer(False) else: - return render(request, 'openid-auth-site.html', - { - 'error': 'Invalid request submitted.' - }, status = 400) + return render(request, 'openid-auth-site.html', { + 'error': 'Invalid request submitted.', + }, status=400) del request.session['openid_request'] return render_openid_response(request, oresp) try: - # XXX: cache it + # TODO: cache it if oreq.returnToVerified(): tr_valid = 'Return-To valid and trusted' else: @@ -346,10 +412,9 @@ def openid_auth_site(request): tr_valid = 'Unable to verify trust (HTTP error)' form = SiteAuthForm() - return render(request, 'openid-auth-site.html', - { - 'openid_request': oreq, - 'return_to_valid': tr_valid, - 'form': form, - 'sreg': sreg, - }) + return render(request, 'openid-auth-site.html', { + 'openid_request': oreq, + 'return_to_valid': tr_valid, + 'form': form, + 'sreg': sreg, + }) diff --git a/okupy/common/exceptions.py b/okupy/common/exceptions.py index fc04ea3..a979503 100644 --- a/okupy/common/exceptions.py +++ b/okupy/common/exceptions.py @@ -1,4 +1,5 @@ # vim:fileencoding=utf8:et:ts=4:sts=4:sw=4:ft=python + class OkupyError(Exception): pass diff --git a/okupy/common/log.py b/okupy/common/log.py index 4f016c8..c8994cc 100644 --- a/okupy/common/log.py +++ b/okupy/common/log.py @@ -2,11 +2,12 @@ from django.conf import settings -def log_extra_data(additional = None): + +def log_extra_data(additional=None): ''' Extra data needed by the custom formatter - * If the additional argument is a string or unicode, then its value is printed - in the log. + * If the additional argument is a string or unicode, then its value is + printed in the log. * If the additional argument is the request, then from the request it prints the client IP and username if applicable. ''' diff --git a/okupy/common/testcase.py b/okupy/common/testcase.py index 3dd7d40..251b361 100644 --- a/okupy/common/testcase.py +++ b/okupy/common/testcase.py @@ -3,7 +3,9 @@ from django.test import TestCase from django.contrib.messages.storage.cookie import CookieStorage + class OkupyTestCase(TestCase): + def _get_matches(self, response, text): """ Get messages that match the given text """ messages = self._get_messages(response) @@ -19,7 +21,8 @@ class OkupyTestCase(TestCase): messages = response.context['messages'] except (TypeError, KeyError): try: - messages = CookieStorage(response)._decode(response.cookies['messages'].value) + messages = CookieStorage(response)._decode( + response.cookies['messages'].value) except KeyError: return return messages @@ -35,7 +38,7 @@ class OkupyTestCase(TestCase): actual_num = 0 if actual_num != expect_num: self.fail('Message count was %d, expected %d' % - (actual_num, expect_num)) + (actual_num, expect_num)) def assertMessage(self, response, text, level=None): """ @@ -46,18 +49,19 @@ class OkupyTestCase(TestCase): msg = matches[0] if level is not None and msg.level != level: self.fail('There was one matching message but with different ' - 'level: %s != %s' % (msg.level, level)) + 'level: %s != %s' % (msg.level, level)) elif len(matches) == 0: - messages_str = ", ".join('"%s"' % m for m in self._get_messages(response)) + messages_str = ", ".join( + '"%s"' % m for m in self._get_messages(response)) self.fail('No message contained text "%s", messages were: %s' % - (text, messages_str)) + (text, messages_str)) else: self.fail('Multiple messages contained text "%s": %s' % - (text, ", ".join(('"%s"' % m) for m in matches))) + (text, ", ".join(('"%s"' % m) for m in matches))) def assertNotMessage(self, response, text): """ Assert that no message contains the given text. """ matches = self._get_matches(response, text) if len(matches) > 0: self.fail('Message(s) contained text "%s": %s' % - (text, ", ".join(('"%s"' % m) for m in matches))) + (text, ", ".join(('"%s"' % m) for m in matches))) diff --git a/okupy/settings/__init__.py b/okupy/settings/__init__.py index e811e89..9daa78e 100644 --- a/okupy/settings/__init__.py +++ b/okupy/settings/__init__.py @@ -80,7 +80,6 @@ LOGGING = { 'formatter': 'simple', 'address': '/dev/log', }, - }, 'loggers': { 'mail_okupy': { @@ -123,3 +122,15 @@ EMAIL_SUBJECT_PREFIX = '[%s]: ' % INSTANCE_NAME TEMPLATE_CONTEXT_PROCESSORS += ( 'django.core.context_processors.request', ) + +# django-ldapdb settings +DATABASES['ldap'] = { + 'ENGINE': 'ldapdb.backends.ldap', + 'NAME': AUTH_LDAP_SERVER_URI, + 'USER': AUTH_LDAP_BIND_DN, + 'PASSWORD': AUTH_LDAP_BIND_PASSWORD, + 'CONNECTION_OPTIONS': AUTH_LDAP_CONNECTION_OPTIONS, + 'TLS': AUTH_LDAP_START_TLS, +} + +DATABASE_ROUTERS = ['ldapdb.router.Router'] diff --git a/okupy/settings/local.py.sample b/okupy/settings/local.py.sample index 79fd533..454906c 100644 --- a/okupy/settings/local.py.sample +++ b/okupy/settings/local.py.sample @@ -60,26 +60,14 @@ AUTH_LDAP_ADMIN_BIND_DN = '' AUTH_LDAP_ADMIN_BIND_PASSWORD = '' AUTH_LDAP_USER_ATTR = 'uid' -AUTH_LDAP_USER_BASE_DN = 'ou=people,o=test' +AUTH_LDAP_USER_BASE_DN = 'ou=people,dc=example,dc=com' AUTH_LDAP_PERMIT_EMPTY_PASSWORD = False AUTH_LDAP_START_TLS = False -#AUTH_LDAP_GROUP_SEARCH -#AUTH_LDAP_GROUP_TYPE -#AUTH_LDAP_REQUIRE_GROUP -#AUTH_LDAP_DENY_GROUP -#AUTH_LDAP_CACHE_GROUPS -#AUTH_LDAP_GROUP_CACHE_TIMEOUT -#AUTH_LDAP_FIND_GROUP_PERMS - -#AUTH_LDAP_USER_FLAGS_BY_GROUP = { - #'is_active': '', - #'is_staff': '', - #'is_superuser': '', -#} - -#AUTH_LDAP_PROFILE_FLAGS_BY_GROUP = {} - -AUTH_LDAP_USER_OBJECTCLASS = ["person", "organizationalPerson", "inetOrgPerson", "posixAccount"] +# objectClasses that are used by any user +AUTH_LDAP_USER_OBJECTCLASS = ['top', 'person', 'organizationalPerson', + 'inetOrgPerson', 'posixAccount', 'shadowAccount'] +# additional objectClasses that are used by developers +AUTH_LDAP_DEV_OBJECTCLASS = ['developerAccount'] diff --git a/okupy/templates/base.html b/okupy/templates/base.html index e63c55c..f96a6a2 100644 --- a/okupy/templates/base.html +++ b/okupy/templates/base.html @@ -25,7 +25,7 @@ <span class="icon-bar"></span> <span class="icon-bar"></span> </a> - <a class="brand" href="#"> + <a class="brand" href="/"> <img src="{%static "img/site-logo.png"%}" alt="Gentoo Logo" /> </a> <div class="nav-collapse"> @@ -36,7 +36,7 @@ <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown">Lists<b class="caret"></b></a> <ul class="dropdown-menu"> - <li><a href="/">Developer List</a></li> + <li><a href="/devlist/">Developer List</a></li> <li><a href="/foundation-members/">Foundation Members</a></li> <li><a href="/former-devlist/">Former Developer List</a></li> </ul> @@ -45,21 +45,33 @@ <ul class="nav pull-right"> <li class="divider-vertical"></li> <li class="dropdown"> - <a href="#" class="dropdown-toggle" data-toggle="dropdown">gentoo.org Sites <b class="caret"></b></a> + <a href="#" class="dropdown-toggle" data-toggle="dropdown">gentoo.org Sites <b class="caret"></b></a> + <ul class="dropdown-menu"> + <li><a href="http://www.gentoo.org/">gentoo.org</a></li> + <li><a href="http://wiki.gentoo.org/" title="Find and contribute documentation">Wiki</a></li> + <li><a href="https://bugs.gentoo.org/" title="Report issues and find common issues">Bugs</a></li> + <li><a href="http://forums.gentoo.org/" title="Discuss with the community">Forums</a></li> + <li><a href="http://packages.gentoo.org/" title="Find software for your Gentoo">Packages</a></li> + <li class="divider"></li> + <li><a href="http://archives.gentoo.org/" title="Read up on past discussions">Archives</a></li> + <li><a href="http://overlays.gentoo.org/" title="Collaborate on maintaining packages">Overlays</a></li> + <li><a href="http://planet.gentoo.org/" title="Find out what's going on in the developer community">Planet</a></li> + <li><a href="http://sources.gentoo.org/" title="Browse our source code">Sources</a></li> + </ul> + </li> + {% if user.is_authenticated %} + <li class="divider-vertical"></li> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ user }}<b class="caret"></b></a> <ul class="dropdown-menu"> - <li><a href="http://www.gentoo.org/">gentoo.org</a></li> - <li><a href="http://wiki.gentoo.org/" title="Find and contribute documentation">Wiki</a></li> - <li><a href="https://bugs.gentoo.org/" title="Report issues and find common issues">Bugs</a></li> - <li><a href="http://forums.gentoo.org/" title="Discuss with the community">Forums</a></li> - <li><a href="http://packages.gentoo.org/" title="Find software for your Gentoo">Packages</a></li> - <li class="divider"></li> - <li><a href="http://archives.gentoo.org/" title="Read up on past discussions">Archives</a></li> - <li><a href="http://overlays.gentoo.org/" title="Collaborate on maintaining packages">Overlays</a></li> - <li><a href="http://planet.gentoo.org/" title="Find out what's going on in the developer community">Planet</a></li> - <li><a href="http://sources.gentoo.org/" title="Browse our source code">Sources</a></li> + <li><a href="/" title="View Profile">View Profile</a></li> + <li><a href="#" title="Edit Profile">Edit Profile</a></li> + <li><a href="#" title="Invite others">Invite</a></li> + <li><a href="/logout/" title="Logout">Logout</a></li> </ul> - </li> - </ul> + </li> + {% endif %} + </ul> </div> </div> </div> diff --git a/okupy/templates/devlist.html b/okupy/templates/devlist.html new file mode 100644 index 0000000..93cee67 --- /dev/null +++ b/okupy/templates/devlist.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} +{% block content %} +<div class="hero-unit"> + <h1>Developers List</h1> + <p>List of active Gentoo developers.</p> +</div> +<p> +<div class="row"> + <div class="span12"> + <h2>Developer List</h2><br /> + <table class="table table-striped sortable" > + <tr> + <td class="infohead"><b>Username</b></td> + <td class="infohead"><b>Name</b></td> + <td class="infohead"><b>GPG key</b></td> + <td class="infohead"><b>Location</b></td> + <td class="infohead"><b>Areas of responsibility</b></td> + </tr> + <tr> + <td style="color:#5c4f85;"><b>mgorny</b></td> + <td>Michał Górny</td> + <td>0xDF84256885283521</td> + <td><a href="devmap.xml?dev=mgorny">near Poznan, Poland</a></td> + <td class="tableinfo">-</td> + </tr> + <tr> + <td class="infohead" style="color:#5c4f85;"><b>tampakrap</b></td> + <td class="tableinfo">Theo Chatzimichos</td> + <td class="tableinfo">0x57DC0078</td> + <td class="tableinfo"><a href="devmap.xml?dev=tampakrap">Larissa, Greece</a></td> + <td class="tableinfo">Infrastructure</td> + </tr> + <tr> + <td class="infohead" style="color:#5c4f85;"><b>dastergon</b></td> + <td class="tableinfo">Pavlos Ratis</td> + <td class="tableinfo">0x3A051746</td> + <td class="tableinfo">Serres, Greece</td> + <td class="tableinfo">kde</td> + </tr> + </table> + </div> +</div> +</p> +{% endblock %} + +{# vim:se fileencoding=utf8 et ts=4 sts=4 sw=4 ft=htmldjango : #} diff --git a/okupy/templates/index.html b/okupy/templates/index.html index 93cee67..eec6d06 100644 --- a/okupy/templates/index.html +++ b/okupy/templates/index.html @@ -1,46 +1,48 @@ {% extends "base.html" %} + {% block content %} -<div class="hero-unit"> - <h1>Developers List</h1> - <p>List of active Gentoo developers.</p> -</div> -<p> -<div class="row"> - <div class="span12"> - <h2>Developer List</h2><br /> - <table class="table table-striped sortable" > - <tr> - <td class="infohead"><b>Username</b></td> - <td class="infohead"><b>Name</b></td> - <td class="infohead"><b>GPG key</b></td> - <td class="infohead"><b>Location</b></td> - <td class="infohead"><b>Areas of responsibility</b></td> - </tr> - <tr> - <td style="color:#5c4f85;"><b>mgorny</b></td> - <td>Michał Górny</td> - <td>0xDF84256885283521</td> - <td><a href="devmap.xml?dev=mgorny">near Poznan, Poland</a></td> - <td class="tableinfo">-</td> - </tr> - <tr> - <td class="infohead" style="color:#5c4f85;"><b>tampakrap</b></td> - <td class="tableinfo">Theo Chatzimichos</td> - <td class="tableinfo">0x57DC0078</td> - <td class="tableinfo"><a href="devmap.xml?dev=tampakrap">Larissa, Greece</a></td> - <td class="tableinfo">Infrastructure</td> - </tr> - <tr> - <td class="infohead" style="color:#5c4f85;"><b>dastergon</b></td> - <td class="tableinfo">Pavlos Ratis</td> - <td class="tableinfo">0x3A051746</td> - <td class="tableinfo">Serres, Greece</td> - <td class="tableinfo">kde</td> - </tr> - </table> +<div id="pageRow" class="container"> + <div class="row"> + <div id="page" class="span10"> + <div class="row-fluid"> + <p> + <div class="span9"> + <h3>Personal Information</h3><br /> + <table class="table table-bordered table-striped table-condensed fixed-cell" id="yw0"> + {% for key,attr in ldap_personal_info.items %} + <tr class={% cycle 'odd' 'even' %}><th>{{ key }}</th><td>{{ attr }}</td></tr> + {% endfor %} + </table> + </p> + </div> + </div> + <div class="row-fluid"> + <p> + <div class="span9"> + <h3>Contact Information</h3><br /> + <table class="table table-bordered table-striped table-condensed fixed-cell" id="yw1"> + {% for key,attr in ldap_contact_info.items %} + <tr class={% cycle 'odd' 'even' %}><th>{{ key }}</th><td>{{ attr }}</td></tr> + {% endfor %} + </table> + </div> + </p> + </div> + <div class="row-fluid"> + <p> + <div class="span9"> + <h3>Gentoo related Information</h3><br /> + <table class="table table-bordered table-striped table-condensed fixed-cell" id="yw1"> + {% for key,attr in ldap_gentoo_info.items %} + <tr class={% cycle 'odd' 'even' %}><th>{{ key }}</th><td>{{ attr }}</td></tr> + {% endfor %} + </table> + </div> + </p> + </div> + </div> </div> </div> -</p> {% endblock %} {# vim:se fileencoding=utf8 et ts=4 sts=4 sw=4 ft=htmldjango : #} diff --git a/okupy/tests/__init__.py b/okupy/tests/__init__.py index f52534a..e69de29 100644 --- a/okupy/tests/__init__.py +++ b/okupy/tests/__init__.py @@ -1,2 +0,0 @@ -# vim:fileencoding=utf8:et:ts=4:sts=4:sw=4:ft=python - diff --git a/okupy/tests/integration/index.py b/okupy/tests/integration/index.py index ebec9ba..7de50ef 100644 --- a/okupy/tests/integration/index.py +++ b/okupy/tests/integration/index.py @@ -5,12 +5,11 @@ from django.test.client import Client from mockldap import MockLdap from ...common.testcase import OkupyTestCase -from ..tests import example_directory class IndexTests(OkupyTestCase): @classmethod def setUpClass(cls): - cls.mockldap = MockLdap(example_directory) + cls.mockldap = MockLdap(settings.DIRECTORY) def setUp(self): self.client = Client() diff --git a/okupy/tests/integration/login.py b/okupy/tests/integration/login.py index 9c209d6..98e7a58 100644 --- a/okupy/tests/integration/login.py +++ b/okupy/tests/integration/login.py @@ -8,7 +8,6 @@ from django.test.client import Client from mockldap import MockLdap from ...common.testcase import OkupyTestCase -from ..tests import example_directory import mock @@ -18,7 +17,7 @@ class LoginTestsEmptyDB(OkupyTestCase): @classmethod def setUpClass(cls): - cls.mockldap = MockLdap(example_directory) + cls.mockldap = MockLdap(settings.DIRECTORY) def setUp(self): self.client = Client() @@ -85,18 +84,6 @@ class LoginTestsEmptyDB(OkupyTestCase): self.assertEqual(User.objects.count(), 0) self.mockldap.start() - def test_weird_account(self): - account = {'username': 'dreßler', 'password': 'password'} - response = self.client.post('/login/', account) - self.assertRedirects(response, '/') - user = User.objects.get(pk=1) - self.assertEqual(User.objects.count(), 1) - self.assertEqual(user.username, u'dreßler') - self.assert_(not user.has_usable_password()) - self.assertEqual(user.first_name, '') - self.assertEqual(user.last_name, '') - self.assertEqual(user.email, '') - @mock.patch("django.db.backends.util.CursorWrapper", cursor_wrapper) def test_no_database(self): response = self.client.post('/login/', self.account) @@ -123,7 +110,7 @@ class LoginTestsOneAccountInDB(OkupyTestCase): @classmethod def setUpClass(cls): - cls.mockldap = MockLdap(example_directory) + cls.mockldap = MockLdap(settings.DIRECTORY) def setUp(self): self.client = Client() diff --git a/okupy/tests/integration/signup.py b/okupy/tests/integration/signup.py index 010bc4e..f5b5140 100644 --- a/okupy/tests/integration/signup.py +++ b/okupy/tests/integration/signup.py @@ -9,7 +9,6 @@ from mockldap import MockLdap from ...accounts.models import Queue from ...common.testcase import OkupyTestCase -from ..tests import example_directory import mock @@ -62,7 +61,7 @@ class SignupTestsOneAccountInQueue(OkupyTestCase): @classmethod def setUpClass(cls): - cls.mockldap = MockLdap(example_directory) + cls.mockldap = MockLdap(settings.DIRECTORY) def setUp(self): self.client = Client() @@ -92,7 +91,7 @@ class SignupTestsOneAccountInQueue(OkupyTestCase): self.assertEqual(ldap_account['givenName'][0], self.queued_account.first_name) self.assertEqual(ldap_account['sn'][0], self.queued_account.last_name) self.assertEqual(ldap_account['objectClass'], settings.AUTH_LDAP_USER_OBJECTCLASS) - self.assertEqual(ldap_account['uidNumber'][0], '1003') + self.assertEqual(ldap_account['uidNumber'][0], '1002') self.assertEqual(ldap_account['mail'][0], self.queued_account.email) data={'username': self.queued_account.username, 'password': 'queuedpass'} response = self.client.post('/login/', data) diff --git a/okupy/tests/settings.py b/okupy/tests/settings.py index 0081d53..fefbdab 100644 --- a/okupy/tests/settings.py +++ b/okupy/tests/settings.py @@ -12,6 +12,15 @@ ADMINS = ( ('admin', 'admin@example.com'), ) +# Instance name, used in: +# * log dir name: /var/log/okupy/${INSTANCE_NAME} +# * console logs: ${INSTANCE_NAME} ${IP} ${ERROR} +# * prefix of the notification mails: "[${INSTANCE_NAME}] ${TITLE}" +# * (production only): {MEDIA,STATIC}_ROOT: +# /var/www/${INSTANCE_NAME}/htdocs/{media,static} +# Examples: okupy, okupy-dev, identity.gentoo.org +INSTANCE_NAME = 'okupy-test' + DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', @@ -41,40 +50,21 @@ AUTH_LDAP_ADMIN_BIND_PASSWORD = '' AUTH_LDAP_USER_ATTR = 'uid' AUTH_LDAP_USER_BASE_DN = 'ou=people,o=test' -AUTH_LDAP_USER_DN_TEMPLATE = AUTH_LDAP_USER_ATTR + '=%(user)s,' + AUTH_LDAP_USER_BASE_DN AUTH_LDAP_PERMIT_EMPTY_PASSWORD = False AUTH_LDAP_START_TLS = False -#AUTH_LDAP_GROUP_SEARCH -#AUTH_LDAP_GROUP_TYPE -#AUTH_LDAP_REQUIRE_GROUP -#AUTH_LDAP_DENY_GROUP -#AUTH_LDAP_CACHE_GROUPS -#AUTH_LDAP_GROUP_CACHE_TIMEOUT -#AUTH_LDAP_FIND_GROUP_PERMS - -#AUTH_LDAP_USER_FLAGS_BY_GROUP = { - #'is_active': '', - #'is_staff': '', - #'is_superuser': '', -#} - -#AUTH_LDAP_PROFILE_FLAGS_BY_GROUP = {} - -AUTH_LDAP_USER_OBJECTCLASS = ["person", "organizationalPerson", "inetOrgPerson", "posixAccount"] +# objectClasses that are used by any user +AUTH_LDAP_USER_OBJECTCLASS = ['top', 'person', 'organizationalPerson', + 'inetOrgPerson', 'posixAccount', 'shadowAccount'] +# additional objectClasses that are used by developers +AUTH_LDAP_DEV_OBJECTCLASS = ['developerAccount'] # DEBUG Options: Select "True" for development use, "False" for production use DEBUG = False TEMPLATE_DEBUG = DEBUG -# Instance name, used in: -# * prefix of the notification mails: "[${INSTANCE_NAME}] ${TITLE}" -# * log dir name: /var/log/${INSTANCE_NAME} -# * console logs: ${INSTANCE_NAME} ${IP} ${ERROR} -INSTANCE_NAME = 'okupy-test' - # Hosts/domain names that are valid for this site; required if DEBUG is False # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts ALLOWED_HOSTS = [] @@ -173,6 +163,10 @@ INSTALLED_APPS = ( 'okupy.tests' ) +#Compressor settings +COMPRESS_ENABLED = False +COMPRESS_PARSER = 'compressor.parser.HtmlParser' + MANAGERS = ADMINS SITE_ID = 1 @@ -191,11 +185,11 @@ LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { - 'okupy': { + 'verbose': { 'format': '%(instance_name)s: %(levelname)s %(id_name)s %(client_ip)s Message: %(message)s File: %(module)s Function: %(funcName)s Line: %(lineno)d', }, - 'django_auth_ldap': { - 'format': 'django-auth-ldap: %(levelname)s Message: %(message)s', + 'simple': { + 'format': '$(instance_name)s: %(levelname)s Message: %(message)s File: %(module)s Function: %(funcName)s Line: %(lineno)d', }, }, 'filters': { @@ -210,18 +204,28 @@ LOGGING = { 'class': 'django.utils.log.AdminEmailHandler', 'include_html': True, }, + 'console_v': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'verbose', + }, + 'syslog_v': { + 'level': 'INFO', + 'class': 'logging.handlers.SysLogHandler', + 'formatter': 'verbose', + 'address': '/dev/log', + }, 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', - 'formatter': 'okupy', + 'formatter': 'simple', }, 'syslog': { 'level': 'INFO', 'class': 'logging.handlers.SysLogHandler', - 'formatter': 'okupy', + 'formatter': 'simple', 'address': '/dev/log', }, - }, 'loggers': { 'mail_okupy': { @@ -230,6 +234,14 @@ LOGGING = { 'propagate': True, }, 'okupy': { + 'handlers': ['console_v' if DEBUG else 'syslog_v'], + 'level': 'DEBUG' if DEBUG else 'INFO', + }, + 'okupy_simple': { + 'handlers': ['console' if DEBUG else 'syslog'], + 'level': 'DEBUG' if DEBUG else 'INFO', + }, + 'django_auth_ldap': { 'handlers': ['console' if DEBUG else 'syslog'], 'level': 'DEBUG' if DEBUG else 'INFO', }, @@ -241,15 +253,56 @@ LOGIN_REDIRECT_URL = '/' LOGOUT_URL = '/logout/' SESSION_EXPIRE_AT_BROWSER_CLOSE = True +AUTH_LDAP_USER_DN_TEMPLATE = AUTH_LDAP_USER_ATTR + '=%(user)s,' + AUTH_LDAP_USER_BASE_DN + # Custom authentication backend AUTHENTICATION_BACKENDS = ( 'django_auth_ldap.backend.LDAPBackend', 'django.contrib.auth.backends.ModelBackend', ) +# email sending variables regarding server authentication +# and configuration should be specified in settings/local.py EMAIL_SUBJECT_PREFIX = '[%s]: ' % INSTANCE_NAME -SERVER_EMAIL = 'no-reply@example.com' -#Compressor Settings -COMPRESS_ENABLED = False -COMPRESS_PARSER = 'compressor.parser.HtmlParser' +TEMPLATE_CONTEXT_PROCESSORS += ( + 'django.core.context_processors.request', +) + +# django-ldapdb settings +# they break the existing tests for unknown reason +# disabling them temporarily since they are not actually used yet +# needs to be fixed though asap +#DATABASES['ldap'] = { +# 'ENGINE': 'ldapdb.backends.ldap', +# 'NAME': AUTH_LDAP_SERVER_URI, +# 'USER': AUTH_LDAP_BIND_DN, +# 'PASSWORD': AUTH_LDAP_BIND_PASSWORD, +# 'CONNECTION_OPTIONS': AUTH_LDAP_CONNECTION_OPTIONS, +# 'TLS': AUTH_LDAP_START_TLS, +#} + +DATABASE_ROUTERS = ['ldapdb.router.Router'] + +DIRECTORY = { + "uid=alice,ou=people,o=test": { + "uid": ["alice"], + "userPassword": ['{CRYPT}$1$lO/RU6zz$2fJCOwurxBtCqdImkoLQo1'], + "objectClass": AUTH_LDAP_USER_OBJECTCLASS + AUTH_LDAP_DEV_OBJECTCLASS, + "uidNumber": ["1000"], + "gidNumber": ["1000"], + "givenName": ["Alice"], + "sn": ["Adams"], + "mail": ["alice@test.com"], + }, + "uid=bob,ou=people,o=test": { + "uid": ["bob"], + "userPassword": ['{CRYPT}$1$eFSQMJY6$8y.WUL/ONeEarVXqeCIbH.'], + "objectClass": AUTH_LDAP_USER_OBJECTCLASS, + "uidNumber": ["1001"], + "gidNumber": ["50"], + "givenName": ["Robert"], + "sn": ["Barker"], + "mail": ["bob@test.com"], + } +} diff --git a/okupy/tests/tests.py b/okupy/tests/tests.py index 4bf6de7..38d660f 100644 --- a/okupy/tests/tests.py +++ b/okupy/tests/tests.py @@ -1,38 +1,5 @@ # vim:fileencoding=utf8:et:ts=4:sts=4:sw=4:ft=python -example_directory = { - "uid=alice,ou=people,o=test": { - "uid": ["alice"], - "userPassword": ['{CRYPT}$1$lO/RU6zz$2fJCOwurxBtCqdImkoLQo1'], - "objectClass": ["person", "organizationalPerson", "inetOrgPerson", "posixAccount"], - "uidNumber": ["1000"], - "gidNumber": ["1000"], - "givenName": ["Alice"], - "sn": ["Adams"], - "mail": ["alice@test.com"], - }, - "uid=bob,ou=people,o=test": { - "uid": ["bob"], - "objectClass": ["person", "organizationalPerson", "inetOrgPerson", "posixAccount"], - "userPassword": ['{CRYPT}$1$eFSQMJY6$8y.WUL/ONeEarVXqeCIbH.'], - "uidNumber": ["1001"], - "gidNumber": ["50"], - "givenName": ["Robert"], - "sn": ["Barker"], - "mail": ["bob@test.com"], - }, - u"uid=dreßler,ou=people,o=test".encode('utf-8'): { - "uid": [u"dreßler".encode('utf-8')], - "objectClass": ["person", "organizationalPerson", "inetOrgPerson", "posixAccount"], - "userPassword": ['{CRYPT}$1$kQ3GmP3k$oKSdmDpdepvrni/JQQ4Ri.'], - "uidNumber": ["1002"], - "gidNumber": ["50"], - "givenName": ["Wolfgang"], - "sn": [u"Dreßler".encode('utf-8')], - "mail": ["dressler@test.com"], - } -} - # run tests modules from .integration.index import * from .integration.login import * diff --git a/requirements.txt b/requirements.txt index b966c1c..e6d20ae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ django>=1.5 django-auth-ldap>=1.1.4 django-compressor>=1.3 +git+https://github.com/tampakrap/django-ldapdb@okupy#egg=django-ldapdb edpwd>=0.0.7 mock>=1.0.1 hg+https://bitbucket.org/psagers/mockldap#egg=mockldap @@ -3,7 +3,6 @@ from setuptools import setup, find_packages import okupy -import os setup( name='okupy', @@ -13,7 +12,7 @@ setup( author_email='identity@gentoo.org', url='http://github.com/gentoo/identity.gentoo.org', description='Django LDAP webUI and OpenID provider for the Gentoo Linux project', - long_description=open(os.path.join(os.path.dirname(__file__), 'README.md')).read(), + long_description=open('README.md').read(), keywords='django, ldap, gentoo', packages=find_packages(), include_package_data=True, @@ -31,11 +30,13 @@ setup( ], dependency_links=[ 'https://bitbucket.org/psagers/mockldap/get/default.tar.gz#egg=mockldap', + 'https://github.com/tampakrap/django-ldapdb/archive/okupy.tar.gz#egg=django-ldapdb', ], install_requires=[ 'django>=1.5', 'django-auth-ldap>=1.1.4', 'django-compressor>=1.3', + 'django-ldapdb', 'edpwd>=0.0.7', 'passlib>=1.6.1', 'python-ldap>=2.4.10', |