webfaction and repo.or.cz deployment done
[worddb.git] / libs / django_authopenid / util.py
blob841a81c7b53972fd412b6b7a7cd232966bbd1a05
1 # -*- coding: utf-8 -*-
2 from openid.store.interface import OpenIDStore
3 from openid.association import Association as OIDAssociation
4 from openid.extensions import sreg
5 import openid.store
7 from django.db.models.query import Q
8 from django.conf import settings
9 from django.http import str_to_unicode
12 # needed for some linux distributions like debian
13 try:
14 from openid.yadis import xri
15 except:
16 from yadis import xri
18 import time, base64, md5, operator
19 import urllib
21 from models import Association, Nonce
23 __all__ = ['OpenID', 'DjangoOpenIDStore', 'from_openid_response', 'clean_next']
25 DEFAULT_NEXT = getattr(settings, 'OPENID_REDIRECT_NEXT', '/')
26 def clean_next(next):
27 if next is None:
28 return DEFAULT_NEXT
29 next = str_to_unicode(urllib.unquote(next), 'utf-8')
30 next = next.strip()
31 if next.startswith('/'):
32 return next
33 return DEFAULT_NEXT
35 class OpenID:
36 def __init__(self, openid_, issued, attrs=None, sreg_=None):
37 self.openid = openid_
38 self.issued = issued
39 self.attrs = attrs or {}
40 self.sreg = sreg_ or {}
41 self.is_iname = (xri.identifierScheme(openid_) == 'XRI')
43 def __repr__(self):
44 return '<OpenID: %s>' % self.openid
46 def __str__(self):
47 return self.openid
49 class DjangoOpenIDStore(OpenIDStore):
50 def __init__(self):
51 self.max_nonce_age = 6 * 60 * 60 # Six hours
53 def storeAssociation(self, server_url, association):
54 assoc = Association(
55 server_url = server_url,
56 handle = association.handle,
57 secret = base64.encodestring(association.secret),
58 issued = association.issued,
59 lifetime = association.issued,
60 assoc_type = association.assoc_type
62 assoc.save()
64 def getAssociation(self, server_url, handle=None):
65 assocs = []
66 if handle is not None:
67 assocs = Association.objects.filter(
68 server_url = server_url, handle = handle
70 else:
71 assocs = Association.objects.filter(
72 server_url = server_url
74 if not assocs:
75 return None
76 associations = []
77 for assoc in assocs:
78 association = OIDAssociation(
79 assoc.handle, base64.decodestring(assoc.secret), assoc.issued,
80 assoc.lifetime, assoc.assoc_type
82 if association.getExpiresIn() == 0:
83 self.removeAssociation(server_url, assoc.handle)
84 else:
85 associations.append((association.issued, association))
86 if not associations:
87 return None
88 return associations[-1][1]
90 def removeAssociation(self, server_url, handle):
91 assocs = list(Association.objects.filter(
92 server_url = server_url, handle = handle
94 assocs_exist = len(assocs) > 0
95 for assoc in assocs:
96 assoc.delete()
97 return assocs_exist
99 def useNonce(self, server_url, timestamp, salt):
100 if abs(timestamp - time.time()) > openid.store.nonce.SKEW:
101 return False
103 query = [
104 Q(server_url__exact=server_url),
105 Q(timestamp__exact=timestamp),
106 Q(salt__exact=salt),
108 try:
109 ononce = Nonce.objects.get(reduce(operator.and_, query))
110 except Nonce.DoesNotExist:
111 ononce = Nonce(
112 server_url=server_url,
113 timestamp=timestamp,
114 salt=salt
116 ononce.save()
117 return True
119 ononce.delete()
121 return False
123 def cleanupNonce(self):
124 Nonce.objects.filter(timestamp<int(time.time()) - nonce.SKEW).delete()
126 def cleanupAssociations(self):
127 Association.objects.extra(where=['issued + lifetimeint<(%s)' % time.time()]).delete()
129 def getAuthKey(self):
130 # Use first AUTH_KEY_LEN characters of md5 hash of SECRET_KEY
131 return md5.new(settings.SECRET_KEY).hexdigest()[:self.AUTH_KEY_LEN]
133 def isDumb(self):
134 return False
136 def from_openid_response(openid_response):
137 """ return openid object from response """
138 issued = int(time.time())
139 sreg_resp = sreg.SRegResponse.fromSuccessResponse(openid_response) \
140 or []
142 return OpenID(
143 openid_response.identity_url, issued, openid_response.signed_fields,
144 dict(sreg_resp)