def create(self, users): # If users is a singular object, make it a list of one if not hasattr(users, '__iter__'): users = [users] # Validate internal uniqueness self._validate_internal_uniqueness(users) # Validate Redis uniqueness # NOTE: This should check user_id and username (which is more important) for uniqueness with redpipe.autoexec() as pipe: all_names = self.get_usernames(pipe) all_exists = [] for user in users: all_exists.append(self._exists(user.oid, pipe=pipe)) # Return if any of the objects already exist for ex in all_exists: if ex.IS(True): raise ExistsException() for user in users: if user.username in all_names: raise ExistsException() # Create all the entries with redpipe.autoexec() as pipe: for user in users: self._upsert(user, pipe=pipe) self._create_registration_token(user, pipe=pipe)
def _upsert(self, token, expiry=0, pipe=None): with redpipe.autoexec(pipe=pipe) as pipe: # Create/update the token and save it to redis db_token = DBOAuthToken(token.get_dict(), pipe) # Remove empty custome fields from the object for field in token.fields_custom: if not str(getattr(token, field)).strip(): db_token.remove(field, pipe=pipe) # Add lookup keys for access and refresh tokens if expiry <= 0: # Set the secondary keys pipe.set("oauth:tokens:access:{}".format(token.access_token), token.oid) pipe.set("oauth:tokens:refresh:{}".format(token.refresh_token), token.oid) else: # Set the expiry on the struct pipe.expire("oauth:tokens{{{}}}".format(token.oid), int(expiry) * 24) # Set the secondary keys pipe.set("oauth:tokens:access:{}".format(token.access_token), token.oid, ex=int(expiry)) pipe.set("oauth:tokens:refresh:{}".format(token.refresh_token), token.oid, ex=(int(expiry) * 24))
def get_by_client_id(self, client_id): self.logger.debug("client_id: %s", client_id) oid = None with redpipe.autoexec() as pipe: oid = pipe.get("oauth:clients:client_id:{}".format(client_id)) client_obj = self.get_by_oid(oid.result.decode('utf-8')) return client_obj
def remove(self, oauth_user): with redpipe.autoexec() as pipe: pipe.srem('oauth:users:usernames', oauth_user.username.upper()) pipe.srem('oauth:users:oids', oauth_user.oid) pipe.delete('oauth:users:{}'.format(oauth_user.username.upper())) pipe.delete('oauth:users{{{}}}'.format(oauth_user.oid)) self._remove_registration_token(oauth_user, pipe)
def get_by_refresh_token(self, refresh_token): # Look up the token by the refresh_token with redpipe.autoexec() as pipe: oid = pipe.get("oauth:tokens:refresh:{}".format(refresh_token)) if oid.IS(None): raise NotExistsException() return self.get_by_id(oid.result.decode('utf-8'))
def create(self, tokens, expiry=0): # If tokens is a singular object, make it a list of one if not hasattr(tokens, '__iter__'): tokens = [tokens] # Validate Redis uniqueness with redpipe.autoexec() as pipe: all_exists = [] for token in tokens: all_exists.append(self._exists(token.oid, pipe=pipe)) # Return if any of the objects already exist for ex in all_exists: if ex.IS(True): raise ExistsException() # Create all the entries with redpipe.autoexec() as pipe: for token in tokens: self._upsert(token, expiry=expiry, pipe=pipe)
def get_user_id(self, username, pipe=None): decoded_user_id = redpipe.Future() with redpipe.autoexec(pipe=pipe) as pipe: user_id = pipe.get('oauth:users:{}'.format(username.upper())) def callback(): if not user_id: raise NotExistsException() decoded_user_id.set(user_id.decode("utf-8")) pipe.on_execute(callback) return decoded_user_id
def valid_registration_token(self, user_id, pipe=None): valid_token = redpipe.Future() valid_token.set(False) with redpipe.autoexec(pipe=pipe) as pipe: usertoken = pipe.get('oauth:usertokens:{}'.format(user_id)) def callback(): if usertoken: valid_token.set(True) pipe.on_execute(callback) return valid_token
def _upsert(self, client, pipe=None): with redpipe.autoexec(pipe=pipe) as pipe: # Create/update the user and save it to redis db_obj = DBOAuthClient(client.get_dict(), pipe) # Remove empty custome fields from the object for field in client.fields_custom: if not str(getattr(client, field)).strip(): db_obj.remove(field, pipe=pipe) # Add the indexing data pipe.set("oauth:clients:client_id:{}".format(client.client_id), client.oid) pipe.sadd("oauth:clients:client_ids", client.client_id) pipe.sadd("oauth:clients:oids", client.oid)
def get_by_id(self, user_id, pipe=None): user_obj = OAuthUser() with redpipe.autoexec(pipe=pipe) as pipe: db_obj = DBOAuthUser(user_id, pipe=pipe) def callback(): if db_obj.persisted: user_obj.set_fields((dict(db_obj))) else: raise NotExistsException() pipe.on_execute(callback) return user_obj
def username_exists(self, username): exists = redpipe.Future() with redpipe.autoexec() as pipe: user_id = pipe.get('oauth:users:{}'.format(username.upper())) def callback(): if not user_id: exists.set(False) else: exists.set(True) pipe.on_execute(callback) return exists
def update(self, users): # If users is a singular object, make it a list of one if not hasattr(users, '__iter__'): users = [users] # Validate internal uniqueness self._validate_internal_uniqueness(users) # Validate objects exist in Redis with redpipe.autoexec() as pipe: all_exists = [] for user in users: all_exists.append(self._exists(user.oid, pipe=pipe)) # Return if any of the objects don't already exist for ex in all_exists: if ex.IS(False): raise NotExistsException() # Update all the entries with redpipe.autoexec() as pipe: for user in users: self._upsert(user, pipe=pipe)
def _upsert(self, oauth_user, pipe=None): with redpipe.autoexec(pipe=pipe) as pipe: # Create/update the user and save it to redis db_user = DBOAuthUser(oauth_user.get_dict(), pipe=pipe) # Remove empty custom fields from the object for field in oauth_user.fields_custom: if not str(getattr(oauth_user, field)).strip(): db_user.remove(field, pipe=pipe) # Add the user to the usernames set pipe.set('oauth:users:{}'.format(oauth_user.username.upper()), oauth_user.oid) pipe.sadd('oauth:users:usernames', oauth_user.username.upper()) pipe.sadd('oauth:users:oids', oauth_user.oid)
def create(self, clients): # If clients is a singular object, make it a list of one if not hasattr(clients, '__iter__'): clients = [clients] # Validate internal uniqueness self._validate_internal_uniqueness(clients) # Validate Redis uniqueness with redpipe.autoexec() as pipe: all_exists = [] for client in clients: all_exists.append(self._exists(client.client_id, pipe=pipe)) # Return if any of the objects already exist for ex in all_exists: if ex.IS(True): raise ExistsException() # Create all the entries with redpipe.autoexec() as pipe: for client in clients: self._upsert(client, pipe=pipe)
def get_ids(self, pipe=None): key_future = redpipe.Future() with redpipe.autoexec(pipe=pipe) as pipe: byte_set = pipe.smembers('oauth:users:oids') # After executing the pipe, callback to decode the results def callback(): key_list = [] for byte_value in byte_set: key_list.append(byte_value.decode("utf-8")) key_future.set(key_list) # Execute the callback pipe.on_execute(callback) return key_future
def test_connect_redpipe(self): # Connect to the database dstore = InoRedis(host=self.redis_host, port=self.redis_port, db=self.redis_db) # Flush the database dstore.redis.flushdb() # Add an item with a redpipe pipeline with redpipe.autoexec() as pipe: pipe.set('TESTKEY2', 'TESTVALUE2') # Get the item with without a pipeline test_value2 = None with redpipe.autoexec() as pipe: test_value2 = pipe.get('TESTKEY2') test_value2 = test_value2.decode('utf-8') # Compare the values to make sure everything is happy self.logger.debug("test_value2: %s, type: %s", test_value2, type(test_value2)) self.assertEqual(test_value2, 'TESTVALUE2') # Flush the database dstore.redis.flushdb() # Force deletion of the dstore object (to force garbage collection). This is due to an issue on the Travis-CI # environment of instantiating the next test before the current test is garbage collected. del dstore
def get_by_oid(self, oid, pipe=None): self.logger.debug("oid: %s", oid) client_obj = OAuthClient() with redpipe.autoexec(pipe=pipe) as pipe: db_obj = DBOAuthClient(oid, pipe) def callback(): self.logger.debug("db_obj: %s", db_obj) if db_obj.persisted: self.logger.debug("db_obj.persisted: True") client_obj.set_fields((dict(db_obj))) else: raise NotExistsException() pipe.on_execute(callback) return client_obj
def _load_default_user_data(self): self.logger.info("Loading the default user set") # Load each of the default users with redpipe.autoexec() as pipe: for user in default_user_data: # User data will be loaded via direct calls to Redis tmp_user_id = uuid.uuid4() tmp_key = "oauth:users{{{}}}".format(tmp_user_id) pipe.hset(tmp_key, "oid", tmp_user_id) pipe.hset(tmp_key, "username", user[0]) pipe.hset(tmp_key, "password_hash", pbkdf2_sha512.hash(user[1])) pipe.hset(tmp_key, "is_active", user[2]) pipe.hset(tmp_key, "scopes", json.dumps(user[3])) # Setup the appropriate references pipe.set("oauth:users:{}".format(user[0]), tmp_user_id) # Load the username and user_id into the appropriate set pipe.sadd("oauth:users:usernames", user[0]) pipe.sadd("oauth:users:oids", tmp_user_id)
def _remove_registration_token(self, oauth_user, pipe=None): with redpipe.autoexec(pipe=pipe) as pipe: key = 'oauth:usertokens:{}'.format(oauth_user.oid) pipe.delete(key)
def _create_registration_token(self, oauth_user, pipe=None): with redpipe.autoexec(pipe=pipe) as pipe: key = 'oauth:usertokens:{}'.format(oauth_user.oid) pipe.set(key, oauth_user.oid) ttl = datetime.timedelta(days=7) pipe.expire(key, ttl)
def _exists(self, user_id, pipe=None): with redpipe.autoexec(pipe=pipe) as pipe: exists = pipe.exists('oauth:users{{{}}}'.format(user_id)) return exists
def remove(self, client): with redpipe.autoexec() as pipe: pipe.srem("oauth:clients:client_ids", client.client_id) pipe.srem("oauth:clients:oids", client.oid) pipe.delete("oauth:clients:client_id:{}".format(client.client_id)) pipe.delete("oauth:clients{{{}}}".format(client.oid))
def _exists(self, client_id, pipe=None): with redpipe.autoexec(pipe=pipe) as pipe: exists = pipe.exists( "oauth:clients:client_id:{}".format(client_id)) return exists
def _exists(self, token_id, pipe=None): with redpipe.autoexec(pipe=pipe) as pipe: exists = pipe.exists('oauth:tokens{{{}}}'.format(token_id)) return exists
def redpipe_bench(): for values in values_iterator(): with redpipe.autoexec() as r: results = bench(r, values) assert (results == values)