Module: check_mk
Branch: master
Commit: 277c6f6750f84b1205072764b6bde7f95a30c2eb
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=277c6f6750f84b…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Tue Nov 13 15:44:24 2012 +0100
userdb/ldap: Implemented page hook
---
web/htdocs/index.py | 4 +++
web/htdocs/userdb.py | 51 ++++++++++++++++++++++++++++++++-----------
web/htdocs/wato.py | 5 ++++
web/plugins/userdb/ldap.py | 16 ++++++++++++-
4 files changed, 61 insertions(+), 15 deletions(-)
diff --git a/web/htdocs/index.py b/web/htdocs/index.py
index e2fd68f..fc90b52 100644
--- a/web/htdocs/index.py
+++ b/web/htdocs/index.py
@@ -286,6 +286,10 @@ def handler(req, profiling = True):
else:
return result
+ # Call userdb page hooks which are executed on a regular base to e.g. syncronize
+ # information withough explicit user triggered actions
+ userdb.hook_page()
+
# Set all permissions, read site config, and similar stuff
config.login(html.req.user)
diff --git a/web/htdocs/userdb.py b/web/htdocs/userdb.py
index 164fb44..960bfe7 100644
--- a/web/htdocs/userdb.py
+++ b/web/htdocs/userdb.py
@@ -100,6 +100,11 @@ def create_non_existing_user(connector_id, username):
# Call the sync function for this new user
hook_sync(connector_id = connector_id, only_username = username)
+def user_locked(username):
+ import wato
+ users = wato.load_users()
+ return users[username].get('locked', False)
+
# .----------------------------------------------------------------------.
# | _ _ _ |
# | | | | | ___ ___ | | _____ |
@@ -113,19 +118,31 @@ def create_non_existing_user(connector_id, username):
def hook_login(username, password):
for connector in multisite_user_connectors:
handler = connector.get('login', None)
- if handler:
- result = handler(username, password)
- # None -> User unknown, means continue with other connectors
- # True -> success
- # False -> failed
- if result == True:
- # Check wether or not the user exists (and maybe create it)
- create_non_existing_user(connector['id'], username)
-
- return result
-
- elif result == False:
- return result
+ if not handler:
+ continue
+
+ result = handler(username, password)
+ # None -> User unknown, means continue with other connectors
+ # True -> success
+ # False -> failed
+ if result == True:
+ # Check wether or not the user exists (and maybe create it)
+ create_non_existing_user(connector['id'], username)
+
+ # Now, after successfull login (and optional user account
+ # creation), check wether or not the user is locked.
+ # In e.g. htpasswd connector this is checked by validating the
+ # password against the hash in the htpasswd file prefixed with
+ # a "!". But when using other conectors it might be neccessary
+ # to validate the user "locked" attribute.
+ lock_handler = connector.get('locked', None)
+ if lock_handler:
+ result = not lock_handler(username) # returns True if locked
+
+ return result
+
+ elif result == False:
+ return result
# Hook function can be registered here to be executed to synchronize all users.
# Is called on:
@@ -150,3 +167,11 @@ def hook_sync(connector_id = None, add_to_changelog = False, only_username = Non
)
else:
raise
+
+# Hook function can be registered here to execute actions on a "regular" base without
+# user triggered action. This hook is called on each page load.
+def hook_page():
+ for connector in multisite_user_connectors:
+ handler = connector.get('page', None)
+ if handler:
+ handler()
diff --git a/web/htdocs/wato.py b/web/htdocs/wato.py
index 7c96457..83f443c 100644
--- a/web/htdocs/wato.py
+++ b/web/htdocs/wato.py
@@ -8449,9 +8449,14 @@ def save_users(profiles):
# users from htpasswd are lost. If you start managing users with
# WATO, you should continue to do so or stop doing to for ever...
# Locked accounts get a '!' before their password. This disable it.
+ # FIXME: implement as 'save'-hook in htpasswd connector
filename = defaults.htpasswd_file
out = create_user_file(filename, "w")
for id, user in profiles.items():
+ # only process users which are handled by htpasswd connector
+ if user.get('connector', 'htpasswd') != 'htpasswd':
+ continue
+
if user.get("password"):
if user.get("locked", False):
locksym = '!'
diff --git a/web/plugins/userdb/ldap.py b/web/plugins/userdb/ldap.py
index d0b9b9e..8713402 100644
--- a/web/plugins/userdb/ldap.py
+++ b/web/plugins/userdb/ldap.py
@@ -261,6 +261,7 @@ ldap_attribute_plugins['alias'] = {
# Connector hook functions
#
+# This function only validates credentials, no locked checking or similar
def ldap_login(username, password):
ldap_connect()
# Returns None when the user is not found or not uniq, else returns the
@@ -328,17 +329,28 @@ def ldap_sync(add_to_changelog, only_username):
# Calculates the attributes of the users which are locked for users managed
# by this connector
-def ldap_locked():
+def ldap_locked_attributes():
locked = set([ 'password' ]) # This attributes are locked in all cases!
for key in config.ldap_active_plugins:
locked.update(ldap_attribute_plugins[key]['set_attributes'])
return list(locked)
+# Is called on every multisite http request
+def ldap_page():
+ # FIXME: Implement
+ pass
+
multisite_user_connectors.append({
'id': 'ldap',
'title': _('LDAP (AD, OpenLDAP)'),
'login': ldap_login,
'sync': ldap_sync,
- 'locked_attributes': ldap_locked,
+ 'page': ldap_page,
+ 'locked': user_locked, # no ldap check, just check the WATO attribute.
+ # This handles setups where the locked attribute is not
+ # synchronized and the user is enabled in LDAP and disabled
+ # in Check_MK. When the user is locked in LDAP a login is
+ # not possible.
+ 'locked_attributes': ldap_locked_attributes,
})
Module: check_mk
Branch: master
Commit: 0b575ddf14222bd6fae3389bebc099fc376289c4
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=0b575ddf14222b…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Tue Oct 30 13:35:25 2012 +0100
Restructured cookie auth cookies (all auth cookies will be invalid
after update -> all users have to login again)
---
ChangeLog | 2 ++
web/htdocs/login.py | 29 ++++++++++++++++++-----------
web/htdocs/wato.py | 14 +++++++++++++-
3 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 2d7a325..83f7db0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -16,6 +16,8 @@
* Max. number of queued connections on status sockets is configurable now
Multisite:
+ * Restructured cookie auth cookies (all auth cookies will be invalid
+ after update -> all users have to login again)
* Enable automation login with _username= and _secret=, while
_secret is the content of var/check_mk/web/$USER/automation.secret
* FIX: Fixed releasing of locks and livestatus connections when logging out
diff --git a/web/htdocs/login.py b/web/htdocs/login.py
index 1ca86c4..4fc70fb 100644
--- a/web/htdocs/login.py
+++ b/web/htdocs/login.py
@@ -82,25 +82,32 @@ def load_secret():
return secret
+# Load the password serial of the user. This serial identifies the current config
+# state of the user account. If either the password is changed or the account gets
+# locked the serial is increased by WATO and all cookies get invalidated.
+def load_serial(user_id):
+ users = wato.load_users()
+ return users.get(user_id, {}).get('serial', 0)
+
# Generates the hash to be added into the cookie value
-def generate_hash(username, now, pwhash):
+def generate_hash(username, now, serial):
secret = load_secret()
- return md5.md5(username + now + pwhash + secret).hexdigest()
+ return md5.md5(username + now + str(serial) + secret).hexdigest()
def del_auth_cookie():
name = site_cookie_name()
if html.has_cookie(name):
html.del_cookie(name)
-def auth_cookie_value(username, pwhash):
+def auth_cookie_value(username, serial):
now = str(time.time())
- return username + ':' + now + ':' + generate_hash(username, now, pwhash)
+ return username + ':' + now + ':' + generate_hash(username, now, serial)
-def set_auth_cookie(username, pwhash):
- html.set_cookie(site_cookie_name(), auth_cookie_value(username, pwhash))
+def set_auth_cookie(username, serial):
+ html.set_cookie(site_cookie_name(), auth_cookie_value(username, serial))
def get_cookie_value():
- return auth_cookie_value(config.user_id, load_htpasswd()[config.user_id])
+ return auth_cookie_value(config.user_id, load_serial(config.user_id))
def check_auth_cookie(cookie_name):
username, issue_time, cookie_hash = html.cookie(cookie_name, '::').split(':', 2)
@@ -114,10 +121,10 @@ def check_auth_cookie(cookie_name):
users = load_htpasswd()
if not username in users:
raise MKAuthException(_('Username is unknown'))
- pwhash = users[username]
# Validate the hash
- if cookie_hash != generate_hash(username, issue_time, pwhash):
+ serial = load_serial(username)
+ if cookie_hash != generate_hash(username, issue_time, serial):
raise MKAuthException(_('Invalid credentials'))
# Once reached this the cookie is a good one. Renew it!
@@ -126,7 +133,7 @@ def check_auth_cookie(cookie_name):
# b) A logout is requested
if (html.req.myfile != 'logout' or html.has_var('_ajaxid')) \
and cookie_name == site_cookie_name():
- set_auth_cookie(username, pwhash)
+ set_auth_cookie(username, serial)
# Return the authenticated username
return username
@@ -181,7 +188,7 @@ def do_login():
# a) Set the auth cookie
# b) Unset the login vars in further processing
# c) Show the real requested page (No redirect needed)
- set_auth_cookie(username, users[username])
+ set_auth_cookie(username, load_serial(username))
# Use redirects for URLs or simply execute other handlers for
# mulitsite modules
diff --git a/web/htdocs/wato.py b/web/htdocs/wato.py
index b1b9dba..0a255a5 100644
--- a/web/htdocs/wato.py
+++ b/web/htdocs/wato.py
@@ -7805,13 +7805,19 @@ def mode_edit_user(phase):
if password:
new_user["password"] = encrypt_password(password)
+ # Set initial password serial or increase existing
+ if new:
+ new_user["serial"] = 0
+ else:
+ new_user["serial"] += 1
+
# Email address
email = html.var("email").strip()
regex_email = '^[-a-zäöüÄÖÜA-Z0-9_.]+(a)xn--[-a-za-z0-9]+(\-4kba73ab2jc.[a-zA-Z]+)*$'
if email and not re.match(regex_email, email):
raise MKUserError("email", _("'%s' is not a valid email address." % email))
new_user["email"] = email
-
+
# Pager
pager = html.var("pager").strip()
new_user["pager"] = pager
@@ -10875,6 +10881,12 @@ def page_user_profile():
users[config.user_id]['password'] = encrypt_password(password)
+ # Increase serial to invalidate old cookies
+ if 'serial' not in users[config.user_id]:
+ users[config.user_id]['serial'] = 1
+ else:
+ users[config.user_id]['serial'] += 1
+
save_users(users)
success = True
Module: check_mk
Branch: master
Commit: 049d209bc2193762d16e8f6082896d378598cece
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=049d209bc21937…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Thu Nov 15 11:14:48 2012 +0100
userdb/ldap: Added option to add custom vars to contacts.mk or multisite users.mk
---
web/htdocs/userdb.py | 10 ++++++++++
web/htdocs/wato.py | 8 ++++++--
web/plugins/userdb/ldap.py | 34 +++++++++++++++++++++++++++++-----
3 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/web/htdocs/userdb.py b/web/htdocs/userdb.py
index f64e3c7..a216ec0 100644
--- a/web/htdocs/userdb.py
+++ b/web/htdocs/userdb.py
@@ -74,6 +74,16 @@ def locked_attributes(connector_id):
connector = get_connector(connector_id)
return connector.get('locked_attributes', lambda: [])()
+# Returns a list of multisite attributes
+def multisite_attributes(connector_id):
+ connector = get_connector(connector_id)
+ return connector.get('multisite_attributes', lambda: [])()
+
+# Returns a list of non contact attributes
+def non_contact_attributes(connector_id):
+ connector = get_connector(connector_id)
+ return connector.get('non_contact_attributes', lambda: [])()
+
# This is a function needed in WATO and the htpasswd module. This should
# really be modularized one day. Till this day this is a good place ...
def encrypt_password(password, salt = None):
diff --git a/web/htdocs/wato.py b/web/htdocs/wato.py
index 746e3bf..2de411c 100644
--- a/web/htdocs/wato.py
+++ b/web/htdocs/wato.py
@@ -8417,6 +8417,8 @@ def save_users(profiles):
"locked",
"automation_secret",
"language",
+ "serial",
+ "connector",
] + custom_values
# Keys to put into multisite configuration
@@ -8426,19 +8428,21 @@ def save_users(profiles):
"automation_secret",
"alias",
"language",
+ "serial",
+ "connector",
] + custom_values
# Remove multisite keys in contacts.
contacts = dict(
e for e in
- [ (id, split_dict(user, non_contact_keys, False))
+ [ (id, split_dict(user, non_contact_keys + userdb.non_contact_attributes(user.get('connector')), False))
for (id, user)
in profiles.items() ])
# Only allow explicitely defined attributes to be written to multisite config
users = {}
for uid, profile in profiles.items():
- users[uid] = dict([ (p, val) for p, val in profile.items() if p in multisite_keys ])
+ users[uid] = dict([ (p, val) for p, val in profile.items() if p in multisite_keys + userdb.multisite_attributes(user.get('connector'))])
# Check_MK's monitoring contacts
filename = root_dir + "contacts.mk"
diff --git a/web/plugins/userdb/ldap.py b/web/plugins/userdb/ldap.py
index a6f8669..e605426 100644
--- a/web/plugins/userdb/ldap.py
+++ b/web/plugins/userdb/ldap.py
@@ -270,7 +270,7 @@ ldap_attribute_plugins['email'] = {
# gathered from ldap
'convert': ldap_convert_mail,
# User-Attributes to be written by this plugin and will be locked in WATO
- 'set_attributes': [ 'email' ],
+ 'lock_attributes': [ 'email' ],
}
ldap_attribute_plugins['alias'] = {
@@ -278,7 +278,7 @@ ldap_attribute_plugins['alias'] = {
'help': _('Synchronizes the alias of the LDAP user account into Check_MK.'),
'needed_attributes': lambda: ldap_attrs(['cn']),
'convert': lambda user_id, ldap_user, user: ldap_convert_simple(user_id, ldap_user, user, 'alias', 'cn'),
- 'set_attributes': [ 'alias' ],
+ 'lock_attributes': [ 'alias' ],
}
# Checks wether or not the user auth must be invalidated (increasing the serial).
@@ -313,7 +313,13 @@ ldap_attribute_plugins['auth_expire'] = {
'the password has changed in LDAP or the account has been locked.'),
'needed_attributes': lambda: ldap_attrs(['pw_changed']),
'convert': ldap_convert_auth_expire,
- 'set_attributes': [],
+ 'lock_attributes': [],
+ # When a plugin introduces new user attributes, it should declare the output target for
+ # this attribute. It can either be written to the multisites users.mk or the check_mk
+ # contacts.mk to be forwarded to nagios. Undeclared attributes are stored in the check_mk
+ # contacts.mk file.
+ 'multisite_attributes': ['ldap_pw_last_changed'],
+ 'non_contact_attributes': ['ldap_pw_last_changed'],
}
# .----------------------------------------------------------------------.
@@ -401,9 +407,25 @@ def ldap_sync(add_to_changelog, only_username):
def ldap_locked_attributes():
locked = set([ 'password' ]) # This attributes are locked in all cases!
for key in config.ldap_active_plugins:
- locked.update(ldap_attribute_plugins[key]['set_attributes'])
+ locked.update(ldap_attribute_plugins[key]['lock_attributes'])
return list(locked)
+# Calculates the attributes added in this connector which shal be written to
+# the multisites users.mk
+def ldap_multisite_attributes():
+ attrs = set([])
+ for key in config.ldap_active_plugins:
+ attrs.update(ldap_attribute_plugins[key].get('multisite_attributes', []))
+ return list(attrs)
+
+# Calculates the attributes added in this connector which shal NOT be written to
+# the check_mks contacts.mk
+def ldap_non_contact_attributes():
+ attrs = set([])
+ for key in config.ldap_active_plugins:
+ attrs.update(ldap_attribute_plugins[key].get('non_contact_attributes', []))
+ return list(attrs)
+
# Is called on every multisite http request
def ldap_page():
try:
@@ -429,5 +451,7 @@ multisite_user_connectors.append({
# synchronized and the user is enabled in LDAP and disabled
# in Check_MK. When the user is locked in LDAP a login is
# not possible.
- 'locked_attributes': ldap_locked_attributes,
+ 'locked_attributes': ldap_locked_attributes,
+ 'multisite_attributes': ldap_multisite_attributes,
+ 'non_contact_attributes': ldap_multisite_attributes,
})
Module: check_mk
Branch: master
Commit: 266f6bdf0f53013b886117a5d39d4c9b3ee09463
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=266f6bdf0f5301…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Wed Oct 31 09:24:13 2012 +0100
Basic user attributes can now be locked by the user connectors
---
web/htdocs/userdb.py | 16 +++++++++
web/htdocs/wato.py | 74 ++++++++++++++++++++++++++++++++-------
web/plugins/userdb/htpasswd.py | 2 +
3 files changed, 78 insertions(+), 14 deletions(-)
diff --git a/web/htdocs/userdb.py b/web/htdocs/userdb.py
index 09345e4..18ee600 100644
--- a/web/htdocs/userdb.py
+++ b/web/htdocs/userdb.py
@@ -49,6 +49,22 @@ def load_plugins():
def list_user_connectors():
return [ (c['id'], c['title']) for c in multisite_user_connectors ]
+# Returns the connector dictionary
+def get_connector(connector_id):
+ if connector_id is None:
+ connector_id = 'htpasswd'
+ for connector in multisite_user_connectors:
+ if connector['id'] == connector_id:
+ return connector
+
+# Returns a list of locked attributes. If connector is None the htpasswd
+# connector is assumed.
+def locked_attributes(connector_id):
+ for connector in multisite_user_connectors:
+ if connector['id'] == connector_id:
+ return connector.get('locked_attributes', None)
+ return []
+
# This is a function needed in WATO and the htpasswd module. This should
# really be modularized one day. Till this day this is a good place ...
def encrypt_password(password, salt = None):
diff --git a/web/htdocs/wato.py b/web/htdocs/wato.py
index 8c6dd96..e94cc00 100644
--- a/web/htdocs/wato.py
+++ b/web/htdocs/wato.py
@@ -7616,6 +7616,7 @@ def mode_users(phase):
html.write("<table class=data>")
html.write("<tr><th>" + _("Actions") + "<th>"
+ _("Name")
+ + "</th><th>" + _("Connector")
+ "</th><th>" + _("Authentication")
+ "</th><th>" + _("Locked")
+ "</th><th>" + _("Full Name")
@@ -7645,6 +7646,9 @@ def mode_users(phase):
# ID
html.write("<td>%s</td>" % id)
+ # Connector
+ html.write("<td>%s</td>" % userdb.get_connector(user.get('connector'))['title'])
+
# Authentication
if "automation_secret" in user:
auth_method = _("Automation")
@@ -7738,6 +7742,13 @@ def mode_edit_user(phase):
else:
user = users.get(userid, {})
+ # Returns true if an attribute is locked and should be read only. Is only
+ # checked when modifying an existing user
+ # FIXME: Also lock those attributes on form processing
+ locked_attributes = userdb.locked_attributes(user.get('connector'))
+ def is_locked(attr):
+ return not new and attr in locked_attributes
+
# Load data that is referenced - in order to display dropdown
# boxes and to check for validity.
contact_groups = load_group_information().get("contact", {})
@@ -7897,31 +7908,44 @@ def mode_edit_user(phase):
html.write(userid)
html.hidden_field("userid", userid)
+ def lockable_input(name, dflt):
+ if not is_locked(name):
+ html.text_input(name, user.get(name, dflt), size = 50)
+ else:
+ html.write(user.get(name, dflt))
+ html.hidden_field(name, user.get(name, dflt))
+
# Full name
forms.section(_("Full name"))
- html.text_input("alias", user.get("alias", userid), size = 50)
+ lockable_input('alias', userid)
html.help(_("Full name or alias of the user"))
# Email address
forms.section(_("Email address"))
- html.text_input("email", user.get("email", ""), size = 50)
+ lockable_input('email', '')
html.help(_("The email address is optional and is needed "
"if the user is a monitoring contact and receives notifications "
"via Email."))
forms.section(_("Pager address"))
- html.text_input("pager", user.get("pager", ""), size = 50)
+ lockable_input('pager', '')
html.help(_("The pager address is optional "))
+
forms.header(_("Security"))
forms.section(_("Authentication"))
is_automation = user.get("automation_secret", None) != None
html.radiobutton("authmethod", "password", not is_automation,
_("Normal user login with password"))
html.write("<ul><table><tr><td>%s</td><td>" % _("password:"))
- html.password_input("password", autocomplete="off")
- html.write("</td></tr><tr><td>%s</td><td>" % _("repeat:"))
- html.password_input("password2", autocomplete="off")
- html.write(" (%s)" % _("optional"))
+ if not is_locked('password'):
+ html.password_input("password", autocomplete="off")
+ html.write("</td></tr><tr><td>%s</td><td>" % _("repeat:"))
+ html.password_input("password2", autocomplete="off")
+ html.write(" (%s)" % _("optional"))
+ else:
+ html.write('<i>%s</i>' % _('The password can not be changed (It is locked by the user connector).'))
+ html.hidden_field('password', '')
+ html.hidden_field('password2', '')
html.write("</td></tr></table></ul>")
html.radiobutton("authmethod", "secret", is_automation,
_("Automation secret for machine accounts"))
@@ -7947,7 +7971,11 @@ def mode_edit_user(phase):
# Locking
forms.section(_("Disable password"), simple=True)
- html.checkbox("locked", user.get("locked", False), label = _("disable the login to this account"))
+ if not is_locked('locked'):
+ html.checkbox("locked", user.get("locked", False), label = _("disable the login to this account"))
+ else:
+ html.write(user.get("locked", False) and _('Login disabled') or _('Login possible'))
+ html.hidden_field('locked', user.get("locked", False) and '1' or '')
html.help(_("Disabling the password will prevent a user from logging in while "
"retaining the original password. Notifications are not affected "
"by this setting."))
@@ -7957,9 +7985,18 @@ def mode_edit_user(phase):
entries = roles.items()
entries.sort(cmp = lambda a,b: cmp((a[1]["alias"],a[0]), (b[1]["alias"],b[0])))
for role_id, role in entries:
- html.checkbox("role_" + role_id, role_id in user.get("roles", []))
- url = make_link([("mode", "edit_role"), ("edit", role_id)])
- html.write("<a href='%s'>%s</a><br>" % (url, role["alias"]))
+ if not is_locked('roles'):
+ html.checkbox("role_" + role_id, role_id in user.get("roles", []))
+ url = make_link([("mode", "edit_role"), ("edit", role_id)])
+ html.write("<a href='%s'>%s</a><br>" % (url, role["alias"]))
+ else:
+ is_member = role_id in user.get("roles", [])
+ html.hidden_field("role_" + role_id, is_member and '1' or '')
+ if not is_member:
+ html.write('<i>%s</i>' % _('No roles assigned.'))
+ else:
+ url = make_link([("mode", "edit_role"), ("edit", role_id)])
+ html.write("<a href='%s'>%s</a><br>" % (url, role["alias"]))
html.help(_("By assigning roles to a user he obtains permissions. "
"If a user has more than one role, he gets the maximum of all "
"permissions of his roles. "
@@ -7980,9 +8017,18 @@ def mode_edit_user(phase):
for alias, gid in entries:
if not alias:
alias = gid
- html.checkbox("cg_" + gid, gid in user.get("contactgroups", []))
- url = make_link([("mode", "edit_contact_group"), ("edit", gid)])
- html.write(" <a href=\"%s\">%s</a><br>" % (url, alias))
+ if not is_locked('contactgroups'):
+ html.checkbox("cg_" + gid, gid in user.get("contactgroups", []))
+ url = make_link([("mode", "edit_contact_group"), ("edit", gid)])
+ html.write(" <a href=\"%s\">%s</a><br>" % (url, alias))
+ else:
+ is_member = gid in user.get("contactgroups", [])
+ html.hidden_field("cg_" + gid, is_member and '1' or '')
+ if not is_member:
+ html.write('<i>%s</i>' % _('No contact groups assigned.'))
+ else:
+ url = make_link([("mode", "edit_contact_group"), ("edit", gid)])
+ html.write("<a href='%s'>%s</a><br>" % (url, alias))
html.help(_("Contact groups are used to assign monitoring "
"objects to users. If you haven't defined any contact groups yet, "
diff --git a/web/plugins/userdb/htpasswd.py b/web/plugins/userdb/htpasswd.py
index e1f4dde..4ca5a45 100644
--- a/web/plugins/userdb/htpasswd.py
+++ b/web/plugins/userdb/htpasswd.py
@@ -55,6 +55,8 @@
# locked_attributes
# List of user attributes locked for all users attached to this
# connector. Those locked attributes are read-only in WATO.
+# Lockable attributes at the moment:
+# password, locked, roles, contactgroups, alias, email, pager
import crypt
import defaults
Module: check_mk
Branch: master
Commit: 50835a50ba5044761964b839193ab8c4c44276c3
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=50835a50ba5044…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Thu Nov 15 10:51:57 2012 +0100
Store last changed pw as string, not list; Catching all exceptions in page handler by default
---
web/htdocs/userdb.py | 13 ++++++++++++-
web/plugins/userdb/ldap.py | 11 ++++++++---
2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/web/htdocs/userdb.py b/web/htdocs/userdb.py
index 643c048..f64e3c7 100644
--- a/web/htdocs/userdb.py
+++ b/web/htdocs/userdb.py
@@ -194,8 +194,19 @@ def hook_save(users):
# Hook function can be registered here to execute actions on a "regular" base without
# user triggered action. This hook is called on each page load.
+# Catch all exceptions and log them to apache error log. Let exceptions raise trough
+# when debug mode is enabled.
def hook_page():
for connector in enabled_connectors():
handler = connector.get('page', None)
- if handler:
+ if not handler:
+ continue
+ try:
handler()
+ except:
+ if config.debug:
+ raise
+ else:
+ import traceback
+ html.log('Exception (%s, page handler): %s' %
+ (connector['id'], traceback.format_exc()))
diff --git a/web/plugins/userdb/ldap.py b/web/plugins/userdb/ldap.py
index fec04e0..a6f8669 100644
--- a/web/plugins/userdb/ldap.py
+++ b/web/plugins/userdb/ldap.py
@@ -113,7 +113,12 @@ def ldap_connect():
ldap_connection.protocol_version = config.ldap_connection['version']
ldap_default_bind()
+ except ldap.SERVER_DOWN:
+ ldap_connection = None # Invalidate connection on failure
+ raise MKLDAPException(_('The LDAP connector is unable to connect to the LDAP server.'))
+
except ldap.LDAPError, e:
+ html.write(repr(e))
ldap_connection = None # Invalidate connection on failure
raise MKLDAPException(e)
@@ -290,12 +295,12 @@ def ldap_convert_auth_expire(user_id, ldap_user, user):
# value has been changed.
if 'ldap_pw_last_changed' not in user:
- return {'ldap_pw_last_changed': ldap_user[changed_attr]} # simply store
+ return {'ldap_pw_last_changed': ldap_user[changed_attr][0]} # simply store
# Update data (and invalidate auth) if the attribute has changed
- if user['ldap_pw_last_changed'] != ldap_user[changed_attr]:
+ if user['ldap_pw_last_changed'] != ldap_user[changed_attr][0]:
return {
- 'ldap_pw_last_changed': ldap_user[changed_attr],
+ 'ldap_pw_last_changed': ldap_user[changed_attr][0],
'serial': user.get('serial', 0) + 1,
}