# HG changeset patch # User Matthew Wild # Date 1640184526 0 # Node ID bfd4af4caddc3195f59f2240d29ff4017b7fd7b6 # Parent 5a42cb84c8ee6c64035a186ab58813d2851b7dc9 mod_password_policy: Support for additional policies provided by other modules E.g. check a password contains an uppercase character: module:provides("password-policy", { name = "contains_uppercase"; check_password = function (password, policy) return (policy ~= true) or (not not password:match("%u")); end; }) Config: password_policy = { contains_uppercase = true; } diff -r 5a42cb84c8ee -r bfd4af4caddc mod_password_policy/mod_password_policy.lua --- a/mod_password_policy/mod_password_policy.lua Wed Dec 22 14:43:53 2021 +0000 +++ b/mod_password_policy/mod_password_policy.lua Wed Dec 22 14:48:46 2021 +0000 @@ -9,6 +9,10 @@ -- } +local it = require "util.iterators"; +local set = require "util.set"; +local st = require "util.stanza"; + local options = module:get_option("password_policy"); options = options or {}; @@ -17,7 +21,21 @@ options.exclude_username = true; end -local st = require "util.stanza"; +local builtin_policies = set.new({ "length", "exclude_username" }); +local extra_policies = set.new(it.to_array(it.keys(options))) - builtin_policies; + +local extra_policy_handlers = {}; + +module:handle_items("password-policy-provider", function (event) + -- Password policy handler added + local item = event.item; + module:log("error", "Adding password policy handler '%s'", item.name); + extra_policy_handlers[item.name] = item.check_password; +end, function (event) + -- Password policy handler removed + local item = event.item; + extra_policy_handlers[item.name] = nil; +end); function check_password(password, additional_info) if not password or password == "" then @@ -34,6 +52,19 @@ return nil, "Password must not include your username", "username"; end end + + for policy in extra_policies do + local handler = extra_policy_handlers[policy]; + if not handler then + module:log("error", "No policy handler found for '%s' (typo, or module not loaded?)", policy); + return nil, "Internal error while verifying password", "internal"; + end + local ok, reason_text, reason_name = handler(password, options[policy], additional_info); + if ok ~= true then + return nil, reason_text or ("Password failed %s check"):format(policy), reason_name or policy; + end + end + return true; end