Skip to content
Permalink
Browse files

Merge pull request #1824 from privacyidea/1823/event-handler-config

Only re-read event handler definitions if the configuration has changed
  • Loading branch information...
cornelinux committed Aug 27, 2019
2 parents 2608889 + 94838fb commit 4599835a5679357c0ce8dad7f6f707db2399a59e
Showing with 40 additions and 23 deletions.
  1. +13 −5 privacyidea/lib/config.py
  2. +11 −15 privacyidea/lib/event.py
  3. +3 −2 privacyidea/models.py
  4. +13 −1 tests/test_lib_events.py
@@ -41,7 +41,7 @@

from .log import log_with
from ..models import (Config, db, Resolver, Realm, PRIVACYIDEA_TIMESTAMP,
save_config_timestamp, Policy)
save_config_timestamp, Policy, EventHandler)
from privacyidea.lib.framework import get_request_local_store, get_app_config_value, get_app_local_store
from .crypto import encryptPassword
from .crypto import decryptPassword
@@ -66,8 +66,8 @@
class SharedConfigClass(object):
"""
A shared config class object is shared between threads and is supposed
to store the current configuration with resolvers, realms and policies,
along with the timestamp of the configuration.
to store the current configuration with resolvers, realms, policies
and event handler definitions along with the timestamp of the configuration.
The method ``_reload_from_db()`` compares this timestamp against the
timestamp in the database (while taking the PI_CHECK_RELOAD_CONFIG
@@ -85,6 +85,7 @@ def __init__(self):
self.realm = {}
self.default_realm = None
self.policies = []
self.events = []
self.timestamp = None

def _reload_from_db(self):
@@ -104,6 +105,7 @@ def _reload_from_db(self):
realmconfig = {}
default_realm = None
policies = []
events = []
# Load system configuration
for sysconf in Config.query.all():
config[sysconf.Key] = {
@@ -140,6 +142,9 @@ def _reload_from_db(self):
# Load all policies
for pol in Policy.query.all():
policies.append(pol.get())
# Load all events
for event in EventHandler.query.order_by(EventHandler.ordering):
events.append(event.get())
# Finally, set the current timestamp
timestamp = datetime.datetime.now()
with self._config_lock:
@@ -148,6 +153,7 @@ def _reload_from_db(self):
self.realm = realmconfig
self.default_realm = default_realm
self.policies = policies
self.events = events
self.timestamp = timestamp

def _clone(self):
@@ -161,6 +167,7 @@ def _clone(self):
self.realm,
self.default_realm,
self.policies,
self.events,
self.timestamp
)

@@ -177,17 +184,18 @@ def reload_and_clone(self):
class LocalConfigClass(object):
"""
The Config_Object will contain all database configuration of system
config, resolvers, realms and policies.
config, resolvers, realms, policies and event handler definitions.
It will be cloned from the shared config object at the beginning of the
request and is supposed to stay alive and unchanged during the request.
"""
def __init__(self, config, resolver, realm, default_realm, policies, timestamp):
def __init__(self, config, resolver, realm, default_realm, policies, events, timestamp):
self.config = config
self.resolver = resolver
self.realm = realm
self.default_realm = default_realm
self.policies = policies
self.events = events
self.timestamp = timestamp

def get_config(self, key=None, default=None, role="admin",
@@ -22,9 +22,9 @@
# License along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
from privacyidea.lib.config import get_config_object
from privacyidea.lib.utils import fetch_one_resource
from privacyidea.models import EventHandler, EventHandlerOption, db
from privacyidea.lib.error import ParameterError
from privacyidea.lib.audit import getAudit
import functools
import logging
@@ -244,17 +244,19 @@ def delete_event(event_id):
class EventConfiguration(object):
"""
This class is supposed to contain the event handling configuration during
the Request. It can be read initially (in the init method) an can be
accessed later during the request.
the Request.
The currently defined events are fetched from the request-local config object.
"""

def __init__(self):
self.eventlist = []
self._read_events()
pass

@property
def events(self):
return self.eventlist
"""
Shortcut for retrieving the currently defined event handlers from the request-local config object.
"""
return get_config_object().events

def get_handled_events(self, eventname, position="post"):
"""
@@ -265,7 +267,7 @@ def get_handled_events(self, eventname, position="post"):
:param position: the position of the event definition
:return:
"""
eventlist = [e for e in self.eventlist if (
eventlist = [e for e in self.events if (
eventname in e.get("event") and e.get("active") and e.get("position") == position)]
return eventlist

@@ -280,13 +282,7 @@ def get_event(self, eventid):
"""
if eventid is not None:
eventid = int(eventid)
eventlist = [e for e in self.eventlist if e.get("id") == eventid]
eventlist = [e for e in self.events if e.get("id") == eventid]
return eventlist
else:
return self.eventlist

def _read_events(self):
q = EventHandler.query.order_by(EventHandler.ordering)
for e in q:
self.eventlist.append(e.get())

return self.events
@@ -1759,7 +1759,6 @@ def save(self):
if self.id is None:
# create a new one
db.session.add(self)
db.session.commit()
else:
# update
EventHandler.query.filter_by(id=self.id).update({
@@ -1772,7 +1771,8 @@ def save(self):
"condition": self.condition,
"action": self.action
})
db.session.commit()
save_config_timestamp()
db.session.commit()
return self.id

def delete(self):
@@ -1786,6 +1786,7 @@ def delete(self):
db.session.query(EventHandlerCondition) \
.filter(EventHandlerCondition.eventhandler_id == ret) \
.delete()
save_config_timestamp()
db.session.commit()
return ret

@@ -12,6 +12,7 @@
from .base import MyTestCase, FakeFlaskG, FakeAudit
from privacyidea.lib.eventhandler.usernotification import (
UserNotificationEventHandler, NOTIFY_TYPE)
from privacyidea.lib.config import get_config_object
from privacyidea.lib.eventhandler.tokenhandler import (TokenEventHandler,
ACTION_TYPE, VALIDITY)
from privacyidea.lib.eventhandler.scripthandler import ScriptEventHandler, SCRIPT_WAIT, SCRIPT_BACKGROUND
@@ -56,6 +57,8 @@ def test_01_create_update_delete(self):
conditions={},
options={"emailconfig": "themis",
"always": "immer"})
# retrieve the current config timestamp
current_timestamp = get_config_object().timestamp

self.assertEqual(r, 2)
# Update the first event
@@ -67,11 +70,19 @@ def test_01_create_update_delete(self):
id=eid)
self.assertEqual(r, eid)

# check that the config timestamp has been updated
self.assertGreater(get_config_object().timestamp, current_timestamp)
current_timestamp = get_config_object().timestamp

event_config = EventConfiguration()
self.assertEqual(len(event_config.events), 2)
# delete
r = delete_event(eid)
self.assertTrue(r)

# check that the config timestamp has been updated
self.assertGreater(get_config_object().timestamp, current_timestamp)
current_timestamp = get_config_object().timestamp
event_config = EventConfiguration()
self.assertEqual(len(event_config.events), 1)

@@ -82,6 +93,8 @@ def test_01_create_update_delete(self):
n_eid = events[0].get("id")
# Disable this event in the database
enable_event(n_eid, False)
# check that the config timestamp has been updated
self.assertGreater(get_config_object().timestamp, current_timestamp)
# Reread event config from the database
event_config = EventConfiguration()
events = event_config.get_handled_events("token_init")
@@ -92,7 +105,6 @@ def test_01_create_update_delete(self):
event_config = EventConfiguration()
events = event_config.get_handled_events("token_init")
self.assertEqual(len(events), 1)

# If eventid is None, then the whole list is returned
r = event_config.get_event(None)
self.assertEqual(r, event_config.events)

0 comments on commit 4599835

Please sign in to comment.
You can’t perform that action at this time.