Merge pull request #821 from MITx/feature/rocha/openid-djangostore

Use django cache for OpenID provider store
This commit is contained in:
Victor Shnayder
2012-10-05 08:41:18 -07:00
2 changed files with 126 additions and 6 deletions

View File

@@ -0,0 +1,123 @@
"""A openid store using django cache"""
from openid.store.interface import OpenIDStore
from openid.store import nonce
from django.core.cache import cache
import logging
import time
DEFAULT_ASSOCIATION_TIMEOUT = 60
DEFAULT_NONCE_TIMEOUT = 600
ASSOCIATIONS_KEY_PREFIX = 'openid.provider.associations.'
NONCE_KEY_PREFIX = 'openid.provider.nonce.'
log = logging.getLogger('DjangoOpenIDStore')
def get_url_key(server_url):
key = ASSOCIATIONS_KEY_PREFIX + server_url
return key
def get_nonce_key(server_url, timestamp, salt):
key = '{prefix}{url}.{ts}.{salt}'.format(prefix=NONCE_KEY_PREFIX,
url=server_url,
ts=timestamp,
salt=salt)
return key
class DjangoOpenIDStore(OpenIDStore):
def __init__(self):
log.info('DjangoStore cache:' + str(cache.__class__))
def storeAssociation(self, server_url, association):
key = get_url_key(server_url)
log.info('storeAssociation {0}'.format(key))
associations = cache.get(key, {})
associations[association.handle] = association
cache.set(key, associations, DEFAULT_ASSOCIATION_TIMEOUT)
def getAssociation(self, server_url, handle=None):
key = get_url_key(server_url)
log.info('getAssociation {0}'.format(key))
associations = cache.get(key)
association = None
if associations:
if handle is None:
# get best association
valid = [a for a in associations if a.getExpiresIn() > 0]
if valid:
association = valid[0]
else:
association = associations.get(handle)
# check expiration and remove if it has expired
if association and association.getExpiresIn() <= 0:
if handle is None:
cache.delete(key)
else:
associations.pop(handle)
cache.set(key, association, DEFAULT_ASSOCIATION_TIMEOUT)
association = None
return association
def removeAssociation(self, server_url, handle):
key = get_url_key(server_url)
log.info('removeAssociation {0}'.format(key))
associations = cache.get(key)
removed = False
if associations:
if handle is None:
cache.delete(key)
removed = True
else:
association = associations.pop(handle)
if association:
cache.set(key, association, DEFAULT_ASSOCIATION_TIMEOUT)
removed = True
return removed
def useNonce(self, server_url, timestamp, salt):
key = get_nonce_key(server_url, timestamp, salt)
log.info('useNonce {0}'.format(key))
if abs(timestamp - time.time()) > nonce.SKEW:
return False
anonce = cache.get(key)
found = False
if anonce is None:
cache.set(key, '-', DEFAULT_NONCE_TIMEOUT)
found = False
else:
found = True
return found
def cleanupNonces(self):
# not necesary, keys will timeout
return 0
def cleanupAssociations(self):
# not necesary, keys will timeout
return 0

View File

@@ -7,6 +7,7 @@ import string
import fnmatch
from external_auth.models import ExternalAuthMap
from external_auth.djangostore import DjangoOpenIDStore
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME, authenticate, login
@@ -30,7 +31,6 @@ from openid.consumer.consumer import SUCCESS
from openid.server.server import Server
from openid.server.trustroot import TrustRoot
from openid.store.filestore import FileOpenIDStore
from openid.extensions import ax, sreg
import student.views as student_views
@@ -271,10 +271,7 @@ def get_xrds_url(resource, request):
"""
Return the XRDS url for a resource
"""
host = request.META['HTTP_HOST']
if not host.endswith('edx.org'):
return None
host = request.get_host()
location = host + '/openid/provider/' + resource + '/'
@@ -400,7 +397,7 @@ def provider_login(request):
return default_render_failure(request, "Invalid OpenID request")
# initialize store and server
store = FileOpenIDStore('/tmp/openid_provider')
store = DjangoOpenIDStore()
server = Server(store, endpoint)
# handle OpenID request