1"""A simple store using only in-process memory.""" 2 3from openid.store import nonce 4 5import copy 6import time 7 8class ServerAssocs(object): 9 def __init__(self): 10 self.assocs = {} 11 12 def set(self, assoc): 13 self.assocs[assoc.handle] = assoc 14 15 def get(self, handle): 16 return self.assocs.get(handle) 17 18 def remove(self, handle): 19 try: 20 del self.assocs[handle] 21 except KeyError: 22 return False 23 else: 24 return True 25 26 def best(self): 27 """Returns association with the oldest issued date. 28 29 or None if there are no associations. 30 """ 31 best = None 32 for assoc in self.assocs.values(): 33 if best is None or best.issued < assoc.issued: 34 best = assoc 35 return best 36 37 def cleanup(self): 38 """Remove expired associations. 39 40 @return: tuple of (removed associations, remaining associations) 41 """ 42 remove = [] 43 for handle, assoc in self.assocs.iteritems(): 44 if assoc.getExpiresIn() == 0: 45 remove.append(handle) 46 for handle in remove: 47 del self.assocs[handle] 48 return len(remove), len(self.assocs) 49 50 51 52class MemoryStore(object): 53 """In-process memory store. 54 55 Use for single long-running processes. No persistence supplied. 56 """ 57 def __init__(self): 58 self.server_assocs = {} 59 self.nonces = {} 60 61 def _getServerAssocs(self, server_url): 62 try: 63 return self.server_assocs[server_url] 64 except KeyError: 65 assocs = self.server_assocs[server_url] = ServerAssocs() 66 return assocs 67 68 def storeAssociation(self, server_url, assoc): 69 assocs = self._getServerAssocs(server_url) 70 assocs.set(copy.deepcopy(assoc)) 71 72 def getAssociation(self, server_url, handle=None): 73 assocs = self._getServerAssocs(server_url) 74 if handle is None: 75 return assocs.best() 76 else: 77 return assocs.get(handle) 78 79 def removeAssociation(self, server_url, handle): 80 assocs = self._getServerAssocs(server_url) 81 return assocs.remove(handle) 82 83 def useNonce(self, server_url, timestamp, salt): 84 if abs(timestamp - time.time()) > nonce.SKEW: 85 return False 86 87 anonce = (str(server_url), int(timestamp), str(salt)) 88 if anonce in self.nonces: 89 return False 90 else: 91 self.nonces[anonce] = None 92 return True 93 94 def cleanupNonces(self): 95 now = time.time() 96 expired = [] 97 for anonce in self.nonces.iterkeys(): 98 if abs(anonce[1] - now) > nonce.SKEW: 99 # removing items while iterating over the set could be bad. 100 expired.append(anonce) 101 102 for anonce in expired: 103 del self.nonces[anonce] 104 return len(expired) 105 106 def cleanupAssociations(self): 107 remove_urls = [] 108 removed_assocs = 0 109 for server_url, assocs in self.server_assocs.iteritems(): 110 removed, remaining = assocs.cleanup() 111 removed_assocs += removed 112 if not remaining: 113 remove_urls.append(server_url) 114 115 # Remove entries from server_assocs that had none remaining. 116 for server_url in remove_urls: 117 del self.server_assocs[server_url] 118 return removed_assocs 119 120 def __eq__(self, other): 121 return ((self.server_assocs == other.server_assocs) and 122 (self.nonces == other.nonces)) 123 124 def __ne__(self, other): 125 return not (self == other) 126