openid.py
162 lines
| 5.1 KiB
| text/x-python
|
PythonLexer
r5040 | ||||
r3912 | ||||
# We need absolute import to import from openid library which has the same | ||||
# name as this module | ||||
r5040 | from __future__ import absolute_import | |||
r3912 | import logging | |||
import datetime | ||||
r5040 | import openid.store.interface | |||
r3912 | ||||
r5040 | logger = logging.getLogger(__name__) | |||
try: | ||||
from google.appengine.ext import ndb | ||||
except ImportError: | ||||
logger.exception("FATAL: google.appengine 1st Gen. not installed!") | ||||
raise | ||||
r3912 | ||||
class NDBOpenIDStore(ndb.Expando, openid.store.interface.OpenIDStore): | ||||
""" | ||||
|gae| `NDB <https://developers.google.com/appengine/docs/python/ndb/>`_ | ||||
based implementation of the :class:`openid.store.interface.OpenIDStore` | ||||
interface of the `python-openid`_ library. | ||||
""" | ||||
serialized = ndb.StringProperty() | ||||
expiration_date = ndb.DateTimeProperty() | ||||
# we need issued to sort by most recently issued | ||||
issued = ndb.IntegerProperty() | ||||
@staticmethod | ||||
def _log(*args, **kwargs): | ||||
pass | ||||
@classmethod | ||||
def storeAssociation(cls, server_url, association): | ||||
# store an entity with key = server_url | ||||
issued = datetime.datetime.fromtimestamp(association.issued) | ||||
lifetime = datetime.timedelta(0, association.lifetime) | ||||
expiration_date = issued + lifetime | ||||
entity = cls.get_or_insert( | ||||
association.handle, parent=ndb.Key( | ||||
'ServerUrl', server_url)) | ||||
entity.serialized = association.serialize() | ||||
entity.expiration_date = expiration_date | ||||
entity.issued = association.issued | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Putting OpenID association to datastore.') | ||||
entity.put() | ||||
@classmethod | ||||
def cleanupAssociations(cls): | ||||
# query for all expired | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Querying datastore for OpenID associations.') | ||||
query = cls.query(cls.expiration_date <= datetime.datetime.now()) | ||||
# fetch keys only | ||||
expired = query.fetch(keys_only=True) | ||||
# delete all expired | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Deleting expired OpenID associations from datastore.') | ||||
ndb.delete_multi(expired) | ||||
return len(expired) | ||||
@classmethod | ||||
def getAssociation(cls, server_url, handle=None): | ||||
cls.cleanupAssociations() | ||||
if handle: | ||||
key = ndb.Key('ServerUrl', server_url, cls, handle) | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Getting OpenID association from datastore by key.') | ||||
entity = key.get() | ||||
else: | ||||
# return most recently issued association | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Querying datastore for OpenID associations by ancestor.') | ||||
entity = cls.query(ancestor=ndb.Key( | ||||
'ServerUrl', server_url)).order(-cls.issued).get() | ||||
if entity and entity.serialized: | ||||
return openid.association.Association.deserialize( | ||||
entity.serialized) | ||||
@classmethod | ||||
def removeAssociation(cls, server_url, handle): | ||||
key = ndb.Key('ServerUrl', server_url, cls, handle) | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Getting OpenID association from datastore by key.') | ||||
if key.get(): | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Deleting OpenID association from datastore.') | ||||
key.delete() | ||||
return True | ||||
@classmethod | ||||
def useNonce(cls, server_url, timestamp, salt): | ||||
# check whether there is already an entity with the same ancestor path | ||||
# in the datastore | ||||
key = ndb.Key( | ||||
'ServerUrl', | ||||
str(server_url) or 'x', | ||||
'TimeStamp', | ||||
str(timestamp), | ||||
cls, | ||||
str(salt)) | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Getting OpenID nonce from datastore by key.') | ||||
result = key.get() | ||||
if result: | ||||
# if so, the nonce is not valid so return False | ||||
cls._log( | ||||
logging.WARNING, | ||||
u'NDBOpenIDStore: Nonce was already used!') | ||||
return False | ||||
else: | ||||
# if not, store the key to datastore and return True | ||||
nonce = cls(key=key) | ||||
nonce.expiration_date = datetime.datetime.fromtimestamp( | ||||
timestamp) + datetime.timedelta(0, openid.store.nonce.SKEW) | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Putting new nonce to datastore.') | ||||
nonce.put() | ||||
return True | ||||
@classmethod | ||||
def cleanupNonces(cls): | ||||
# get all expired nonces | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Querying datastore for OpenID nonces ordered by expiration date.') | ||||
expired = cls.query().filter( | ||||
cls.expiration_date <= datetime.datetime.now()).fetch( | ||||
keys_only=True) | ||||
# delete all expired | ||||
cls._log( | ||||
logging.DEBUG, | ||||
u'NDBOpenIDStore: Deleting expired OpenID nonces from datastore.') | ||||
ndb.delete_multi(expired) | ||||
return len(expired) | ||||