from ldap3 import MODIFY_REPLACE
from ldap3.core.exceptions import LDAPBindError
-import passlib.apps
-
-HAS_CRACKLIB = False
-try:
- import cracklib
- HAS_CRACKLIB = True
-except ImportError:
- pass
-
# Own modules
# from fb_tools.common import to_bool, is_sequence, pp
from fb_tools.common import is_sequence
from .ldap import BaseLdapApplication
from .ldap import PasswordFileOptionAction
-__version__ = '0.6.6'
+from ..handler.ldap_password import WrongPwdSchemaError
+from ..handler.ldap_password import LdapPasswordHandler
+from ..handler.ldap_password import HAS_CRACKLIB
+
+__version__ = '0.7.1'
LOG = logging.getLogger(__name__)
_ = XLATOR.gettext
except KeyError:
pass
- possible_schemes = (
- 'ldap_des_crypt',
- 'ldap_md5',
- 'ldap_md5_crypt',
- 'ldap_salted_md5',
- 'ldap_sha1',
- 'ldap_sha1_crypt',
- 'ldap_salted_sha1',
- 'ldap_sha256_crypt',
- 'ldap_salted_sha256',
- 'ldap_sha512_crypt',
- 'ldap_salted_sha512',
- 'ldap_pbkdf2_sha512',
- )
-
- ldap_context = passlib.apps.ldap_context
- available_schemes = []
-
- schema_ids = {
- 'ldap_des_crypt': 'CRYPT',
- 'ldap_md5': 'MD5',
- 'ldap_md5_crypt': 'CRYPT-MD5',
- 'ldap_salted_md5': 'SMD5',
- 'ldap_sha1': 'SHA',
- 'ldap_sha1_crypt': 'SHA-CRYPT',
- 'ldap_salted_sha1': 'SSHA',
- 'ldap_sha256_crypt': 'CRYPT-SHA256',
- 'ldap_salted_sha256': 'SSHA256',
- 'ldap_sha512_crypt': 'CRYPT-SHA512',
- 'ldap_salted_sha512': 'SSHA512',
- 'ldap_pbkdf2_sha512': 'PBKDF2_SHA512',
- }
-
- schema_description = {
- 'ldap_des_crypt': _('The ancient and notorious 3 DES crypt method.'),
- 'ldap_md5': _('Pure {} hashing method.').format('MD5'),
- 'ldap_md5_crypt': _("A {} based hashing algorithm.").format('MD5'),
- 'ldap_salted_md5': _("Salted {} hashing method.").format('MD5'),
- 'ldap_sha1': _('Pure {} hashing method.').format('SHA-1'),
- 'ldap_sha1_crypt': _("A {} based hashing algorithm.").format('SHA-1'),
- 'ldap_salted_sha1': _("Salted {} hashing method.").format('SHA-1'),
- 'ldap_sha256_crypt': _("A {} based hashing algorithm.").format('SHA-256'),
- 'ldap_salted_sha256': _("Salted {} hashing method.").format('SHA-256'),
- 'ldap_sha512_crypt': _("A {} based hashing algorithm.").format('SHA-512'),
- 'ldap_salted_sha512': _("Salted {} hashing method.").format('SHA-512'),
- 'ldap_pbkdf2_sha512': _(
- "A hashing method derived from {} with additional computing rounds.").format(
- 'SHA-512'),
- }
-
- passlib_context = None
- default_schema = 'ldap_sha512_crypt'
- default_schema_id = 'CRYPT-SHA512'
- default_pbkdf2_rounds = 30000
-
- # -------------------------------------------------------------------------
- @classmethod
- def init_pass_schemes(cls):
-
- cls.available_schemes = []
- all_handlers = passlib.registry.list_crypt_handlers()
-
- for schema in cls.possible_schemes:
- if schema in all_handlers:
- cls.available_schemes.append(schema)
-
- cls.passlib_context = passlib.context.CryptContext(
- schemes=cls.available_schemes, ldap_pbkdf2_sha512__rounds=cls.default_pbkdf2_rounds)
- cls.passlib_context.update(default=cls.default_schema)
-
# -------------------------------------------------------------------------
def __init__(self, appname=None, base_dir=None):
- self.init_pass_schemes()
+ LdapPasswordHandler.init_pass_schemes()
self.current_password = None
self.need_current_password = False
self.new_password = None
self.user_uid = None
self.user_dn = None
- self.schema = self.default_schema
- self.schema_id = self.default_schema_id
self.no_cracklib = False
self.user_connection = None
+ self.pwd_handler = LdapPasswordHandler(
+ appname=appname, base_dir=base_dir, initialized=False)
+
my_appname = self.get_generic_appname(appname)
desc = _(
schema_list = []
def_schema = ''
- for method in self.available_schemes:
- schema_id = self.schema_ids[method]
+ for method in LdapPasswordHandler.available_schemes:
+ schema_id = LdapPasswordHandler.schema_ids[method]
schema_list.append(schema_id)
- if method == self.default_schema:
+ if method == LdapPasswordHandler.default_schema:
def_schema = schema_id
schema_list.append('list')
+ schema_list.append('help')
help_txt1 = _(
"The schema (hashing method) to use to hash the new password. It is possible to give "
msg = "Given args:\n" + pp(self.args.__dict__)
LOG.debug(msg)
+ self.pwd_handler.verbose = self.verbose
+ self.pwd_handler.simulate = self.simulate
+ self.pwd_handler.force = self.force
+ self.pwd_handler.terminal_has_colors = self.terminal_has_colors
+ self.pwd_handler.initialized = True
+
self.no_cracklib = getattr(self.args, 'no_cracklib', False)
given_schema = getattr(self.args, 'schema', None)
if given_schema:
- if given_schema == 'list':
- self._show_hashing_schemes()
+ if given_schema in ('list', 'help'):
+ self.pwd_handler.show_hashing_schemes()
self.exit(0)
return
- for method in self.available_schemes:
- schema_id = self.schema_ids[method]
- LOG.debug("Testing for {m!r} ({s}) ...".format(m=method, s=schema_id))
- if schema_id == given_schema:
- self.passlib_context.update(default=method)
- self.schema = method
- self.schema_id = schema_id
- break
+ try:
+ self.pwd_handler.set_schema_by_id(given_schema)
+ except WrongPwdSchemaError as e:
+ self.exit(5, str(e))
given_user = getattr(self.args, 'user', None)
if given_user:
LOG.debug("User bind: LDAP instance is readonly or not as admin.")
self.do_user_bind = True
- # -------------------------------------------------------------------------
- def _show_hashing_schemes(self):
-
- max_len_schema = 1
- for method in self.available_schemes:
- schema_id = self.schema_ids[method]
- if len(schema_id) > max_len_schema:
- max_len_schema = len(schema_id)
-
- title = _("Usable Hashing schemes:")
- print(title)
- print('-' * len(title))
- print()
-
- for method in self.available_schemes:
- schema_id = self.schema_ids[method]
- desc = self.schema_description[method]
- if 'pbkdf2' in method:
- desc += ' ' + _(
- "This schema cannot be used for authentication on a "
- "current freeradius server.")
- if method == self.schema:
- desc += ' ' + _("This is the default schema.")
-
- line = ' * {id:<{max_len}} - '.format(id=schema_id, max_len=max_len_schema)
- line += desc
- print(line)
-
- print()
-
# -------------------------------------------------------------------------
def pre_run(self):
self.new_password = self.get_password(
first_prompt, second_prompt, may_empty=False, repeat=True)
- if HAS_CRACKLIB:
- if self.no_cracklib:
- msg = _("Checking the quality of the new password was disabled.")
- LOG.warn(msg)
- else:
- LOG.info(_("Testing quality of new password ..."))
- try:
- cracklib.VeryFascistCheck(self.new_password)
- except ValueError as e:
- msg = _("Quality of the new password is not sufficient:") + ' ' + str(e)
- LOG.error(msg)
- self.exit(1)
- LOG.debug("The quality of the new password seems to be sufficient.")
- else:
- msg = _(
- "Cannot testing the quality of the new password, because the "
- "Python module {!r} is not installed.").format('cracklib')
+ if self.no_cracklib:
+ msg = _("Checking the quality of the new password was disabled.")
LOG.warn(msg)
+ else:
+ if self.pwd_handler.check_password_quality(self.new_password):
+ LOG.debug("The quality of the new password seems to be sufficient.")
+ else:
+ self.exit(1)
super(SetLdapPasswordApplication, self).pre_run()
print(msg)
LOG.debug(_("Used schema: {!r}.").format(self.schema))
- hashed_passwd = self.passlib_context.hash(self.new_password, self.schema)
+ hashed_passwd = self.pwd_handler.get_hash(self.new_password, self.schema)
msg = _("New password hash: '{}'.").format(self.colored(hashed_passwd, 'CYAN'))
print(msg)
# -------------------------------------------------------------------------
def __init__(
self, appname=None, verbose=0, version=__version__, base_dir=None,
- simulate=None, force=None, assumed_answer=None,
+ simulate=False, force=False, assumed_answer=None,
terminal_has_colors=False, initialized=False):
+ self.schema = self.default_schema
+ self.schema_id = self.default_schema_id
+
super(LdapPasswordHandler, self).__init__(
appname=appname, verbose=verbose, version=version, base_dir=base_dir,
simulate=simulate, force=force, assumed_answer=assumed_answer,
terminal_has_colors=terminal_has_colors, initialized=False,
)
+ if initialized:
+ self.initialized = True
+
# -------------------------------------------------------------------------
def as_dict(self, short=True):
"""
# -------------------------------------------------------------------------
def get_hash(self, password, schema=None):
- hashed_passwd = self.passlib_context.hash(password, self.schema)
+ if not schema:
+ schema = self.schema
+
+ hashed_passwd = self.passlib_context.hash(password)
return hashed_passwd
# -------------------------------------------------------------------------