diff options
author | Leif Johansson <leifj@sunet.se> | 2011-09-20 11:01:05 +0200 |
---|---|---|
committer | Leif Johansson <leifj@sunet.se> | 2011-09-20 11:01:05 +0200 |
commit | bc0b2364b1a22ecc9662ddfce1a4bd314f38f79b (patch) | |
tree | f2b2446f44cc276e12a7e1ea0749822f98464893 /coip/apps/userprofile | |
parent | cd364fba4c45f80cfd326f786c3d4901b2d464c2 (diff) |
removed entity model, celery
Diffstat (limited to 'coip/apps/userprofile')
-rw-r--r-- | coip/apps/userprofile/forms.py | 30 | ||||
-rw-r--r-- | coip/apps/userprofile/models.py | 43 | ||||
-rw-r--r-- | coip/apps/userprofile/tasks.py | 48 | ||||
-rw-r--r-- | coip/apps/userprofile/views.py | 176 |
4 files changed, 260 insertions, 37 deletions
diff --git a/coip/apps/userprofile/forms.py b/coip/apps/userprofile/forms.py new file mode 100644 index 0000000..dd42ccf --- /dev/null +++ b/coip/apps/userprofile/forms.py @@ -0,0 +1,30 @@ +''' +Created on Aug 19, 2011 + +@author: leifj +''' + +from form_utils.forms import BetterForm +from django.forms.fields import CharField +from django.forms.widgets import Textarea + + +class AddSSHKeyForm(BetterForm): + sshkey = CharField(label='SSH Key',widget=Textarea(attrs={'cols': 60, 'rows': 6})) + class Meta: + fieldsets = [ + ('key',{'fields':['sshkey'], + 'legend': 'Please provide your SSH key.', + 'description': 'Cut and paste your SSH key into the text field. Note that you should only submit the .pub-file and never the private key.', + 'classes': ['step','submit_step']}) + ] + +class AddCertificateForm(BetterForm): + certificate = CharField(label='PEM X509 Certificate',widget=Textarea(attrs={'cols': 60, 'rows': 6})) + class Meta: + fieldsets = [ + ('key',{'fields':['certificate'], + 'legend': 'Please provide your personal certificate.', + 'description': 'Cut and paste your PEM format X509 Certificate into the text field.', + 'classes': ['step','submit_step']}) + ]
\ No newline at end of file diff --git a/coip/apps/userprofile/models.py b/coip/apps/userprofile/models.py index 6e2364a..315097d 100644 --- a/coip/apps/userprofile/models.py +++ b/coip/apps/userprofile/models.py @@ -7,15 +7,14 @@ from django.db import models from django.contrib.auth.models import User from django.dispatch.dispatcher import receiver from django.db.models.signals import post_save -from coip.apps.name.models import Name, lookup -from coip.apps.membership.models import add_member +from coip.apps.name.models import Name class UserProfile(models.Model): INTERNAL = 0 ENTITY = 1 SSHKEY = 2 - GRIDCERT = 3 + X509 = 3 FEDID = 4 # @@ -24,19 +23,20 @@ class UserProfile(models.Model): # 1 (entity) - username=entity:sha1(entityID), profile.display_name = display or entityID, profile.identifier = ssh key # 2 (sshkey) - username=sshkey:fingerprint, profile.display_name = key alias or "SSH Key with fingerprint ..." # 3 (gridcert) - username=x509:sha1-fingerprint, profile.display_name = dn, profile.identifier = PEM - # 4 (fedid) - username=eppn or equiv (REMOTE_USER),profile.display_name = display or eppn, profile.identifier = eppn, profile.authority = idp + # 4 (fedid) - username=eppn or equiv (REMOTE_USER),profile.display_name = display or eppn, profile.identifier = eppn, profile.idp = idp # - user = models.OneToOneField(User) + user = models.OneToOneField(User,related_name='profile') home = models.ForeignKey(Name,blank=True,null=True) display_name = models.CharField(max_length=255,blank=True,null=True) - type = models.SmallIntegerField(choices=((ENTITY,"Connected Service"), + type = models.SmallIntegerField(default=INTERNAL, + choices=((ENTITY,"Service"), (INTERNAL,"System User"), - (SSHKEY,"SSH Key"), - (GRIDCERT,"eScience Certificate"), + (SSHKEY,"Personal SSH Key"), + (X509,"Personal eScience Certificate"), (FEDID,"User Identity"))) - authority = models.CharField(max_length=255,blank=True,null=True) + idp = models.CharField(max_length=255,blank=True,null=True) identifier = models.CharField(max_length=1023,blank=True,null=True) timecreated = models.DateTimeField(auto_now_add=True) @@ -45,30 +45,7 @@ class UserProfile(models.Model): def __unicode__(self): return "%s [%s] - %s" % (self.identifier,self.user.username,self.display_name) -def import_sshkey(keyfile): - fingerprint = "xxx" - user = User.objects.get_or_create(username="sshkey:%s" % fingerprint) - -def home_name(user,short=None,autocreate=False): - if short == None: - short = user.username - urn = lookup("urn",True) - anyuser = lookup("system:anyuser",True) - urn.setacl(anyuser,'rl') - - home = lookup('user:'+user.username,autocreate=autocreate) - add_member(home,user,hidden=True) - home.setpacl(home, "rwlida") - home.setacl(home,"rwlia") #don't allow users to delete or reset acls on their home, nor invite members - that would be confusing as hell - home.short = short - home.save() - - return home - @receiver(post_save,sender=User) def _create_profile(sender,**kwargs): user = kwargs['instance'] - profile,created = UserProfile.objects.get_or_create(user=user) - if profile.home == None: - profile.home = home_name(user,autocreate=True) - profile.save()
\ No newline at end of file + UserProfile.objects.get_or_create(user=user)
\ No newline at end of file diff --git a/coip/apps/userprofile/tasks.py b/coip/apps/userprofile/tasks.py new file mode 100644 index 0000000..175c8a5 --- /dev/null +++ b/coip/apps/userprofile/tasks.py @@ -0,0 +1,48 @@ +''' +Created on Aug 18, 2011 + +@author: leifj +''' +from coip.settings import METADATA +from lxml import etree +from hashlib import sha1 +from django.contrib.auth.models import User +from coip.apps.name.models import lookup +from coip.apps.userprofile.models import UserProfile +from coip.apps.membership.models import add_member +from celery.decorators import periodic_task +from celery.schedules import crontab + +@periodic_task(run_every=crontab(hour="*", minute="*/3", day_of_week="*")) +def import_metadata(): + doc = etree.parse(METADATA) + ns = {'md': 'urn:oasis:names:tc:SAML:2.0:metadata', + 'xml': 'http://www.w3.org/XML/1998/namespace'} + for e in doc.xpath("md:EntityDescriptor",namespaces=ns): + entityId = e.get('entityID') + print entityId + display = entityId + x = e.xpath("md:OrganizationDisplayName",namespaces=ns) + if x: + display = x[0] + + username = "entity:%s" % sha1(entityId).hexdigest() + (user,created) = User.objects.get_or_create(username=username) + save = created + profile = user.get_profile() + + if created: + anyuser = lookup("system:anyuser") + anyentity = lookup("system:anyentity",True) + anyentity.setacl(anyuser, "rl") + profile.type = UserProfile.ENTITY + profile.home = anyentity + add_member(anyentity, user) + + if display != profile.display_name: + profile.display_name = display + save = True + + if save: + user.save() + profile.save()
\ No newline at end of file diff --git a/coip/apps/userprofile/views.py b/coip/apps/userprofile/views.py index a7b15e8..b1be4c1 100644 --- a/coip/apps/userprofile/views.py +++ b/coip/apps/userprofile/views.py @@ -4,12 +4,93 @@ Created on Jul 6, 2010 @author: leifj ''' from django.contrib.auth.decorators import login_required -from coip.multiresponse import respond_to, json_response -from coip.apps.membership.models import Membership +from coip.multiresponse import respond_to, json_response, render403 +from coip.apps.membership.models import Membership, add_member from django.core.exceptions import ObjectDoesNotExist -from coip.apps.name.models import NameLink +from coip.apps.name.models import NameLink, lookup, Name from django.contrib.auth.models import User from django.shortcuts import get_object_or_404 +from coip.apps.userprofile.models import UserProfile +from django.db.models import Q +from coip.extensions.templatetags.userdisplay import userdisplay +import subprocess +import re +from tempfile import NamedTemporaryFile +from coip.apps.userprofile.forms import AddSSHKeyForm, AddCertificateForm +from django.http import HttpResponseRedirect + +def _add_sshkey(name,keyfile): + p = subprocess.Popen(['ssh-keygen','-l','-f',keyfile.name],stdout=subprocess.PIPE,stderr=subprocess.PIPE) + (out,err) = p.communicate() + code = p.wait() + if code != 0: + raise Exception("Unable to fingerprint ssh key: %d - %s" % (code,err)) + parts = out.split() + fp = re.sub(':','',parts[1]) + + p = subprocess.Popen(['ssh-keygen','-e','-f',keyfile.name],stdout=subprocess.PIPE,stderr=subprocess.PIPE) + (out,err) = p.communicate() + code = p.wait() + if code != 0: + raise Exception("Unable to import ssh key: %d - %s" % (code,err)) + id = out + + username = "sshkey:%s" % fp + user,created = User.objects.get_or_create(username=username) + profile = user.get_profile() + if created: + profile.type = UserProfile.SSHKEY + profile.home = name + profile.display = "SSH Key (%s)" % (fp) + profile.identifier = id + + add_member(profile.home,user) + profile.save() + + +def _add_gridcert(name,keyfile): + p = subprocess.Popen(['openssl','x509','-noout','-fingerprint','-sha1','-in',keyfile.name],stdout=subprocess.PIPE,stderr=subprocess.PIPE) + (out,err) = p.communicate() + code = p.wait() + if code != 0: + raise Exception("Unable to fingerprint X509 certificate: %d - %s" % (code,err)) + parts = out.split('=') + fp = re.sub(':','',parts[1].lower()) + + p = subprocess.Popen(['openssl','x509','-outform','PEM','-in',keyfile.name],stdout=subprocess.PIPE,stderr=subprocess.PIPE) + (out,err) = p.communicate() + code = p.wait() + if code != 0: + raise Exception("Unable to import X509 certificate: %d - %s" % (code,err)) + id = out + + username = "x509:%s" % fp + user,created = User.objects.get_or_create(username=username) + profile = user.get_profile() + if created: + profile.type = UserProfile.X509 + profile.home = name + profile.display = "X509 Certificate (%s)" % (fp) + profile.identifier = id + + add_member(profile.home,user) + profile.save() + +def home_name(user,short=None,autocreate=False): + if short == None: + short = user.username + urn = lookup("urn",True) + anyuser = lookup("system:anyuser",True) + urn.setacl(anyuser,'rl') + + home = lookup('user:'+user.username,autocreate=autocreate) + add_member(home,user,hidden=True) + home.setpacl(home, "rwlida") + home.setacl(home,"rwlia") #don't allow users to delete or reset acls on their home, nor invite members - that would be confusing as hell + home.short = short + home.save() + + return home @login_required def home(request): @@ -19,16 +100,103 @@ def home(request): except ObjectDoesNotExist: pass + user = request.user + profile = user.get_profile() + if profile.home == None: + cn = user.get_full_name() + if not cn: + cn = user.username + profile.home = home_name(user, short=cn, autocreate=True) + names = [(link.src,link.data) for link in NameLink.objects.filter(dst__memberships__user=request.user,type=NameLink.access_control,data__contains='i').all()] return respond_to(request, {'text/html': 'apps/userprofile/home.html'},{'memberships': memberships,'names': names}) @login_required +def add_sshkey(request,id=None): + name = None + if id == None: + name = request.user.get_profile().home + else: + name = get_object_or_404(Name,pk=id) + if name == None: + return render403(request, "Homeless user.") + if not name.has_permission(request.user,'i'): + return render403(request,"You do not have permission to manage aliases here.") + if not name.parent or name.parent.value != 'user': + return render403(request,"This is the wrong place for that.") + + if request.method == 'POST': + form = AddSSHKeyForm(request.POST) + if form.is_valid(): + sshkey = form.cleaned_data['sshkey'] + keyfile = NamedTemporaryFile() + keyfile.write(sshkey) + keyfile.seek(0) + _add_sshkey(name, keyfile) + keyfile.close() + return HttpResponseRedirect("/user/home") + else: + form = AddSSHKeyForm() + + return respond_to(request,{'text/html':'apps/userprofile/sshkey.html'},{'form':form}) + +@login_required +def add_cert(request,id=None): + name = None + if id == None: + name = request.user.get_profile().home + else: + name = get_object_or_404(Name,pk=id) + if name == None: + return render403(request, "Homeless user.") + if not name.has_permission(request.user,'i'): + return render403(request,"You do not have permission to manage aliases here.") + if not name.parent or name.parent.value != 'user': + return render403(request,"This is the wrong place for that.") + + if request.method == 'POST': + form = AddCertificateForm(request.POST) + if form.is_valid(): + certificate = form.cleaned_data['certificate'] + keyfile = NamedTemporaryFile() + keyfile.write(certificate) + keyfile.seek(0) + _add_gridcert(name, keyfile) + keyfile.close() + return HttpResponseRedirect("/user/home") + else: + form = AddCertificateForm() + + return respond_to(request,{'text/html':'apps/userprofile/cert.html'},{'form':form}) + +@login_required +def add_alias(request,id=None): + name = None + if id == None: + name = request.user.get_profile().home + else: + name = get_object_or_404(Name,pk=id) + if name == None: + return render403(request, "Homeless user.") + if not name.has_permission(request.user,'i'): + return render403(request,"You do not have permission to manage aliases here.") + if not name.parent or name.parent.value != 'user': + return render403(request,"This is the wrong place for that.") + + return respond_to(request,{'text/html':'apps/userprofile/addalias.html'}) + +@login_required def search(request): list = [] if request.REQUEST.has_key('term'): term = request.REQUEST['term'] - list = [{'label': user.username,'value': user.id} for user in User.objects.filter(username__contains=term)] + list = [{'label': userdisplay(user),'value': user.id} + for user in User.objects.filter(Q(username__contains=term) | + Q(profile__display_name__contains=term) | + Q(profile__identifier__contains=term) | + Q(first_name__contains=term) | + Q(last_name__contains=term))] return json_response(list) @login_required |