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
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
14 from openid
.yadis
import xri
18 import time
, base64
, md5
, operator
21 from models
import Association
, Nonce
23 __all__
= ['OpenID', 'DjangoOpenIDStore', 'from_openid_response', 'clean_next']
25 DEFAULT_NEXT
= getattr(settings
, 'OPENID_REDIRECT_NEXT', '/')
29 next
= str_to_unicode(urllib
.unquote(next
), 'utf-8')
31 if next
.startswith('/'):
36 def __init__(self
, openid_
, issued
, attrs
=None, sreg_
=None):
39 self
.attrs
= attrs
or {}
40 self
.sreg
= sreg_
or {}
41 self
.is_iname
= (xri
.identifierScheme(openid_
) == 'XRI')
44 return '<OpenID: %s>' % self
.openid
49 class DjangoOpenIDStore(OpenIDStore
):
51 self
.max_nonce_age
= 6 * 60 * 60 # Six hours
53 def storeAssociation(self
, server_url
, 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
64 def getAssociation(self
, server_url
, handle
=None):
66 if handle
is not None:
67 assocs
= Association
.objects
.filter(
68 server_url
= server_url
, handle
= handle
71 assocs
= Association
.objects
.filter(
72 server_url
= server_url
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
)
85 associations
.append((association
.issued
, association
))
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
99 def useNonce(self
, server_url
, timestamp
, salt
):
100 if abs(timestamp
- time
.time()) > openid
.store
.nonce
.SKEW
:
104 Q(server_url__exact
=server_url
),
105 Q(timestamp__exact
=timestamp
),
109 ononce
= Nonce
.objects
.get(reduce(operator
.and_
, query
))
110 except Nonce
.DoesNotExist
:
112 server_url
=server_url
,
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
]
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
) \
143 openid_response
.identity_url
, issued
, openid_response
.signed_fields
,