# HG changeset patch # User Pascal Volk # Date 1272931295 0 # Node ID 1e77dd639fa33cd795bfaf1b5a3d45087a1a9738 # Parent e2046d47688b9f971008e577af89f2b14489dc8d VMM/password: moved the 'scheme check' code from pwhash() to the new function verify_scheme(). VMM/Config: use verify_scheme() to check the scheme when LazyConfig.set() is called. diff -r e2046d47688b -r 1e77dd639fa3 VirtualMailManager/Config.py --- a/VirtualMailManager/Config.py Mon May 03 20:38:36 2010 +0000 +++ b/VirtualMailManager/Config.py Tue May 04 00:01:35 2010 +0000 @@ -17,7 +17,8 @@ from VirtualMailManager.common import exec_ok, get_unicode, is_dir, version_hex from VirtualMailManager.constants.ERROR import CONF_ERROR -from VirtualMailManager.errors import ConfigError +from VirtualMailManager.errors import ConfigError, VMMError +from VirtualMailManager.password import verify_scheme as _verify_scheme _ = lambda msg: msg @@ -349,7 +350,7 @@ 'dovecot_version': LCO(str, None, self.hexversion, check_version_format), 'password_scheme': LCO(str, 'CRAM-MD5', self.get, - self.known_scheme), + verify_scheme), 'transport': LCO(str, 'dovecot:', self.get), }, } @@ -396,22 +397,9 @@ value to an int.""" return version_hex(self.get(section, option)) - def known_scheme(self, scheme): - """Converts `scheme` to upper case and checks if is known by - Dovecot (listed in VirtualMailManager.SCHEMES). - - Throws a `ConfigValueError` if the scheme is not listed in - VirtualMailManager.SCHEMES. - - """ - scheme = scheme.upper() - # TODO: VMM.SCHEMES - def unicode(self, section, option): """Returns the value of the `option` from `section`, converted - to Unicode. - - """ + to Unicode.""" return get_unicode(self.get(section, option)) def __chk_cfg(self): @@ -445,4 +433,17 @@ get_unicode(version_string)) return version_string + +def verify_scheme(scheme): + """Checks if the password scheme *scheme* can be accepted and returns + the verified scheme. + """ + try: + scheme, encoding = _verify_scheme(scheme) + except VMMError, err: # 'cast' it + raise ConfigValueError(err.msg) + if not encoding: + return scheme + return '%s.%s' % (scheme, encoding) + del _ diff -r e2046d47688b -r 1e77dd639fa3 VirtualMailManager/password.py --- a/VirtualMailManager/password.py Mon May 03 20:38:36 2010 +0000 +++ b/VirtualMailManager/password.py Tue May 04 00:01:35 2010 +0000 @@ -6,10 +6,12 @@ VirtualMailManager.password VirtualMailManager's password module to generate password hashes from - passwords or random passwords. There are two functions: + passwords or random passwords. This module provides following + functions: hashed_password = pwhash(password[, scheme][, user]) random_password = randompw() + scheme, encoding = verify_scheme(scheme) """ from crypt import crypt @@ -343,6 +345,47 @@ } +def verify_scheme(scheme): + """Checks if the password scheme *scheme* is known and supported by the + configured `misc.dovecot_version`. + + The *scheme* maybe a password scheme's name (e.g.: 'PLAIN') or a scheme + name with a encoding suffix (e.g. 'PLAIN.BASE64'). If the scheme is + known and supported by the used Dovecot version, + a tuple ``(scheme, encoding)`` will be returned. + The `encoding` in the tuple may be `None`. + + Raises a `VMMError` if the password scheme: + * is unknown + * depends on a newer Dovecot version + * has a unknown encoding suffix + """ + assert isinstance(scheme, basestring), 'Not a str/unicode: %r' % scheme + scheme_encoding = scheme.upper().split('.') + scheme = scheme_encoding[0] + if not scheme in _scheme_info: + raise VMMError(_(u"Unsupported password scheme: '%s'") % scheme, + VMM_ERROR) + if cfg_dget('misc.dovecot_version') < _scheme_info[scheme][1]: + raise VMMError(_(u"The password scheme '%(scheme)s' requires Dovecot \ +>= v%(version)s") % + {'scheme': scheme, + 'version': version_str(_scheme_info[scheme][1])}, + VMM_ERROR) + if len(scheme_encoding) > 1: + if cfg_dget('misc.dovecot_version') < 0x10100a01: + raise VMMError(_(u'Encoding suffixes for password schemes require \ +Dovecot >= v1.1.alpha1'), + VMM_ERROR) + if scheme_encoding[1] not in ('B64', 'BASE64', 'HEX'): + raise VMMError(_(u"Unsupported password encoding: '%s'") % + scheme_encoding[1], VMM_ERROR) + encoding = scheme_encoding[1] + else: + encoding = None + return scheme, encoding + + def pwhash(password, scheme=None, user=None): """Generates a password hash from the plain text *password* string. @@ -359,25 +402,7 @@ raise ValueError("Couldn't accept empty password.") if scheme is None: scheme = cfg_dget('misc.password_scheme') - scheme_encoding = scheme.split('.') - scheme = scheme_encoding[0].upper() - if not scheme in _scheme_info: - raise VMMError(_(u"Unsupported password scheme: '%s'") % scheme, - VMM_ERROR) - if cfg_dget('misc.dovecot_version') < _scheme_info[scheme][1]: - raise VMMError(_(u"The scheme '%s' requires Dovecot >= v%s") % - (scheme, version_str(_scheme_info[scheme][1])), - VMM_ERROR) - if len(scheme_encoding) > 1: - if cfg_dget('misc.dovecot_version') < 0x10100a01: - raise VMMError(_(u'Encoding suffixes for password schemes require \ -Dovecot >= v1.1.alpha1'), - VMM_ERROR) - if scheme_encoding[1].upper() not in ('B64', 'BASE64', 'HEX'): - raise ValueError('Unsupported encoding: %r' % scheme_encoding[1]) - encoding = scheme_encoding[1].upper() - else: - encoding = None + scheme, encoding = verify_scheme(scheme) if scheme == 'DIGEST-MD5': assert isinstance(user, EmailAddress) return _md5_hash(password, scheme, encoding, user)