Implementing password policy modules


The password policy modules must respect following API:

class ldapcherry.ppolicy.PPolicy(config, logger)[source]
__init__(config, logger)[source]

Password policy constructor

  • config (dict {'config key': 'value'}) – the configuration of the ppolicy
  • logger (python logger) – the cherrypy error logger object

Check if a password match the ppolicy

Parameters:password (string) – the password to check
Return type:dict with keys ‘match’ a boolean (True if ppolicy matches, False otherwise) and ‘reason’, an explaination string

Give information about the ppolicy

Return type:a string describing the ppolicy


Parameters are declared in the main configuration file, inside the ppolicy section.

After having set self.config to config in the constructor, parameters can be recovered by self.get_param:

class ldapcherry.ppolicy.PPolicy(config, logger)[source]
get_param(param, default=None)[source]

Get a parameter in config (handle default value)

  • param (string) – name of the parameter to recover
  • default (string or None) – the default value, raises an exception if param is not in configuration and default is None (which is the default value).
Return type:

the value of the parameter or the default value if not set in configuration


Here is the simple default ppolicy module that comes with LdapCherry:

# -*- coding: utf-8 -*-
# vim:set expandtab tabstop=4 shiftwidth=4:
# The MIT License (MIT)
# LdapCherry
# Copyright (c) 2014 Carpentier Pierre-Francois

import ldapcherry.ppolicy
import re

class PPolicy(ldapcherry.ppolicy.PPolicy):

    def __init__(self, config, logger):
        self.config = config
        self.min_length = self.get_param('min_length')
        self.min_upper = self.get_param('min_upper')
        self.min_digit = self.get_param('min_digit')

    def check(self, password):
        if len(password) < self.min_length:
            return {'match': False, 'reason': 'Password too short'}
        if len(re.findall(r'[A-Z]', password)) < self.min_upper:
            return {
                'match': False,
                'reason': 'Not enough upper case characters'
        if len(re.findall(r'[0-9]', password)) < self.min_digit:
            return {'match': False, 'reason': 'Not enough digits'}
        return {'match': True, 'reason': 'password ok'}

    def info(self):
        return \
            "* Minimum length: %(len)d\n" \
            "* Minimum number of uppercase characters: %(upper)d\n" \
            "* Minimum number of digits: %(digit)d" % {
                'upper': self.min_upper,
                'len': self.min_length,
                'digit': self.min_digit