def test_05_multiple_entries(self): # two consistent entries now = datetime.now() UserCache("hans1", "hans1", "resolver1", "uid1", now - timedelta(seconds=60)).save() UserCache("hans1", "hans1", "resolver1", "uid1", now).save() r = UserCache.query.filter(UserCache.username == "hans1", UserCache.resolver == "resolver1") self.assertEquals(r.count(), 2) u_name = get_username("uid1", "resolver1") self.assertEqual(u_name, "hans1") r = delete_user_cache() # two inconsistent entries: most recent entry (ordered by datetime) wins UserCache("hans2", "hans2", "resolver1", "uid1", now).save() UserCache("hans1", "hans1", "resolver1", "uid1", now - timedelta(seconds=60)).save() r = UserCache.query.filter(UserCache.user_id == "uid1", UserCache.resolver == "resolver1") self.assertEquals(r.count(), 2) u_name = get_username("uid1", "resolver1") self.assertEqual(u_name, "hans2") # Clean up the cache r = delete_user_cache()
def delete_resolver(resolvername): """ delete a resolver and all related ResolverConfig entries If there was no resolver, that could be deleted, it returns -1 :param resolvername: the name of the to be deleted resolver :type resolvername: string :return: The Id of the resolver :rtype: int """ ret = -1 reso = Resolver.query.filter_by(name=resolvername).first() if reso: if reso.realm_list: # The resolver is still contained in a realm! We must not delete it realmname = reso.realm_list[0].realm.name raise ConfigAdminError("The resolver %r is still contained in " "realm %r." % (resolvername, realmname)) reso.delete() ret = reso.id # Delete resolver object from cache store = get_request_local_store() if 'resolver_objects' in store: if resolvername in store['resolver_objects']: del store['resolver_objects'][resolvername] # Remove corresponding entries from the user cache delete_user_cache(resolver=resolvername) return ret
def test_06_implicit_cache_population(self): self._create_realm() # testing `get_username` self.assertEquals(UserCache.query.count(), 0) # the cache is empty, so the username is read from the resolver u_name = get_username(self.uid, self.resolvername1) self.assertEqual(self.username, u_name) # it should be part of the cache now r = UserCache.query.filter(UserCache.user_id == self.uid, UserCache.resolver == self.resolvername1).one() self.assertEqual(self.username, r.username) # Apart from that, the cache should be empty. self.assertEqual(UserCache.query.count(), 1) r = delete_user_cache() # testing `User()`, but this time we add an already-expired entry to the cache self.assertEquals(UserCache.query.count(), 0) UserCache(self.username, self.resolvername1, 'fake_uid', datetime.now() - timedelta(weeks=50)).save() # cache contains an expired entry, uid is read from the resolver (we can verify # that the cache entry is indeed not queried as it contains 'fake_uid' instead of the correct uid) user = User(self.username, self.realm1, self.resolvername1) self.assertEqual(user.uid, self.uid) # a new entry should have been added to the cache now r = retrieve_latest_entry((UserCache.username == self.username) & (UserCache.resolver == self.resolvername1)) self.assertEqual(self.uid, r.user_id) # But the expired entry is also still in the cache self.assertEqual(UserCache.query.count(), 2) r = delete_user_cache() self._delete_realm()
def test_06_implicit_cache_population(self): self._create_realm() # testing `get_username` self.assertEquals(UserCache.query.count(), 0) # the cache is empty, so the username is read from the resolver u_name = get_username(self.uid, self.resolvername1) self.assertEqual(self.username, u_name) # it should be part of the cache now r = UserCache.query.filter( UserCache.user_id == self.uid, UserCache.resolver == self.resolvername1).one() self.assertEqual(self.username, r.username) # Apart from that, the cache should be empty. self.assertEqual(UserCache.query.count(), 1) r = delete_user_cache() # testing `User()`, but this time we add an already-expired entry to the cache self.assertEquals(UserCache.query.count(), 0) UserCache(self.username, self.username, self.resolvername1, 'fake_uid', datetime.now() - timedelta(weeks=50)).save() # cache contains an expired entry, uid is read from the resolver (we can verify # that the cache entry is indeed not queried as it contains 'fake_uid' instead of the correct uid) user = User(self.username, self.realm1, self.resolvername1) self.assertEqual(user.uid, self.uid) # a new entry should have been added to the cache now r = retrieve_latest_entry((UserCache.username == self.username) & (UserCache.resolver == self.resolvername1)) self.assertEqual(self.uid, r.user_id) # But the expired entry is also still in the cache self.assertEqual(UserCache.query.count(), 2) r = delete_user_cache() self._delete_realm()
def test_05_multiple_entries(self): # two consistent entries now = datetime.now() UserCache("hans1", "resolver1", "uid1", now - timedelta(seconds=60)).save() UserCache("hans1", "resolver1", "uid1", now).save() r = UserCache.query.filter(UserCache.username == "hans1", UserCache.resolver == "resolver1") self.assertEquals(r.count(), 2) u_name = get_username("uid1", "resolver1") self.assertEqual(u_name, "hans1") r = delete_user_cache() # two inconsistent entries: most recent entry (ordered by datetime) wins UserCache("hans2", "resolver1", "uid1", now).save() UserCache("hans1", "resolver1", "uid1", now - timedelta(seconds=60)).save() r = UserCache.query.filter(UserCache.user_id == "uid1", UserCache.resolver == "resolver1") self.assertEquals(r.count(), 2) u_name = get_username("uid1", "resolver1") self.assertEqual(u_name, "hans2") # Clean up the cache r = delete_user_cache()
def test_08_invalidate_delete_resolver(self): self._create_realm() self._populate_cache() # call delete_resolver on resolver1, which should invalidate all of its entries self._delete_realm() self.assertEquals(UserCache.query.count(), 1) # Only hans3 in resolver2 should still be in the cache u_name = get_username("uid2", "resolver2") self.assertEquals("hans3", u_name) delete_user_cache()
def test_03_get_identifiers(self): # create realm self._create_realm() # delete user_cache r = delete_user_cache() self.assertTrue(r >= 0) # The username is not in the cache. It is fetched from the resolver # At the same time the cache is filled. Implicitly we test the # _get_resolvers! user = User(self.username, self.realm1, self.resolvername1) uids = user.get_user_identifiers() self.assertEqual(user.login, self.username) self.assertEqual(user.uid, self.uid) # Now, the cache should have exactly one entry entry = UserCache.query.one() self.assertEqual(entry.user_id, self.uid) self.assertEqual(entry.username, self.username) self.assertEqual(entry.resolver, self.resolvername1) ts = entry.timestamp # delete the resolver, which also purges the cache self._delete_realm() # manually re-add the entry from above UserCache(self.username, self.username, self.resolvername1, self.uid, ts).save() # the username is fetched from the cache u_name = get_username(self.uid, self.resolvername1) self.assertEqual(u_name, self.username) # The `User` class also fetches the UID from the cache user2 = User(self.username, self.realm1, self.resolvername1) self.assertEqual(user2.uid, self.uid) # delete the cache r = delete_user_cache() # try to fetch the username. It is not in the cache and the # resolver does not exist anymore. u_name = get_username(self.uid, self.resolvername1) self.assertEqual(u_name, "") # similar case for the `User` class # The `User` class also tries to fetch the UID from the cache with self.assertRaises(UserError): user3 = User(self.username, self.realm1, self.resolvername1)
def test_03_get_identifiers(self): # create realm self._create_realm() # delete user_cache r = delete_user_cache() self.assertTrue(r >= 0) # The username is not in the cache. It is fetched from the resolver # At the same time the cache is filled. Implicitly we test the # _get_resolvers! user = User(self.username, self.realm1, self.resolvername1) uids = user.get_user_identifiers() self.assertEqual(user.login, self.username) self.assertEqual(user.uid, self.uid) # Now, the cache should have exactly one entry entry = UserCache.query.one() self.assertEqual(entry.user_id, self.uid) self.assertEqual(entry.username, self.username) self.assertEqual(entry.resolver, self.resolvername1) # delete the resolver, which also purges the cache self._delete_realm() # manually re-add the entry from above UserCache(entry.username, entry.resolver, entry.user_id, entry.timestamp).save() # the username is fetched from the cache u_name = get_username(self.uid, self.resolvername1) self.assertEqual(u_name, self.username) # The `User` class also fetches the UID from the cache user2 = User(self.username, self.realm1, self.resolvername1) self.assertEqual(user2.uid, self.uid) # delete the cache r = delete_user_cache() # try to fetch the username. It is not in the cache and the # resolver does not exist anymore. u_name = get_username(self.uid, self.resolvername1) self.assertEqual(u_name, "") # similar case for the `User` class # The `User` class also tries to fetch the UID from the cache with self.assertRaises(UserError): user3 = User(self.username, self.realm1, self.resolvername1)
def test_07_invalidate_save_resolver(self): self._create_realm() self._populate_cache() # call save_resolver on resolver1, which should invalidate all entries of "resolver1" # (even the expired 'hans2' one) save_resolver({"resolver": self.resolvername1, "type": "passwdresolver", "fileName": self.PWFILE, "type.fileName": "string", "desc.fileName": "Some change" }) self.assertEquals(UserCache.query.count(), 1) # Only hans3 in resolver2 should still be in the cache # We can use get_username to ensure it is fetched from the cache # because resolver2 does not actually exist u_name = get_username("uid2", "resolver2") self.assertEquals("hans3", u_name) delete_user_cache() self._delete_realm()
def test_02_get_resolvers(self): # enable user cache set_privacyidea_config(EXPIRATION_SECONDS, 600) # create realm self._create_realm() # delete user_cache r = delete_user_cache() self.assertTrue(r >= 0) # The username is not in the cache. It is fetched from the resolver # At the same time the cache is filled. user = User(self.username, self.realm1) self.assertEqual(user.login, self.username) # The user ID is fetched from the resolver self.assertEqual(user.uid, self.uid) # Now, the cache should have exactly one entry entry = UserCache.query.one() self.assertEqual(entry.user_id, self.uid) self.assertEqual(entry.username, self.username) self.assertEqual(entry.resolver, self.resolvername1) ts = entry.timestamp # delete the resolver, which also purges the cache self._delete_realm() # manually re-add the entry from above UserCache(self.username, self.username, self.resolvername1, self.uid, ts).save() # the username is fetched from the cache u_name = get_username(self.uid, self.resolvername1) self.assertEqual(u_name, self.username) # delete the cache r = delete_user_cache() # try to fetch the username. It is not in the cache and the # resolver does not exist anymore. u_name = get_username(self.uid, self.resolvername1) self.assertEqual(u_name, "")
def test_11_cache_expiration(self): # delete user_cache r = delete_user_cache() self.assertTrue(r >= 0) # populate the cache with artificial, somewhat "old", but still relevant data timestamp = datetime.now() - timedelta(seconds=300) UserCache("hans1", "hans1", "resolver1", "uid1", timestamp).save() UserCache("hans2", "hans2", "resolver1", "uid2", timestamp).save() # check that the cache is indeed queried self.assertEqual(get_username("uid1", "resolver1"), "hans1") self.assertEqual(User("hans2", "realm1", "resolver1").uid, "uid2") # check that the (non-existent) resolver is queried # for entries not contained in the cache self.assertEqual(get_username("uid3", "resolver1"), "") # TODO: Interestingly, if we mock `datetime` here to increase the time by one # day, this test works, but a subsequent test (test_ui_certificate) will fail # with weird error messages. So we do not use the datetime mock for now. #with self._patch_datetime_now('privacyidea.lib.usercache.datetime.datetime') as mock_datetime: with patch('privacyidea.lib.usercache.get_cache_time' ) as mock_get_cache_time: # Instead, we just decrease the cache time from 600 to 60 seconds, # which causes the entries above to be considered expired mock_get_cache_time.return_value = timedelta(seconds=60) # check that the cached entries are not queried anymore self.assertEqual(UserCache.query.count(), 2) self.assertEqual(get_username("uid1", "resolver1"), "") with self.assertRaises(UserError): User("hans2", "realm1", "resolver1") self.assertEqual(get_username("uid3", "resolver1"), "") # We add another, "current" entry UserCache("hans4", "hans4", "resolver1", "uid4", datetime.now()).save() self.assertEqual(UserCache.query.count(), 3) # we now remove old entries, only the newest remains delete_user_cache(expired=True) self.assertEqual(UserCache.query.count(), 1) self.assertEqual(UserCache.query.one().user_id, "uid4") # clean up delete_user_cache()
def test_11_cache_expiration(self): # delete user_cache r = delete_user_cache() self.assertTrue(r >= 0) # populate the cache with artificial, somewhat "old", but still relevant data timestamp = datetime.now() - timedelta(seconds=300) UserCache("hans1", "resolver1", "uid1", timestamp).save() UserCache("hans2", "resolver1", "uid2", timestamp).save() # check that the cache is indeed queried self.assertEqual(get_username("uid1", "resolver1"), "hans1") self.assertEqual(User("hans2", "realm1", "resolver1").uid, "uid2") # check that the (non-existent) resolver is queried # for entries not contained in the cache self.assertEqual(get_username("uid3", "resolver1"), "") # TODO: Interestingly, if we mock `datetime` here to increase the time by one # day, this test works, but a subsequent test (test_ui_certificate) will fail # with weird error messages. So we do not use the datetime mock for now. #with self._patch_datetime_now('privacyidea.lib.usercache.datetime.datetime') as mock_datetime: with patch('privacyidea.lib.usercache.get_cache_time') as mock_get_cache_time: # Instead, we just decrease the cache time from 600 to 60 seconds, # which causes the entries above to be considered expired mock_get_cache_time.return_value = timedelta(seconds=60) # check that the cached entries are not queried anymore self.assertEqual(UserCache.query.count(), 2) self.assertEqual(get_username("uid1", "resolver1"), "") with self.assertRaises(UserError): User("hans2", "realm1", "resolver1") self.assertEqual(get_username("uid3", "resolver1"), "") # We add another, "current" entry UserCache("hans4", "resolver1", "uid4", datetime.now()).save() self.assertEqual(UserCache.query.count(), 3) # we now remove old entries, only the newest remains delete_user_cache(expired=True) self.assertEqual(UserCache.query.count(), 1) self.assertEqual(UserCache.query.one().user_id, "uid4") # clean up delete_user_cache()
def test_04_delete_cache(self): now = datetime.now() UserCache("hans1", "resolver1", "uid1", now).save() UserCache("hans2", "resolver2", "uid2", now).save() r = UserCache.query.filter(UserCache.username == "hans1").first() self.assertTrue(r) r = UserCache.query.filter(UserCache.username == "hans2").first() self.assertTrue(r) # delete hans1 delete_user_cache(username="******") r = UserCache.query.filter(UserCache.username == "hans1").first() self.assertFalse(r) r = UserCache.query.filter(UserCache.username == "hans2").first() self.assertTrue(r) # delete resolver2 delete_user_cache(resolver="resolver2") r = UserCache.query.filter(UserCache.username == "hans1").first() self.assertFalse(r) r = UserCache.query.filter(UserCache.username == "hans2").first() self.assertFalse(r)
def test_04_delete_cache(self): now = datetime.now() UserCache("hans1", "hans1", "resolver1", "uid1", now).save() UserCache("hans2", "hans1", "resolver2", "uid2", now).save() r = UserCache.query.filter(UserCache.username == "hans1").first() self.assertTrue(r) r = UserCache.query.filter(UserCache.username == "hans2").first() self.assertTrue(r) # delete hans1 delete_user_cache(username="******") r = UserCache.query.filter(UserCache.username == "hans1").first() self.assertFalse(r) r = UserCache.query.filter(UserCache.username == "hans2").first() self.assertTrue(r) # delete resolver2 delete_user_cache(resolver="resolver2") r = UserCache.query.filter(UserCache.username == "hans1").first() self.assertFalse(r) r = UserCache.query.filter(UserCache.username == "hans2").first() self.assertFalse(r)
def test_02_get_resolvers(self): # create realm self._create_realm() # delete user_cache r = delete_user_cache() self.assertTrue(r >= 0) # The username is not in the cache. It is fetched from the resolver # At the same time the cache is filled. user = User(self.username, self.realm1) self.assertEqual(user.login, self.username) # The user ID is fetched from the resolver self.assertEqual(user.uid, self.uid) # Now, the cache should have exactly one entry entry = UserCache.query.one() self.assertEqual(entry.user_id, self.uid) self.assertEqual(entry.username, self.username) self.assertEqual(entry.resolver, self.resolvername1) # delete the resolver, which also purges the cache self._delete_realm() # manually re-add the entry from above UserCache(entry.username, entry.resolver, entry.user_id, entry.timestamp).save() # the username is fetched from the cache u_name = get_username(self.uid, self.resolvername1) self.assertEqual(u_name, self.username) # delete the cache r = delete_user_cache() # try to fetch the username. It is not in the cache and the # resolver does not exist anymore. u_name = get_username(self.uid, self.resolvername1) self.assertEqual(u_name, "")
def save_resolver(params): """ create a new resolver from request parameters and save the resolver in the database. If the resolver already exist, it is updated. If you update a resolver, you do not need to provide all parameters. Parameters you do not provide are left untouched. When updating a resolver you must not change the type! You do not need to specify the type, but if you specify a wrong type, it will produce an error. :param params: request parameters like "name" and "type" and the configuration parameters of the resolver config. :type params: dict :return: the database ID of the resolver :rtype: int """ # before we create the resolver in the database, we need to check # for the name and type thing... resolvername = getParam(params, 'resolver', required) resolvertype = getParam(params, 'type', required) update_resolver = False # check the name sanity_name_check(resolvername) # check the type resolvertypes = get_resolver_types() if resolvertype not in resolvertypes: raise Exception("resolver type : {0!s} not in {1!s}".format( resolvertype, str(resolvertypes))) # check the name resolvers = get_resolver_list(filter_resolver_name=resolvername) for r_name, resolver in resolvers.items(): if resolver.get("type") == resolvertype: # We found the resolver with the same name and the same type, # So we will update this resolver update_resolver = True else: raise Exception( "resolver with similar name and other type already " "exists: %s" % r_name) # create a dictionary for the ResolverConfig resolver_config = get_resolver_config_description(resolvertype) config_description = resolver_config.get(resolvertype).get('config', {}) data, types, desc = get_data_from_params(params, ['resolver', 'type'], config_description, resolvertype, resolvername) # Everything passed. So lets actually create the resolver in the DB if update_resolver: resolver_id = Resolver.query.filter( func.lower(Resolver.name) == resolvername.lower()).first().id else: resolver = Resolver(params.get("resolver"), params.get("type")) resolver_id = resolver.save() # create the config for key, value in data.items(): if types.get(key) == "password": if value == CENSORED: continue else: value = encryptPassword(value) ResolverConfig(resolver_id=resolver_id, Key=key, Value=value, Type=types.get(key, ""), Description=desc.get(key, "")).save() # Remove corresponding entries from the user cache delete_user_cache(resolver=resolvername) return resolver_id
def save_resolver(params): """ create a new resolver from request parameters and save the resolver in the database. If the resolver already exist, it is updated. If you update a resolver, you do not need to provide all parameters. Parameters you do not provide are left untouched. When updating a resolver you must not change the type! You do not need to specify the type, but if you specify a wrong type, it will produce an error. :param params: request parameters like "name" and "type" and the configuration parameters of the resolver config. :type params: dict :return: the database ID of the resolver :rtype: int """ # before we create the resolver in the database, we need to check # for the name and type thing... resolvername = getParam(params, 'resolver', required) resolvertype = getParam(params, 'type', required) update_resolver = False # check the name sanity_name_check(resolvername) # check the type resolvertypes = get_resolver_types() if resolvertype not in resolvertypes: raise Exception("resolver type : {0!s} not in {1!s}".format(resolvertype, unicode(resolvertypes))) # check the name resolvers = get_resolver_list(filter_resolver_name=resolvername) for r_name, resolver in resolvers.items(): if resolver.get("type") == resolvertype: # We found the resolver with the same name and the same type, # So we will update this resolver update_resolver = True else: raise Exception("resolver with similar name and other type already " "exists: %s" % r_name) # create a dictionary for the ResolverConfig resolver_config = get_resolver_config_description(resolvertype) config_description = resolver_config.get(resolvertype).get('config', {}) types = {} desc = {} data = {} for k in params: if k not in ['resolver', 'type']: if k.startswith('type.') is True: key = k[len('type.'):] types[key] = params.get(k) elif k.startswith('desc.') is True: key = k[len('desc.'):] desc[key] = params.get(k) else: data[k] = params.get(k) if k in config_description: types[k] = config_description.get(k) else: log.warn("the passed key %r is not a " "parameter for the resolver %r" % (k, resolvertype)) # Check that there is no type or desc without the data itself. # i.e. if there is a type.BindPW=password, then there must be a # BindPW=.... _missing = False for t in types: if t not in data: _missing = True for t in desc: if t not in data: _missing = True if _missing: raise Exception("type or description without necessary data! {0!s}".format( unicode(params))) # Everything passed. So lets actually create the resolver in the DB if update_resolver: resolver_id = Resolver.query.filter(func.lower(Resolver.name) == resolvername.lower()).first().id else: resolver = Resolver(params.get("resolver"), params.get("type")) resolver_id = resolver.save() # create the config for key, value in data.items(): if types.get(key) == "password": value = encryptPassword(value) ResolverConfig(resolver_id=resolver_id, Key=key, Value=value, Type=types.get(key, ""), Description=desc.get(key, "")).save() # Remove corresponding entries from the user cache delete_user_cache(resolver=resolvername) return resolver_id
def save_resolver(params): """ create a new resolver from request parameters and save the resolver in the database. If the resolver already exist, it is updated. If you update a resolver, you do not need to provide all parameters. Parameters you do not provide are left untouched. When updating a resolver you must not change the type! You do not need to specify the type, but if you specify a wrong type, it will produce an error. :param params: request parameters like "name" and "type" and the configuration parameters of the resolver config. :type params: dict :return: the database ID of the resolver :rtype: int """ # before we create the resolver in the database, we need to check # for the name and type thing... resolvername = getParam(params, 'resolver', required) resolvertype = getParam(params, 'type', required) update_resolver = False # check the name sanity_name_check(resolvername) # check the type resolvertypes = get_resolver_types() if resolvertype not in resolvertypes: raise Exception("resolver type : {0!s} not in {1!s}".format( resolvertype, unicode(resolvertypes))) # check the name resolvers = get_resolver_list(filter_resolver_name=resolvername) for r_name, resolver in resolvers.items(): if resolver.get("type") == resolvertype: # We found the resolver with the same name and the same type, # So we will update this resolver update_resolver = True else: raise Exception( "resolver with similar name and other type already " "exists: %s" % r_name) # create a dictionary for the ResolverConfig resolver_config = get_resolver_config_description(resolvertype) config_description = resolver_config.get(resolvertype).get('config', {}) types = {} desc = {} data = {} for k in params: if k not in ['resolver', 'type']: if k.startswith('type.') is True: key = k[len('type.'):] types[key] = params.get(k) elif k.startswith('desc.') is True: key = k[len('desc.'):] desc[key] = params.get(k) else: data[k] = params.get(k) if k in config_description: types[k] = config_description.get(k) else: log.warn("the passed key %r is not a " "parameter for the resolver %r" % (k, resolvertype)) # Check that there is no type or desc without the data itself. # i.e. if there is a type.BindPW=password, then there must be a # BindPW=.... _missing = False for t in types: if t not in data: _missing = True for t in desc: if t not in data: _missing = True if _missing: raise Exception( "type or description without necessary data! {0!s}".format(params)) # Everything passed. So lets actually create the resolver in the DB if update_resolver: resolver_id = Resolver.query.filter( func.lower(Resolver.name) == resolvername.lower()).first().id else: resolver = Resolver(params.get("resolver"), params.get("type")) resolver_id = resolver.save() # create the config for key, value in data.items(): if types.get(key) == "password": if value == CENSORED: continue else: value = encryptPassword(value) ResolverConfig(resolver_id=resolver_id, Key=key, Value=value, Type=types.get(key, ""), Description=desc.get(key, "")).save() # Remove corresponding entries from the user cache delete_user_cache(resolver=resolvername) return resolver_id