From 2bdad0ae7a3a6e4ec5116becd39910388b679ed2 Mon Sep 17 00:00:00 2001 From: Leif Johansson Date: Thu, 4 Oct 2012 15:39:08 +0200 Subject: restructure --- meetingtools/apps/auth/__init__.py | 79 +++++++++++++++++ meetingtools/apps/auth/utils.py | 19 +++++ meetingtools/apps/auth/views.py | 169 +++++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 meetingtools/apps/auth/__init__.py create mode 100644 meetingtools/apps/auth/utils.py create mode 100644 meetingtools/apps/auth/views.py (limited to 'meetingtools/apps/auth') diff --git a/meetingtools/apps/auth/__init__.py b/meetingtools/apps/auth/__init__.py new file mode 100644 index 0000000..e69cc29 --- /dev/null +++ b/meetingtools/apps/auth/__init__.py @@ -0,0 +1,79 @@ +__author__ = 'leifj' + +from django.conf import settings +from saml2.config import SPConfig +import copy +from saml2 import BINDING_HTTP_POST, BINDING_HTTP_REDIRECT + +import logging +logging.basicConfig() +logger = logging.getLogger("djangosaml2") +logger.setLevel(logging.DEBUG) + +def asgard_sp_config(request=None): + host = "localhost" + if request is not None: + host = request.get_host().replace(":","-") + x= { + # your entity id, usually your subdomain plus the url to the metadata view + 'entityid': 'https://%s/saml2/sp/metadata' % host, + # directory with attribute mapping + "attribute_map_dir" : "%s/saml2/attributemaps" % settings.BASE_DIR, + # this block states what services we provide + 'service': { + # we are just a lonely SP + 'sp' : { + 'name': 'meetingtools', + 'endpoints': { + # url and binding to the assertion consumer service view + # do not change the binding osettingsr service name + 'assertion_consumer_service': [ + ('https://%s/saml2/sp/acs/' % host, + BINDING_HTTP_POST), + ], + # url and binding to the single logout service view + # do not change the binding or service name + 'single_logout_service': [ + ('https://%s/saml2/sp/ls/' % host, + BINDING_HTTP_REDIRECT), + ], + }, + # attributes that this project need to identify a user + 'required_attributes': ['eduPersonPrincipalName','displayName','eduPersonScopedAffiliation'], + } + }, + + # where the remote metadata is stored + #'metadata': { 'remote': [{'url':'http://md.swamid.se/md/swamid-idp.xml', + # 'cert':'%s/saml2/credentials/md-signer.crt' % settings.BASE_DIR}] }, + 'metadata': {'local': [settings.SAML_METADATA_FILE]}, + + # set to 1 to output debugging information + 'debug': 1, + + # certificate + "key_file" : "%s/%s.key" % (settings.SSL_KEY_DIR,host), + "cert_file" : "%s/%s.crt" % (settings.SSL_CRT_DIR,host), + # own metadata settings + 'contact_person': [ + {'given_name': 'Leif', + 'sur_name': 'Johansson', + 'company': 'NORDUnet', + 'email_address': 'leifj@nordu.net', + 'contact_type': 'technical'}, + {'given_name': 'Johan', + 'sur_name': 'Berggren', + 'company': 'NORDUnet', + 'email_address': 'jbn@nordu.net', + 'contact_type': 'technical'}, + ], + # you can set multilanguage information here + 'organization': { + 'name': [('NORDUNet', 'en')], + 'display_name': [('NORDUnet A/S', 'en')], + 'url': [('http://www.nordu.net', 'en')], + } + } + c = SPConfig() + c.load(copy.deepcopy(x)) + return c diff --git a/meetingtools/apps/auth/utils.py b/meetingtools/apps/auth/utils.py new file mode 100644 index 0000000..1a0174c --- /dev/null +++ b/meetingtools/apps/auth/utils.py @@ -0,0 +1,19 @@ +''' +Created on Jul 7, 2010 + +@author: leifj +''' +from uuid import uuid4 + +def nonce(): + return uuid4().hex + +def anonid(): + return uuid4().urn + +def groups(request): + groups = [] + if request.user.is_authenticated(): + groups = request.user.groups + + return groups \ No newline at end of file diff --git a/meetingtools/apps/auth/views.py b/meetingtools/apps/auth/views.py new file mode 100644 index 0000000..ee23df3 --- /dev/null +++ b/meetingtools/apps/auth/views.py @@ -0,0 +1,169 @@ +''' +Created on Jul 5, 2010 + +@author: leifj +''' +from django.http import HttpResponseRedirect +from django.contrib.auth.models import User, Group +import datetime +from django.views.decorators.cache import never_cache +import logging +from meetingtools.apps.userprofile.models import UserProfile +from meetingtools.multiresponse import redirect_to, make_response_dict +from meetingtools.ac import ac_api_client +from django.shortcuts import render_to_response +from django.contrib import auth +from django_co_connector.models import co_import_from_request, add_member,remove_member +from meetingtools.apps.cluster.models import acc_for_user +from django.conf import settings + +def meta(request,attr): + v = request.META.get(attr) + if not v: + return None + values = filter(lambda x: x != "(null)",v.split(";")) + return values; + +def meta1(request,attr): + v = meta(request,attr) + if v: + return str(v[0]).decode('utf-8') + else: + return None + +def _localpart(a): + if hasattr(a,'name'): + a = a.name + if '@' in a: + (lp,dp) = a.split('@') + a = lp + return a + +def _is_member_or_employee_old(affiliations): + lpa = map(_localpart,affiliations) + return 'student' in lpa or 'staff' in lpa or ('member' in lpa and not 'student' in lpa) + +def _is_member_or_employee(user): + lpa = map(_localpart,user.groups.all()) + return 'student' in lpa or 'staff' in lpa or ('member' in lpa and not 'student' in lpa) + +@never_cache +def logout(request): + auth.logout(request) + return HttpResponseRedirect('/Shibboleth.sso/Logout') + +@never_cache +def login(request): + return render_to_response('apps/auth/login.html',make_response_dict(request,{'next': request.REQUEST.get("next")})); + +def join_group(group,**kwargs): + user = kwargs['user'] + acc = acc_for_user(user) + with ac_api_client(acc) as api: + principal = api.find_principal("login", user.username, "user") + if principal: + gp = api.find_group(group.name) + if gp: + api.add_member(principal.get('principal-id'),gp.get('principal-id')) + +def leave_group(group,**kwargs): + user = kwargs['user'] + acc = acc_for_user(user) + with ac_api_client(acc) as api: + principal = api.find_principal("login", user.username, "user") + if principal: + gp = api.find_group(group.name) + if gp: + api.remove_member(principal.get('principal-id'),gp.get('principal-id')) + +add_member.connect(join_group,sender=Group) +remove_member.connect(leave_group,sender=Group) + +def accounts_login_federated(request): + if request.user.is_authenticated(): + profile,created = UserProfile.objects.get_or_create(user=request.user) + if created: + profile.identifier = request.user.username + profile.user = request.user + profile.save() + + update = False + fn = meta1(request,'givenName') + ln = meta1(request,'sn') + cn = meta1(request,'cn') + if not cn: + cn = meta1(request,'displayName') + logging.debug("cn=%s" % cn) + if not cn and fn and ln: + cn = "%s %s" % (fn,ln) + if not cn: + cn = profile.identifier + + mail = meta1(request,'mail') + + idp = meta1(request,'Shib-Identity-Provider') + + for attrib_name, meta_value in (('display_name',cn),('email',mail),('idp',idp)): + attrib_value = getattr(profile, attrib_name) + if meta_value and not attrib_value: + setattr(profile,attrib_name,meta_value) + update = True + + if request.user.password == "": + request.user.password = "(not used for federated logins)" + update = True + + if update: + request.user.save() + + # Allow auto_now to kick in for the lastupdated field + #profile.lastupdated = datetime.datetime.now() + profile.save() + + next = request.session.get("after_login_redirect", None) + if not next and request.GET.has_key('next'): + next = request.GET['next'] + else: + next = settings.DEFAULT_URL + + acc = acc_for_user(request.user) + with ac_api_client(request) as api: + # make sure the principal is created before shooting off + principal = api.find_or_create_principal("login", request.user.username, "user", + {'type': "user", + 'has-children': "0", + 'first-name':fn, + 'last-name':ln, + 'email':mail, + 'send-email': 0, + 'login':request.user.username, + 'ext-login':request.user.username}) + + + + co_import_from_request(request) + + member_or_employee = _is_member_or_employee(request.user) + for gn in ('live-admins','seminar-admins'): + group = api.find_builtin(gn) + if group: + api.add_remove_member(principal.get('principal-id'),group.get('principal-id'),member_or_employee) + + #(lp,domain) = uid.split('@') + #for a in ('student','employee','member'): + # affiliation = "%s@%s" % (a,domain) + # group = connect_api.find_or_create_principal('name',affiliation,'group',{'type': 'group','has-children':'1','name': affiliation}) + # member = affiliation in affiliations + # connect_api.add_remove_member(principal.get('principal-id'),group.get('principal-id'),member) + + #for e in epe: + # group = connect_api.find_or_create_principal('name',e,'group',{'type': 'group','has-children':'1','name': e}) + # if group: + # connect_api.add_remove_member(principal.get('principal-id'),group.get('principal-id'),True) + + if next is not None: + return redirect_to(next) + else: + pass + + return redirect_to(settings.LOGIN_URL) -- cgit v1.1