Merge pull request #821 from MITx/feature/rocha/openid-djangostore
Use django cache for OpenID provider store
This commit is contained in:
123
common/djangoapps/external_auth/djangostore.py
Normal file
123
common/djangoapps/external_auth/djangostore.py
Normal 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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user