[Checkins] SVN: zope.app.authentication/tags/3.5.0a2/ Tag 3.5.0a2
Dan Korostelev
nadako at gmail.com
Sun Feb 1 08:24:06 EST 2009
Log message for revision 95853:
Tag 3.5.0a2
Changed:
A zope.app.authentication/tags/3.5.0a2/
D zope.app.authentication/tags/3.5.0a2/CHANGES.txt
A zope.app.authentication/tags/3.5.0a2/CHANGES.txt
D zope.app.authentication/tags/3.5.0a2/setup.py
A zope.app.authentication/tags/3.5.0a2/setup.py
D zope.app.authentication/tags/3.5.0a2/src/zope/app/authentication/password.py
A zope.app.authentication/tags/3.5.0a2/src/zope/app/authentication/password.py
-=-
Deleted: zope.app.authentication/tags/3.5.0a2/CHANGES.txt
===================================================================
--- zope.app.authentication/trunk/CHANGES.txt 2009-02-01 13:00:27 UTC (rev 95850)
+++ zope.app.authentication/tags/3.5.0a2/CHANGES.txt 2009-02-01 13:24:06 UTC (rev 95853)
@@ -1,57 +0,0 @@
-=======
-Changes
-=======
-
-3.5.0a2 (unreleased)
---------------------
-
-* ...
-
-3.5.0a1 (2009-01-31)
---------------------
-
-* Use ``zope.container`` instead of ``zope.app.container``.
-
-* Encoded passwords are now stored with a prefix ({MD5}, {SHA1},
- {SSHA}) indicating the used encoding schema. Old (encoded) passwords
- can still be used.
-
-* Add an SSHA password manager that is compatible with standard LDAP
- passwords. As this encoding gives better security agains dictionary
- attacks, users are encouraged to switch to this new password schema.
-
-* InternalPrincipal now uses SSHA password manager by default.
-
-3.4.4 (2008-12-12)
-------------------
-
-* Depend on zope.session instead of zope.app.session. The first one
- currently has all functionality we need.
-* Fix deprecation warnings for ``md5`` and ``sha`` on Python 2.6.
-
-3.4.3 (2008-08-07)
-------------------
-
-* No changes. Retag for correct release on PyPI.
-
-3.4.2 (2008-07-09)
--------------------
-
-* Make it compatible with zope.app.container 3.6.1 and 3.5.4 changes,
- Changed ``super(BTreeContainer, self).__init__()`` to
- ``super(GroupFolder, self).__init__()`` in ``GroupFolder`` class.
-
-3.4.1 (2007-10-24)
-------------------
-
-* Avoid deprecation warning.
-
-3.4.0 (2007-10-11)
-------------------
-
-* Updated package meta-data.
-
-3.4.0b1 (2007-09-27)
---------------------
-
-* First release independent of Zope.
Copied: zope.app.authentication/tags/3.5.0a2/CHANGES.txt (from rev 95851, zope.app.authentication/trunk/CHANGES.txt)
===================================================================
--- zope.app.authentication/tags/3.5.0a2/CHANGES.txt (rev 0)
+++ zope.app.authentication/tags/3.5.0a2/CHANGES.txt 2009-02-01 13:24:06 UTC (rev 95853)
@@ -0,0 +1,57 @@
+=======
+Changes
+=======
+
+3.5.0a2 (2009-02-01)
+--------------------
+
+* Make old encoded passwords really work.
+
+3.5.0a1 (2009-01-31)
+--------------------
+
+* Use ``zope.container`` instead of ``zope.app.container``.
+
+* Encoded passwords are now stored with a prefix ({MD5}, {SHA1},
+ {SSHA}) indicating the used encoding schema. Old (encoded) passwords
+ can still be used.
+
+* Add an SSHA password manager that is compatible with standard LDAP
+ passwords. As this encoding gives better security agains dictionary
+ attacks, users are encouraged to switch to this new password schema.
+
+* InternalPrincipal now uses SSHA password manager by default.
+
+3.4.4 (2008-12-12)
+------------------
+
+* Depend on zope.session instead of zope.app.session. The first one
+ currently has all functionality we need.
+* Fix deprecation warnings for ``md5`` and ``sha`` on Python 2.6.
+
+3.4.3 (2008-08-07)
+------------------
+
+* No changes. Retag for correct release on PyPI.
+
+3.4.2 (2008-07-09)
+-------------------
+
+* Make it compatible with zope.app.container 3.6.1 and 3.5.4 changes,
+ Changed ``super(BTreeContainer, self).__init__()`` to
+ ``super(GroupFolder, self).__init__()`` in ``GroupFolder`` class.
+
+3.4.1 (2007-10-24)
+------------------
+
+* Avoid deprecation warning.
+
+3.4.0 (2007-10-11)
+------------------
+
+* Updated package meta-data.
+
+3.4.0b1 (2007-09-27)
+--------------------
+
+* First release independent of Zope.
Deleted: zope.app.authentication/tags/3.5.0a2/setup.py
===================================================================
--- zope.app.authentication/trunk/setup.py 2009-02-01 13:00:27 UTC (rev 95850)
+++ zope.app.authentication/tags/3.5.0a2/setup.py 2009-02-01 13:24:06 UTC (rev 95853)
@@ -1,85 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Setup for zope.app.authentication package
-
-$Id$
-"""
-import os
-from setuptools import setup, find_packages
-
-def read(*rnames):
- return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
-
-setup(name='zope.app.authentication',
- version = '3.5.0a2dev',
- author='Zope Corporation and Contributors',
- author_email='zope-dev at zope.org',
- description='Pluggable Authentication Utility',
- long_description=(
- read('README.txt')
- + '\n\n' +
- 'Detailed Documentation\n' +
- '----------------------\n'
- + '\n' +
- read('src', 'zope', 'app', 'authentication', 'README.txt')
- + '\n\n' +
- read('src', 'zope', 'app', 'authentication', 'principalfolder.txt')
- + '\n\n' +
- read('src', 'zope', 'app', 'authentication', 'vocabulary.txt')
- + '\n\n' +
- read('CHANGES.txt')
- ),
- url='http://cheeseshop.python.org/pypi/zope.app.authentication',
- license='ZPL 2.1',
- classifiers = [
- 'Development Status :: 5 - Production/Stable',
- 'Environment :: Web Environment',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: Zope Public License',
- 'Programming Language :: Python',
- 'Natural Language :: English',
- 'Operating System :: OS Independent',
- 'Topic :: Internet :: WWW/HTTP',
- 'Framework :: Zope3'],
- keywords='zope3 authentication pluggable principal group',
- packages=find_packages('src'),
- package_dir = {'': 'src'},
- extras_require=dict(test=['zope.app.testing',
- 'zope.app.securitypolicy',
- 'zope.app.zcmlfiles',
- 'zope.securitypolicy',
- 'zope.testbrowser']),
- namespace_packages=['zope', 'zope.app'],
- install_requires=['setuptools',
- 'zope.app.component',
- 'zope.app.container',
- 'zope.app.form',
- 'zope.app.security',
- 'zope.dublincore',
- 'zope.event',
- 'zope.exceptions',
- 'zope.i18n',
- 'zope.i18nmessageid',
- 'zope.interface',
- 'zope.location',
- 'zope.publisher',
- 'zope.schema',
- 'zope.security',
- 'zope.session',
- 'zope.traversing',
- 'ZODB3',
- ],
- include_package_data = True,
- zip_safe = False,
- )
Copied: zope.app.authentication/tags/3.5.0a2/setup.py (from rev 95852, zope.app.authentication/trunk/setup.py)
===================================================================
--- zope.app.authentication/tags/3.5.0a2/setup.py (rev 0)
+++ zope.app.authentication/tags/3.5.0a2/setup.py 2009-02-01 13:24:06 UTC (rev 95853)
@@ -0,0 +1,85 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Setup for zope.app.authentication package
+
+$Id$
+"""
+import os
+from setuptools import setup, find_packages
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(name='zope.app.authentication',
+ version = '3.5.0a2',
+ author='Zope Corporation and Contributors',
+ author_email='zope-dev at zope.org',
+ description='Pluggable Authentication Utility',
+ long_description=(
+ read('README.txt')
+ + '\n\n' +
+ 'Detailed Documentation\n' +
+ '----------------------\n'
+ + '\n' +
+ read('src', 'zope', 'app', 'authentication', 'README.txt')
+ + '\n\n' +
+ read('src', 'zope', 'app', 'authentication', 'principalfolder.txt')
+ + '\n\n' +
+ read('src', 'zope', 'app', 'authentication', 'vocabulary.txt')
+ + '\n\n' +
+ read('CHANGES.txt')
+ ),
+ url='http://pypi.python.org/pypi/zope.app.authentication',
+ license='ZPL 2.1',
+ classifiers = [
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Framework :: Zope3'],
+ keywords='zope3 authentication pluggable principal group',
+ packages=find_packages('src'),
+ package_dir = {'': 'src'},
+ extras_require=dict(test=['zope.app.testing',
+ 'zope.app.securitypolicy',
+ 'zope.app.zcmlfiles',
+ 'zope.securitypolicy',
+ 'zope.testbrowser']),
+ namespace_packages=['zope', 'zope.app'],
+ install_requires=['setuptools',
+ 'zope.app.component',
+ 'zope.app.container',
+ 'zope.app.form',
+ 'zope.app.security',
+ 'zope.dublincore',
+ 'zope.event',
+ 'zope.exceptions',
+ 'zope.i18n',
+ 'zope.i18nmessageid',
+ 'zope.interface',
+ 'zope.location',
+ 'zope.publisher',
+ 'zope.schema',
+ 'zope.security',
+ 'zope.session',
+ 'zope.traversing',
+ 'ZODB3',
+ ],
+ include_package_data = True,
+ zip_safe = False,
+ )
Deleted: zope.app.authentication/tags/3.5.0a2/src/zope/app/authentication/password.py
===================================================================
--- zope.app.authentication/trunk/src/zope/app/authentication/password.py 2009-02-01 13:00:27 UTC (rev 95850)
+++ zope.app.authentication/tags/3.5.0a2/src/zope/app/authentication/password.py 2009-02-01 13:24:06 UTC (rev 95853)
@@ -1,245 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Password managers
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-try:
- from hashlib import md5, sha1
-except ImportError:
- # Python 2.4
- from md5 import new as md5
- from sha import new as sha1
-
-from base64 import urlsafe_b64encode
-from base64 import urlsafe_b64decode
-from os import urandom
-from random import randint
-from codecs import getencoder
-
-from zope.interface import implements, classProvides
-from zope.schema.interfaces import IVocabularyFactory
-from zope.app.component.vocabulary import UtilityVocabulary
-
-from zope.app.authentication.interfaces import IPasswordManager
-
-
-_encoder = getencoder("utf-8")
-
-
-class PlainTextPasswordManager(object):
- """Plain text password manager.
-
- >>> from zope.interface.verify import verifyObject
-
- >>> manager = PlainTextPasswordManager()
- >>> verifyObject(IPasswordManager, manager)
- True
-
- >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
- >>> encoded = manager.encodePassword(password)
- >>> encoded
- u'right \u0410'
- >>> manager.checkPassword(encoded, password)
- True
- >>> manager.checkPassword(encoded, password + u"wrong")
- False
- """
-
- implements(IPasswordManager)
-
- def encodePassword(self, password):
- return password
-
- def checkPassword(self, storedPassword, password):
- return storedPassword == self.encodePassword(password)
-
-
-class MD5PasswordManager(PlainTextPasswordManager):
- """MD5 password manager.
-
- Note: use of salt in this password manager is purely
- cosmetical. Use SSHA if you want increased security.
-
- >>> from zope.interface.verify import verifyObject
-
- >>> manager = MD5PasswordManager()
- >>> verifyObject(IPasswordManager, manager)
- True
-
- >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
- >>> encoded = manager.encodePassword(password, salt="")
- >>> encoded
- '{MD5}86dddccec45db4599f1ac00018e54139'
- >>> manager.checkPassword(encoded, password)
- True
- >>> manager.checkPassword(encoded, password + u"wrong")
- False
-
- >>> encoded = manager.encodePassword(password)
- >>> encoded[-32:]
- '86dddccec45db4599f1ac00018e54139'
- >>> manager.checkPassword(encoded, password)
- True
- >>> manager.checkPassword(encoded, password + u"wrong")
- False
-
- >>> manager.encodePassword(password) != manager.encodePassword(password)
- True
- """
-
- implements(IPasswordManager)
-
- def encodePassword(self, password, salt=None):
- if salt is None:
- salt = "%08x" % randint(0, 0xffffffff)
- return '{MD5}%s%s' % (salt, md5(_encoder(password)[0]).hexdigest())
-
- def checkPassword(self, storedPassword, password):
- if storedPassword.startswith('{MD5}'):
- salt = storedPassword[5:-32]
- return storedPassword == self.encodePassword(password, salt)
- salt = storedPassword[:-32]
- return storedPassword == self.encodePassword(password, salt)[6:]
-
-
-class SHA1PasswordManager(PlainTextPasswordManager):
- """SHA1 password manager.
-
- Note: use of salt in this password manager is purely
- cosmetical. Use SSHA if you want increased security.
-
- >>> from zope.interface.verify import verifyObject
-
- >>> manager = SHA1PasswordManager()
- >>> verifyObject(IPasswordManager, manager)
- True
-
- >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
- >>> encoded = manager.encodePassword(password, salt="")
- >>> encoded
- '{SHA1}04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
- >>> manager.checkPassword(encoded, password)
- True
- >>> manager.checkPassword(encoded, password + u"wrong")
- False
-
- >>> encoded = manager.encodePassword(password)
- >>> encoded[-40:]
- '04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
- >>> manager.checkPassword(encoded, password)
- True
- >>> manager.checkPassword(encoded, password + u"wrong")
- False
-
- >>> manager.encodePassword(password) != manager.encodePassword(password)
- True
- """
-
- implements(IPasswordManager)
-
- def encodePassword(self, password, salt=None):
- if salt is None:
- salt = "%08x" % randint(0, 0xffffffff)
- return '{SHA1}%s%s' % (salt, sha1(_encoder(password)[0]).hexdigest())
-
- def checkPassword(self, storedPassword, password):
- if storedPassword.startswith('{SHA1}'):
- salt = storedPassword[6:-40]
- return storedPassword == self.encodePassword(password, salt)
- salt = storedPassword[:-40]
- return storedPassword == self.encodePassword(password, salt)[7:]
-
-class SSHAPasswordManager(PlainTextPasswordManager):
- """SSHA password manager.
-
- SSHA is basically SHA1-encoding which also incorporates a salt
- into the encoded string. This way, stored passwords are more
- robust against dictionary attacks of attackers that could get
- access to lists of encoded passwords.
-
- SSHA is regularly used in LDAP databases and we should be
- compatible with passwords used there.
-
- >>> from zope.interface.verify import verifyObject
-
- >>> manager = SSHAPasswordManager()
- >>> verifyObject(IPasswordManager, manager)
- True
-
- >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
- >>> encoded = manager.encodePassword(password, salt="")
- >>> encoded
- '{SSHA}BLTuxxVMXzouxtKVb7gLgNxzdAI='
-
- >>> manager.checkPassword(encoded, password)
- True
- >>> manager.checkPassword(encoded, password + u"wrong")
- False
-
- Using the `slappasswd` utility to encode ``secret``, we get
- ``{SSHA}J4mrr3NQHXzLVaT0h9TuEWoJOrxeQ5lv`` as seeded hash.
-
- Our password manager generates the same value when seeded with the
- same salt, so we can be sure, our output is compatible with
- standard LDAP tools that also use SSHA::
-
- >>> from base64 import urlsafe_b64decode
- >>> salt = urlsafe_b64decode('XkOZbw==')
- >>> encoded = manager.encodePassword('secret', salt)
- >>> encoded
- '{SSHA}J4mrr3NQHXzLVaT0h9TuEWoJOrxeQ5lv'
-
- >>> encoded = manager.encodePassword(password)
- >>> manager.checkPassword(encoded, password)
- True
- >>> manager.checkPassword(encoded, password + u"wrong")
- False
-
- >>> manager.encodePassword(password) != manager.encodePassword(password)
- True
- """
-
- implements(IPasswordManager)
-
- def encodePassword(self, password, salt=None):
- if salt is None:
- salt = urandom(4)
- hash = sha1(_encoder(password)[0])
- hash.update(salt)
- return '{SSHA}' + urlsafe_b64encode(
- hash.digest() + salt)
-
- def checkPassword(self, storedPassword, password):
- byte_string = urlsafe_b64decode(storedPassword[6:])
- salt = byte_string[20:]
- return storedPassword == self.encodePassword(password, salt)
-
-# Simple registry used by mkzopeinstance script
-managers = [
- ("Plain Text", PlainTextPasswordManager()), # default
- ("MD5", MD5PasswordManager()),
- ("SHA1", SHA1PasswordManager()),
- ("SSHA", SSHAPasswordManager()),
-]
-
-
-class PasswordManagerNamesVocabulary(UtilityVocabulary):
- """Vocabulary of password managers."""
-
- classProvides(IVocabularyFactory)
- interface = IPasswordManager
- nameOnly = True
Copied: zope.app.authentication/tags/3.5.0a2/src/zope/app/authentication/password.py (from rev 95851, zope.app.authentication/trunk/src/zope/app/authentication/password.py)
===================================================================
--- zope.app.authentication/tags/3.5.0a2/src/zope/app/authentication/password.py (rev 0)
+++ zope.app.authentication/tags/3.5.0a2/src/zope/app/authentication/password.py 2009-02-01 13:24:06 UTC (rev 95853)
@@ -0,0 +1,245 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Password managers
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+try:
+ from hashlib import md5, sha1
+except ImportError:
+ # Python 2.4
+ from md5 import new as md5
+ from sha import new as sha1
+
+from base64 import urlsafe_b64encode
+from base64 import urlsafe_b64decode
+from os import urandom
+from random import randint
+from codecs import getencoder
+
+from zope.interface import implements, classProvides
+from zope.schema.interfaces import IVocabularyFactory
+from zope.app.component.vocabulary import UtilityVocabulary
+
+from zope.app.authentication.interfaces import IPasswordManager
+
+
+_encoder = getencoder("utf-8")
+
+
+class PlainTextPasswordManager(object):
+ """Plain text password manager.
+
+ >>> from zope.interface.verify import verifyObject
+
+ >>> manager = PlainTextPasswordManager()
+ >>> verifyObject(IPasswordManager, manager)
+ True
+
+ >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
+ >>> encoded = manager.encodePassword(password)
+ >>> encoded
+ u'right \u0410'
+ >>> manager.checkPassword(encoded, password)
+ True
+ >>> manager.checkPassword(encoded, password + u"wrong")
+ False
+ """
+
+ implements(IPasswordManager)
+
+ def encodePassword(self, password):
+ return password
+
+ def checkPassword(self, storedPassword, password):
+ return storedPassword == self.encodePassword(password)
+
+
+class MD5PasswordManager(PlainTextPasswordManager):
+ """MD5 password manager.
+
+ Note: use of salt in this password manager is purely
+ cosmetical. Use SSHA if you want increased security.
+
+ >>> from zope.interface.verify import verifyObject
+
+ >>> manager = MD5PasswordManager()
+ >>> verifyObject(IPasswordManager, manager)
+ True
+
+ >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
+ >>> encoded = manager.encodePassword(password, salt="")
+ >>> encoded
+ '{MD5}86dddccec45db4599f1ac00018e54139'
+ >>> manager.checkPassword(encoded, password)
+ True
+ >>> manager.checkPassword(encoded, password + u"wrong")
+ False
+
+ >>> encoded = manager.encodePassword(password)
+ >>> encoded[-32:]
+ '86dddccec45db4599f1ac00018e54139'
+ >>> manager.checkPassword(encoded, password)
+ True
+ >>> manager.checkPassword(encoded, password + u"wrong")
+ False
+
+ >>> manager.encodePassword(password) != manager.encodePassword(password)
+ True
+ """
+
+ implements(IPasswordManager)
+
+ def encodePassword(self, password, salt=None):
+ if salt is None:
+ salt = "%08x" % randint(0, 0xffffffff)
+ return '{MD5}%s%s' % (salt, md5(_encoder(password)[0]).hexdigest())
+
+ def checkPassword(self, storedPassword, password):
+ if storedPassword.startswith('{MD5}'):
+ salt = storedPassword[5:-32]
+ return storedPassword == self.encodePassword(password, salt)
+ salt = storedPassword[:-32]
+ return storedPassword == self.encodePassword(password, salt)[5:]
+
+
+class SHA1PasswordManager(PlainTextPasswordManager):
+ """SHA1 password manager.
+
+ Note: use of salt in this password manager is purely
+ cosmetical. Use SSHA if you want increased security.
+
+ >>> from zope.interface.verify import verifyObject
+
+ >>> manager = SHA1PasswordManager()
+ >>> verifyObject(IPasswordManager, manager)
+ True
+
+ >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
+ >>> encoded = manager.encodePassword(password, salt="")
+ >>> encoded
+ '{SHA1}04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
+ >>> manager.checkPassword(encoded, password)
+ True
+ >>> manager.checkPassword(encoded, password + u"wrong")
+ False
+
+ >>> encoded = manager.encodePassword(password)
+ >>> encoded[-40:]
+ '04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
+ >>> manager.checkPassword(encoded, password)
+ True
+ >>> manager.checkPassword(encoded, password + u"wrong")
+ False
+
+ >>> manager.encodePassword(password) != manager.encodePassword(password)
+ True
+ """
+
+ implements(IPasswordManager)
+
+ def encodePassword(self, password, salt=None):
+ if salt is None:
+ salt = "%08x" % randint(0, 0xffffffff)
+ return '{SHA1}%s%s' % (salt, sha1(_encoder(password)[0]).hexdigest())
+
+ def checkPassword(self, storedPassword, password):
+ if storedPassword.startswith('{SHA1}'):
+ salt = storedPassword[6:-40]
+ return storedPassword == self.encodePassword(password, salt)
+ salt = storedPassword[:-40]
+ return storedPassword == self.encodePassword(password, salt)[6:]
+
+class SSHAPasswordManager(PlainTextPasswordManager):
+ """SSHA password manager.
+
+ SSHA is basically SHA1-encoding which also incorporates a salt
+ into the encoded string. This way, stored passwords are more
+ robust against dictionary attacks of attackers that could get
+ access to lists of encoded passwords.
+
+ SSHA is regularly used in LDAP databases and we should be
+ compatible with passwords used there.
+
+ >>> from zope.interface.verify import verifyObject
+
+ >>> manager = SSHAPasswordManager()
+ >>> verifyObject(IPasswordManager, manager)
+ True
+
+ >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
+ >>> encoded = manager.encodePassword(password, salt="")
+ >>> encoded
+ '{SSHA}BLTuxxVMXzouxtKVb7gLgNxzdAI='
+
+ >>> manager.checkPassword(encoded, password)
+ True
+ >>> manager.checkPassword(encoded, password + u"wrong")
+ False
+
+ Using the `slappasswd` utility to encode ``secret``, we get
+ ``{SSHA}J4mrr3NQHXzLVaT0h9TuEWoJOrxeQ5lv`` as seeded hash.
+
+ Our password manager generates the same value when seeded with the
+ same salt, so we can be sure, our output is compatible with
+ standard LDAP tools that also use SSHA::
+
+ >>> from base64 import urlsafe_b64decode
+ >>> salt = urlsafe_b64decode('XkOZbw==')
+ >>> encoded = manager.encodePassword('secret', salt)
+ >>> encoded
+ '{SSHA}J4mrr3NQHXzLVaT0h9TuEWoJOrxeQ5lv'
+
+ >>> encoded = manager.encodePassword(password)
+ >>> manager.checkPassword(encoded, password)
+ True
+ >>> manager.checkPassword(encoded, password + u"wrong")
+ False
+
+ >>> manager.encodePassword(password) != manager.encodePassword(password)
+ True
+ """
+
+ implements(IPasswordManager)
+
+ def encodePassword(self, password, salt=None):
+ if salt is None:
+ salt = urandom(4)
+ hash = sha1(_encoder(password)[0])
+ hash.update(salt)
+ return '{SSHA}' + urlsafe_b64encode(
+ hash.digest() + salt)
+
+ def checkPassword(self, storedPassword, password):
+ byte_string = urlsafe_b64decode(storedPassword[6:])
+ salt = byte_string[20:]
+ return storedPassword == self.encodePassword(password, salt)
+
+# Simple registry used by mkzopeinstance script
+managers = [
+ ("Plain Text", PlainTextPasswordManager()), # default
+ ("MD5", MD5PasswordManager()),
+ ("SHA1", SHA1PasswordManager()),
+ ("SSHA", SSHAPasswordManager()),
+]
+
+
+class PasswordManagerNamesVocabulary(UtilityVocabulary):
+ """Vocabulary of password managers."""
+
+ classProvides(IVocabularyFactory)
+ interface = IPasswordManager
+ nameOnly = True
More information about the Checkins
mailing list