summaryrefslogtreecommitdiff
path: root/coip/apps
diff options
context:
space:
mode:
Diffstat (limited to 'coip/apps')
-rw-r--r--coip/apps/auth/views.py8
-rw-r--r--coip/apps/entity/__init__.py0
-rw-r--r--coip/apps/entity/admin.py4
-rw-r--r--coip/apps/entity/models.py32
-rw-r--r--coip/apps/membership/forms.py23
-rw-r--r--coip/apps/membership/models.py64
-rw-r--r--coip/apps/membership/views.py77
-rw-r--r--coip/apps/name/models.py8
-rw-r--r--coip/apps/opensocial/people.py2
-rw-r--r--coip/apps/userprofile/forms.py30
-rw-r--r--coip/apps/userprofile/models.py43
-rw-r--r--coip/apps/userprofile/tasks.py48
-rw-r--r--coip/apps/userprofile/views.py176
13 files changed, 313 insertions, 202 deletions
diff --git a/coip/apps/auth/views.py b/coip/apps/auth/views.py
index 18b4430..be816d1 100644
--- a/coip/apps/auth/views.py
+++ b/coip/apps/auth/views.py
@@ -4,14 +4,8 @@ Created on Jul 5, 2010
@author: leifj
'''
from django.http import HttpResponseRedirect
-from coip.apps.userprofile.models import UserProfile, home_name
-from django.contrib.auth.models import User
-from coip.apps.auth.utils import anonid
-from coip.apps.name.models import lookup
-import datetime
+from coip.apps.userprofile.views import home_name
from django.views.decorators.cache import never_cache
-import logging
-from coip.apps.membership.models import add_member
def meta(request,attr):
v = request.META.get(attr)
diff --git a/coip/apps/entity/__init__.py b/coip/apps/entity/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/coip/apps/entity/__init__.py
+++ /dev/null
diff --git a/coip/apps/entity/admin.py b/coip/apps/entity/admin.py
deleted file mode 100644
index 516e153..0000000
--- a/coip/apps/entity/admin.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from django.contrib import admin
-from coip.apps.entity.models import Entity
-
-admin.site.register(Entity) \ No newline at end of file
diff --git a/coip/apps/entity/models.py b/coip/apps/entity/models.py
deleted file mode 100644
index 06f89fe..0000000
--- a/coip/apps/entity/models.py
+++ /dev/null
@@ -1,32 +0,0 @@
-'''
-Created on Feb 23, 2011
-
-@author: leifj
-'''
-
-from django.db import models
-import re
-from pprint import pformat
-import logging
-from django.db.models.fields import CharField, SmallIntegerField
-
-class Entity(models.Model):
-
- SP = 0
- IDP = 1
- OTHER = 2
-
- entityId = CharField(max_length=1024,unique=True,editable=False)
- display_name = CharField(max_length=1024,blank=True,null=True)
- type = SmallIntegerField(blank=True,null=True,editable=False,choices=((IDP,"Identity Provider"),(SP,"Service Provider"),(OTHER,"Other Entity")))
- timecreated = models.DateTimeField(auto_now_add=True)
- lastupdated = models.DateTimeField(auto_now=True)
-
- def __unicode__(self):
- return "%s (%s)" % (self.name(),self.type)
-
- def name(self):
- if self.display_name:
- return self.display_name
- else:
- return self.entityId \ No newline at end of file
diff --git a/coip/apps/membership/forms.py b/coip/apps/membership/forms.py
index d44bb3b..b935e35 100644
--- a/coip/apps/membership/forms.py
+++ b/coip/apps/membership/forms.py
@@ -5,28 +5,21 @@ Created on Jun 23, 2010
'''
from coip.apps.membership.models import Membership
from form_utils.forms import BetterModelForm
-from django.forms.fields import ChoiceField, CharField
-from django.forms.widgets import Select, HiddenInput
+from django.forms.fields import CharField
+from django.forms.widgets import HiddenInput, TextInput
class MembershipForm(BetterModelForm):
- type = ChoiceField(choices=(("user","I'm adding a user to the group"),("entity","I'm adding a relying party (SP or IdP) to the group")), label="", widget=Select(attrs={'class':'link'}), required=False, initial="user")
- username = CharField(label="Username")
+ username = CharField(label="User")
class Meta:
model = Membership
- fields = ['entity','user']
+ fields = ['user']
widgets = {
- 'user': HiddenInput()
+ 'user': HiddenInput(),
+ 'username': TextInput(attrs={'size': 40})
}
- fieldsets = [('type', {'fields': ['type'],
- 'legend': 'Which type of member are you adding to the group?',
- 'description': 'Groups can consist of users and/or relying partys. Adding a relying party to a group limits can be useful if you want to limit the visibility of your group. This is an advanced option and you should know what you are doing.',
- 'classes': ['step']}),
- ('entity', {'fields': ['entity'],
- 'legend': 'Adding a federation entity to the group',
- 'description': 'Select the relying party you wish to add to the group.',
- 'classes': ['step','submit_step']}),
+ fieldsets = [
('user', {'fields': ['user','username'],
'legend': 'Adding a user to the group',
- 'description': 'Provide the federation identifier of the user you wish to join. That user must have already logged in at least once. To add a user that has not yet logged in, send an invitation instead.',
+ 'description': 'Start typing to find the user to add. That user must have already logged in at least once. To add a user that has not yet logged in, send an invitation instead.',
'classes': ['step','submit_step']})
] \ No newline at end of file
diff --git a/coip/apps/membership/models.py b/coip/apps/membership/models.py
index b19c04a..71143b5 100644
--- a/coip/apps/membership/models.py
+++ b/coip/apps/membership/models.py
@@ -7,18 +7,23 @@ from django.db import models
from django.contrib.auth.models import User
from coip.apps.name.models import Name
import datetime
-import logging
-from coip.apps.entity.models import Entity
import tagging
from django.core.mail import send_mail
from coip.settings import NOREPLY
+from coip.extensions.templatetags.userdisplay import userdisplay
+from coip.apps.userprofile.models import UserProfile
+
+STATUS = {UserProfile.INTERNAL:'internal',
+ UserProfile.ENTITY:'entity',
+ UserProfile.SSHKEY:'sshkey',
+ UserProfile.X509:'certificate',
+ UserProfile.FEDID:'fedid'}
class Membership(models.Model):
'''
Membership in a namespace/group
'''
- user = models.ForeignKey(User,blank=True,null=True,related_name='memberships')
- entity = models.ForeignKey(Entity,blank=True,null=True,related_name='entity') # XXX should this be memberships too?
+ user = models.ForeignKey(User,related_name='memberships')
name = models.ForeignKey(Name,related_name='memberships')
enabled = models.BooleanField()
hidden = models.BooleanField()
@@ -27,12 +32,7 @@ class Membership(models.Model):
expires = models.DateTimeField(blank=True,null=True)
def __unicode__(self):
- who = "(unknown)"
- if self.user:
- who = self.user
- elif self.entity:
- who = self.entity
-
+ who = self.user
status = ""
if not self.enabled:
status = " (disabled)"
@@ -49,18 +49,15 @@ class Membership(models.Model):
return "active"
else:
return "inactive";
-
- def is_user(self):
- return self.user != None
- def is_entity(self):
- return self.entity != None
+ def type(self):
+ return STATUS[self.user.get_profile().type]
def send_notification(self,what):
if not self.user or not self.user.email:
return
-
- send_mail('You have been %s \'%s\'' % (what,self.name.short),
+
+ send_mail('%s have been %s \'%s\'' % (userdisplay(self.user),what,self.name.short),
'''
You have been %s \'%s\'.
@@ -74,41 +71,40 @@ To view information about \'%s\' open this link in your browser:
return
def add_member(name,member_name,hidden=False):
- if isinstance(member_name,User):
- (m,created) = Membership.objects.get_or_create(user=member_name,name=name)
- else:
- (m,created) = Membership.objects.get_or_create(entity=member_name,name=name)
-
+ (m,created) = Membership.objects.get_or_create(user=member_name,name=name)
if created or not m.enabled or m.hidden != hidden:
m.enabled = True
m.hidden = hidden
m.save()
+
+ if name.nmembers != -1:
+ name.nmembers = -1
+ name.save()
return m.send_notification("added to")
def disable_member(name,member_name):
- if isinstance(member_name,User):
- m = Membership.objects.get(name=name,user=member_name)
- else:
- m = Membership.objects.get(name=name,entity=member_name)
+ m = Membership.objects.get(name=name,user=member_name)
if m:
m.enabled = False
m.save()
m.send_notification("temporarily removed from")
+ if name.nmembers != -1:
+ name.nmembers = -1
+ name.save()
+
def remove_member(name,member_name):
- if isinstance(member_name,User):
- m = Membership.objects.get(name=name,user=member_name)
- else:
- m = Membership.objects.get(name=name,entity=member_name)
+ m = Membership.objects.get(name=name,user=member_name)
if m:
m.send_notification("removed from")
m.delete()
+
+ if name.nmembers != -1:
+ name.nmembers = -1
+ name.save()
def has_member(name,member_name):
- if isinstance(member_name,User):
- return Membership.objects.filter(name=name,user=member_name)
- else:
- return Membership.objects.filter(name=name,entity=member_name)
+ return Membership.objects.filter(name=name,user=member_name)
tagging.register(Membership) \ No newline at end of file
diff --git a/coip/apps/membership/views.py b/coip/apps/membership/views.py
index 176f750..97c8c46 100644
--- a/coip/apps/membership/views.py
+++ b/coip/apps/membership/views.py
@@ -7,15 +7,11 @@ from django.shortcuts import get_object_or_404
from coip.apps.membership.models import Membership, add_member, remove_member
from coip.multiresponse import render403, respond_to
from django.contrib.auth.models import User
-from coip.apps.name.models import Name, lookup
+from coip.apps.name.models import Name
from django.http import HttpResponseRedirect
from django.core.exceptions import ObjectDoesNotExist
-from coip.apps.entity.models import Entity
from django.contrib.auth.decorators import login_required
from coip.apps.membership.forms import MembershipForm
-from coip.settings import METADATA
-from lxml import etree
-from pprint import pprint
def show(request,id):
membership = get_object_or_404(Membership,pk=id)
@@ -27,58 +23,6 @@ def show(request,id):
{'text/html': 'apps/membership/membership.html'},
{'membership': membership})
-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')
- display = entityId
- x = e.xpath("md:OrganizationDisplayName",namespaces=ns)
- if x:
- display = x[0]
-
- (entity,created) = Entity.objects.get_or_create(entityId=entityId)
- save = created
-
- if created:
- entity.type = Entity.OTHER
-
- x = e.xpath("md:SPSSODescriptor",namespaces=ns)
- if x:
- type = Entity.SP
- x = e.xpath("md:IDPSSODescriptor",namespaces=ns)
- if x:
- type = Entity.IDP
-
- if type != entity.type:
- entity.type = type
- save = True
-
- if display != entity.display_name:
- entity.display_name = display
- save = True
-
- if save:
- entity.save()
-
- anyuser = lookup("system:anyuser")
-
- anyentity = lookup("system:anyentity",True)
- anyentity.setacl(anyuser, "rl")
-
- anysp = lookup("system:anysp",True)
- anysp.setacl(anyuser, "rl")
-
- anyidp = lookup("system:anyidp",True)
- anyidp.setacl(anyuser, "rl")
-
- add_member(anyentity,entity)
- if entity.type == Entity.SP:
- add_member(anysp,entity)
- if entity.type == Entity.IDP:
- add_member(anyidp,entity)
-
@login_required
def join(request,id,membername=None):
name = get_object_or_404(Name,pk=id)
@@ -89,13 +33,7 @@ def join(request,id,membername=None):
m = Membership(name=name,enabled=True)
form = MembershipForm(request.POST,instance=m)
if form.is_valid():
- if form.cleaned_data.has_key('user'):
- add_member(name,form.cleaned_data['user'])
- elif form.cleaned_data.has_key('entity'):
- add_member(name,form.cleaned_data['entity'])
- else:
- raise Exception,"Bad form state - should not happen at all!"
-
+ add_member(name,form.cleaned_data['user'])
return HttpResponseRedirect(name.url())
else:
return respond_to(request,
@@ -103,15 +41,10 @@ def join(request,id,membername=None):
{'form': form,'name': name, 'formtitle': 'Add a member to %s' % name.short})
else:
if membername:
- try:
- member = User.objects.get(username=membername)
- except ObjectDoesNotExist:
- member = Entity.objects.get(entityId=name)
- add_member(name, member)
+ add_member(name, membername)
return HttpResponseRedirect(name.url())
else:
form = MembershipForm()
- import_metadata()
return respond_to(request,
{'text/html': 'apps/membership/edit.html'},
{'form': form,'name': name, 'formtitle': 'Add a member to %s' % name.short})
@@ -122,7 +55,7 @@ def leave(request,id,membername=None):
if membername:
try:
member = User.objects.get(username=membername)
+ remove_member(name, member)
except ObjectDoesNotExist:
- member = Entity.objects.get(entityId=name)
- remove_member(name, member)
+ pass
return HttpResponseRedirect(name.url())
diff --git a/coip/apps/name/models.py b/coip/apps/name/models.py
index d7da547..519248b 100644
--- a/coip/apps/name/models.py
+++ b/coip/apps/name/models.py
@@ -34,11 +34,14 @@ class Name(models.Model):
short = models.CharField(max_length=64,blank=True)
creator = models.ForeignKey(User,blank=True, null=True)
display = models.TextField(editable=False)
+ #icon = models.ImageField(blank=True, null=True)
description = models.TextField(blank=True)
format = models.SmallIntegerField(default=FMT_URN,choices=((FMT_URN,"URN"),(FMT_URL,"URL")))
timecreated = models.DateTimeField(auto_now_add=True)
lastupdated = models.DateTimeField(auto_now=True)
+ nmembers = -1
+
def mode(self):
if not self.format:
return FMT_URN
@@ -203,6 +206,11 @@ class Name(models.Model):
def permitted_children(self,user,perm):
return filter(lambda s: s.has_permission(user,perm),self.children.all())
+ def count_members(self):
+ if self.nmembers == -1:
+ self.nmembers = self.memberships.filter(hidden=False).count()
+ return self.nmembers
+
def set_display(sender,**kwargs):
kwargs['instance'].display = kwargs['instance'].display_str()
diff --git a/coip/apps/opensocial/people.py b/coip/apps/opensocial/people.py
index 9465c08..9f0a925 100644
--- a/coip/apps/opensocial/people.py
+++ b/coip/apps/opensocial/people.py
@@ -64,7 +64,7 @@ class GroupResource(OpenSocialResource):
def override_urls(self):
return [
- url(r"^(?P<resource_name>%s)/(?P<username>[\@\w\d_.-:]+)/(?P<group_name_id>[\d]+)%s?" % (self._meta.resource_name,trailing_slash()),
+ url(r"^(?P<resource_name>%s)/(?P<username>[\@\w\d_.-:]+)/(?P<name_id>[\d]+)%s?" % (self._meta.resource_name,trailing_slash()),
self.wrap_view('list_memberships'), name="api_list_memberships"),
url(r"^(?P<resource_name>%s)/(?P<username>[\@\w\d_.-:]+)%s" % (self._meta.resource_name,trailing_slash()),
self.wrap_view('list_memberships'), name="api_list_memberships"),
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