zope.password-3.6.1/0000755000175000017500000000000011377424160012166 5ustar jwjwzope.password-3.6.1/CHANGES.txt0000644000175000017500000000273411377424153014007 0ustar jwjw======= CHANGES ======= 3.6.1 (2010-05-27) ------------------ - The SSHAPasswordManager.checkPassword() would not handle unicode input (even if the string would only contain ascii characters). Now, the encoded_password input will be encoded to ascii, which is deemed safe as it should not contain non-ascii characters anyway. 3.6.0 (2010-05-07) ------------------ - Removed zope.testing dependency for tests. - Updated some copyright headers to comply to repository policy. - Added zpasswd script formerly hold in zope.app.server. Contrary to former zpasswd script, which used "Plain Text" as default password manager, now SSHA is used as default. 3.5.1 (2009-03-14) ------------------ - Make security protection directives in `configure.zcml` execute only if ``zope.security`` is installed. This will allow reuse of the `configure.zcml` file in environments without ``zope.security``, for example with ``repoze.zcml``. - Add "Password Manager Names" vocabulary for use with ``zope.schema`` and ``zope.component``, like it was in ``zope.app.authentication``. It's an optional feature so it doesn't add hard dependency. We use "vocabulary" extra to list dependencies needed for vocabulary functionality. 3.5.0 (2009-03-06) ------------------ First release. This package was splitted off from ``zope.app.authentication`` to separate password manager functionality that is greatly re-usable without any bit of ``zope.app.authentication`` and to reduce its dependencies. zope.password-3.6.1/bootstrap.py0000644000175000017500000000337311377424153014565 0ustar jwjw############################################################################## # # Copyright (c) 2006 Zope Foundation 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. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. $Id: bootstrap.py 112030 2010-05-05 18:53:49Z tseaver $ """ import os, shutil, sys, tempfile, urllib2 tmpeggs = tempfile.mkdtemp() ez = {} exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' ).read() in ez ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) import pkg_resources cmd = 'from setuptools.command.easy_install import main; main()' if sys.platform == 'win32': cmd = '"%s"' % cmd # work around spawn lamosity on windows ws = pkg_resources.working_set assert os.spawnle( os.P_WAIT, sys.executable, sys.executable, '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout', dict(os.environ, PYTHONPATH= ws.find(pkg_resources.Requirement.parse('setuptools')).location ), ) == 0 ws.add_entry(tmpeggs) ws.require('zc.buildout') import zc.buildout.buildout zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap']) shutil.rmtree(tmpeggs) zope.password-3.6.1/setup.py0000644000175000017500000000417611377424153013712 0ustar jwjw############################################################################## # # Copyright (c) 2009 Zope Foundation 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.password package $Id: setup.py 112747 2010-05-27 08:07:28Z janwijbrand $ """ from setuptools import setup, find_packages setup(name='zope.password', version='3.6.1', author='Zope Foundation and Contributors', author_email='zope-dev@zope.org', description='Password encoding and checking utilities', long_description=( open('README.txt').read() + '\n\n' + open('CHANGES.txt').read() ), url='http://pypi.python.org/pypi/zope.password', 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='zope authentication password zpasswd', packages=find_packages('src'), package_dir = {'': 'src'}, extras_require=dict(vocabulary=['zope.schema'], test=['zope.schema'], ), namespace_packages=['zope'], install_requires=['setuptools', 'zope.component', 'zope.configuration', 'zope.interface', ], include_package_data = True, zip_safe = False, ) zope.password-3.6.1/src/0000755000175000017500000000000011377424160012755 5ustar jwjwzope.password-3.6.1/src/zope.password.egg-info/0000755000175000017500000000000011377424160017265 5ustar jwjwzope.password-3.6.1/src/zope.password.egg-info/SOURCES.txt0000644000175000017500000000133211377424155021154 0ustar jwjwCHANGES.txt COPYRIGHT.txt LICENSE.txt README.txt bootstrap.py buildout.cfg setup.py src/zope/__init__.py src/zope.password.egg-info/PKG-INFO src/zope.password.egg-info/SOURCES.txt src/zope.password.egg-info/dependency_links.txt src/zope.password.egg-info/namespace_packages.txt src/zope.password.egg-info/not-zip-safe src/zope.password.egg-info/requires.txt src/zope.password.egg-info/top_level.txt src/zope/password/__init__.py src/zope/password/configure.zcml src/zope/password/interfaces.py src/zope/password/password.py src/zope/password/testing.py src/zope/password/vocabulary.py src/zope/password/zpasswd.py src/zope/password/tests/__init__.py src/zope/password/tests/test_password.py src/zope/password/tests/test_zpasswd.pyzope.password-3.6.1/src/zope.password.egg-info/top_level.txt0000644000175000017500000000000511377424155022016 0ustar jwjwzope zope.password-3.6.1/src/zope.password.egg-info/requires.txt0000644000175000017500000000015111377424155021666 0ustar jwjwsetuptools zope.component zope.configuration zope.interface [test] zope.schema [vocabulary] zope.schemazope.password-3.6.1/src/zope.password.egg-info/namespace_packages.txt0000644000175000017500000000000511377424155023617 0ustar jwjwzope zope.password-3.6.1/src/zope.password.egg-info/not-zip-safe0000644000175000017500000000000111377424153021515 0ustar jwjw zope.password-3.6.1/src/zope.password.egg-info/PKG-INFO0000644000175000017500000001744411377424155020400 0ustar jwjwMetadata-Version: 1.0 Name: zope.password Version: 3.6.1 Summary: Password encoding and checking utilities Home-page: http://pypi.python.org/pypi/zope.password Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: ================ Password Manager ================ This package provides a password manager mechanism. Password manager is an utility object that can encode and check encoded passwords. Beyond the generic interface, this package also provides four implementations: * PlainTextPasswordManager - the most simple and the less secure one. It does not do any password encoding and simply checks password by string equality. It's useful in tests or as a base class for more secure implementations. * MD5PasswordManager - a password manager that uses MD5 algorithm to encode passwords. It adds salt to the encoded password, but the salt is not used for encoding the password itself, so the use of salt in it is purely cosmetical. It's generally weak against dictionary attacks. * SHA1PasswordManager - a password manager that uses SHA1 algorithm to encode passwords. It has the same salt weakness as the MD5PasswordManager. * SSHAPasswordManager - the most secure password manager that is strong against dictionary attacks. It's basically SHA1-encoding password manager which also incorporates a salt into the password when encoding it. This password manager is compatible with passwords used in LDAP databases. It is strongly recommended to use SSHAPasswordManager, as it's the most secure. The package also provides a script `zpasswd` to generate principal entries in typical ``site.zcml`` files. Usage ----- It's very easy to use password managers. The ``zope.password.interfaces.IPasswordManager`` interface defines only two methods:: def encodePassword(password): """Return encoded data for the given password""" def checkPassword(encoded_password, password): """Return whether the given encoded data coincide with the given password""" The implementations mentioned above are in the ``zope.password.password`` module. Password Manager Names Vocabulary --------------------------------- The ``zope.password.vocabulary`` module provides a vocabulary of registered password manager utility names. It is typically registered as an `IVocabularyFactory` utility named "Password Manager Names". It's intended to be used with ``zope.component`` and ``zope.schema``, so you need to have them installed and the utility registrations needs to be done properly. The `configure.zcml` file, contained in ``zope.password`` does the registrations, as well as in `setUpPasswordManagers` function in ``zope.password.testing`` module. zpasswd script -------------- ``zpasswd`` is a script to generate principal entries in typical ``site.zcml`` files. You can create a ``zpasswd`` script in your package by adding a section like this to your ``buildout.cfg``:: [zpasswd] recipe = z3c.recipe.dev:script eggs = zope.password module = zope.password.zpasswd method = main This will generate a script ``zpasswd`` next time you run ``buildout``. When run, the script will ask you for all parameters needed to create a typical principal entry, including the encrypted password. Use:: $ bin/zpasswd --help to get a list of options. Using $ bin/zpasswd -c some/site.zcml the script will try to lookup any password manager you defined and registered in your environment. This is lookup is not necessary if you go with the standard password managers defined in `zope.password`. A typical ``zpasswd`` session:: $ ./bin/zpasswd Please choose an id for the principal. Id: foo Please choose a title for the principal. Title: The Foo Please choose a login for the principal. Login: foo Password manager: 1. Plain Text 2. MD5 3. SHA1 4. SSHA Password Manager Number [4]: SSHA password manager selected Please provide a password for the principal. Password: Verify password: Please provide an optional description for the principal. Description: The main foo ============================================ Principal information for inclusion in ZCML: ======= CHANGES ======= 3.6.1 (2010-05-27) ------------------ - The SSHAPasswordManager.checkPassword() would not handle unicode input (even if the string would only contain ascii characters). Now, the encoded_password input will be encoded to ascii, which is deemed safe as it should not contain non-ascii characters anyway. 3.6.0 (2010-05-07) ------------------ - Removed zope.testing dependency for tests. - Updated some copyright headers to comply to repository policy. - Added zpasswd script formerly hold in zope.app.server. Contrary to former zpasswd script, which used "Plain Text" as default password manager, now SSHA is used as default. 3.5.1 (2009-03-14) ------------------ - Make security protection directives in `configure.zcml` execute only if ``zope.security`` is installed. This will allow reuse of the `configure.zcml` file in environments without ``zope.security``, for example with ``repoze.zcml``. - Add "Password Manager Names" vocabulary for use with ``zope.schema`` and ``zope.component``, like it was in ``zope.app.authentication``. It's an optional feature so it doesn't add hard dependency. We use "vocabulary" extra to list dependencies needed for vocabulary functionality. 3.5.0 (2009-03-06) ------------------ First release. This package was splitted off from ``zope.app.authentication`` to separate password manager functionality that is greatly re-usable without any bit of ``zope.app.authentication`` and to reduce its dependencies. Keywords: zope authentication password zpasswd Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.password-3.6.1/src/zope.password.egg-info/dependency_links.txt0000644000175000017500000000000111377424155023337 0ustar jwjw zope.password-3.6.1/src/zope/0000755000175000017500000000000011377424160013732 5ustar jwjwzope.password-3.6.1/src/zope/password/0000755000175000017500000000000011377424160015574 5ustar jwjwzope.password-3.6.1/src/zope/password/testing.py0000644000175000017500000000500311377424153017623 0ustar jwjw############################################################################## # # Copyright (c) 2009 Zope Foundation 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 password managers as utilities $Id: testing.py 112030 2010-05-05 18:53:49Z tseaver $ """ __docformat__ = "reStructuredText" from zope.component import provideUtility from zope.schema.interfaces import IVocabularyFactory from zope.password.interfaces import IPasswordManager from zope.password.password import PlainTextPasswordManager from zope.password.password import MD5PasswordManager from zope.password.password import SHA1PasswordManager from zope.password.password import SSHAPasswordManager from zope.password.vocabulary import PasswordManagerNamesVocabulary def setUpPasswordManagers(): """Helper function for setting up password manager utilities for tests >>> from zope.component import getUtility >>> setUpPasswordManagers() >>> getUtility(IPasswordManager, 'Plain Text') >>> getUtility(IPasswordManager, 'SSHA') >>> getUtility(IPasswordManager, 'MD5') >>> getUtility(IPasswordManager, 'SHA1') >>> voc = getUtility(IVocabularyFactory, 'Password Manager Names') >>> voc = voc(None) >>> voc >>> 'SSHA' in voc True >>> 'Plain Text' in voc True >>> 'SHA1' in voc True >>> 'MD5' in voc True """ provideUtility(PlainTextPasswordManager(), IPasswordManager, 'Plain Text') provideUtility(SSHAPasswordManager(), IPasswordManager, 'SSHA') provideUtility(MD5PasswordManager(), IPasswordManager, 'MD5') provideUtility(SHA1PasswordManager(), IPasswordManager, 'SHA1') provideUtility(PasswordManagerNamesVocabulary, IVocabularyFactory, 'Password Manager Names') zope.password-3.6.1/src/zope/password/password.py0000644000175000017500000002100311377424153020006 0ustar jwjw############################################################################## # # Copyright (c) 2009 Zope Foundation 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: password.py 112740 2010-05-26 16:01:17Z janwijbrand $ """ __docformat__ = 'restructuredtext' from base64 import urlsafe_b64encode from base64 import urlsafe_b64decode from os import urandom from random import randint from codecs import getencoder try: from hashlib import md5, sha1 except ImportError: # Python 2.4 from md5 import new as md5 from sha import new as sha1 from zope.interface import implements from zope.password.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, encoded_password, password): return encoded_password == self.encodePassword(password) 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 The password manager should be able to cope with unicode strings for input:: >>> passwd = u'foobar\u2211' # sigma-sign. >>> manager.checkPassword(manager.encodePassword(passwd), passwd) True >>> manager.checkPassword(unicode(manager.encodePassword(passwd)), passwd) 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, encoded_password, password): # urlsafe_b64decode() cannot handle unicode input string. We # encode to ascii. This is safe as the encoded_password string # should not contain non-ascii characters anyway. encoded_password = encoded_password.encode('ascii') byte_string = urlsafe_b64decode(encoded_password[6:]) salt = byte_string[20:] return encoded_password == self.encodePassword(password, salt) 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 The old version of this password manager didn't add the {MD5} to passwords. Let's check if it can work with old stored passwords. >>> encoded = manager.encodePassword(password, salt="") >>> encoded = encoded[5:] >>> encoded '86dddccec45db4599f1ac00018e54139' >>> manager.checkPassword(encoded, 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, encoded_password, password): if encoded_password.startswith('{MD5}'): salt = encoded_password[5:-32] return encoded_password == self.encodePassword(password, salt) salt = encoded_password[:-32] return encoded_password == 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 The old version of this password manager didn't add the {SHA1} to passwords. Let's check if it can work with old stored passwords. >>> encoded = manager.encodePassword(password, salt="") >>> encoded = encoded[6:] >>> encoded '04b4eec7154c5f3a2ec6d2956fb80b80dc737402' >>> manager.checkPassword(encoded, 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, encoded_password, password): if encoded_password.startswith('{SHA1}'): salt = encoded_password[6:-40] return encoded_password == self.encodePassword(password, salt) salt = encoded_password[:-40] return encoded_password == self.encodePassword(password, salt)[6:] # Simple registry managers = [ ('Plain Text', PlainTextPasswordManager()), ('MD5', MD5PasswordManager()), ('SHA1', SHA1PasswordManager()), ('SSHA', SSHAPasswordManager()), ] zope.password-3.6.1/src/zope/password/interfaces.py0000644000175000017500000000204111377424153020270 0ustar jwjw############################################################################## # # Copyright (c) 2009 Zope Foundation 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. # ############################################################################## """Password manager interface $Id: interfaces.py 112030 2010-05-05 18:53:49Z tseaver $ """ import zope.interface class IPasswordManager(zope.interface.Interface): """Password manager""" def encodePassword(password): """Return encoded data for the given password""" def checkPassword(encoded_password, password): """Return whether the given encoded data coincide with the given password""" zope.password-3.6.1/src/zope/password/vocabulary.py0000644000175000017500000000245511377424153020325 0ustar jwjw############################################################################## # # Copyright (c) 2009 Zope Foundation 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. # ############################################################################## """Vocabulary of password manager utility names for use with zope.component and zope.schema. $Id: vocabulary.py 97822 2009-03-11 07:59:29Z nadako $ """ from zope.component import getUtilitiesFor from zope.interface import directlyProvides from zope.schema.interfaces import IVocabularyFactory from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm from zope.password.interfaces import IPasswordManager def PasswordManagerNamesVocabulary(context=None): terms = [] for name, util in getUtilitiesFor(IPasswordManager, context): terms.append(SimpleTerm(name)) return SimpleVocabulary(terms) directlyProvides(PasswordManagerNamesVocabulary, IVocabularyFactory) zope.password-3.6.1/src/zope/password/zpasswd.py0000644000175000017500000002137211377424153017650 0ustar jwjw############################################################################## # # Copyright (c) 2004 Zope Foundation 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. # ############################################################################## """Implementation of the zpasswd script. $Id: zpasswd.py 112149 2010-05-07 15:40:42Z ulif $ """ import optparse import os import pkg_resources import sys from xml.sax.saxutils import quoteattr VERSION = pkg_resources.get_distribution('zope.password').version def main(argv=None): """Top-level script function to create a new principals.""" if argv is None: argv = sys.argv try: options = parse_args(argv) except SystemExit, e: if e.code: return 2 else: return 0 app = Application(options) try: return app.process() except KeyboardInterrupt: return 1 except SystemExit, e: return e.code class Principal(object): """Principal. >>> principal = Principal("id", "title", "login", "password") >>> print principal >>> principal = Principal("id", "title", "login", "password", ... "description", "SHA1") >>> print principal """ def __init__(self, id, title, login, password, description="", password_manager_name="Plain Text"): self.id = id self.login = login self.password = password self.title = title self.description = description self.password_manager_name = password_manager_name def getLines(self): lines = [ ' ') return lines def __str__(self): return "\n".join(self.getLines()) TITLE = """ ============================================ Principal information for inclusion in ZCML: """ ID_TITLE = """ Please choose an id for the principal. """ TITLE_TITLE = """ Please choose a title for the principal. """ LOGIN_TITLE = """ Please choose a login for the principal. """ PASSWORD_TITLE = """ Please provide a password for the principal. """ DESCRIPTION_TITLE = """ Please provide an optional description for the principal. """ class Application(object): title = TITLE id_title = ID_TITLE title_title = TITLE_TITLE login_title = LOGIN_TITLE password_title = PASSWORD_TITLE description_title = DESCRIPTION_TITLE def __init__(self, options): self.options = options self.need_blank_line = False def read_input_line(self, prompt): # The tests replace this to make sure the right things happen. return raw_input(prompt) def read_password(self, prompt): # The tests replace this to make sure the right things happen. import getpass try: return getpass.getpass(prompt) except KeyboardInterrupt: # The cursor was left on the same line as the prompt, # which we don't like. Print a blank line. print raise def process(self): options = self.options if not options.destination: destination = sys.stdout else: destination = open(options.destination, "wb") principal = self.get_principal() if destination is sys.stdout: print self.title print >>destination, principal print return 0 def get_principal(self): id = self.get_value(self.id_title, "Id: ", "Id may not be empty") title = self.get_value(self.title_title, "Title: ", "Title may not be empty") login = self.get_value(self.login_title, "Login: ", "Login may not be empty") password_manager_name, password_manager = self.get_password_manager() password = self.get_password() description = self.get_value(self.description_title, "Description: ",) password = password_manager.encodePassword(password) return Principal(id, title, login, password, description, password_manager_name) def get_value(self, title, prompt, error=""): self.print_message(title) self.need_blank_line = True while True: value = self.read_input_line(prompt).strip() if not value and error: print >>sys.stderr, error continue return value def get_password_manager(self): default = 0 self.print_message("Password manager:") print managers = self.options.managers for i, (name, manager) in enumerate(managers): print "% i. %s" % (i + 1, name) if name == 'SSHA': default = i print self.need_blank_line = True while True: password_manager = self.read_input_line( "Password Manager Number [%s]: " % (default + 1)) if not password_manager: index = default break elif password_manager.isdigit(): index = int(password_manager) if index > 0 and index <= len(managers): index -= 1 break print >>sys.stderr, "You must select a password manager" print "%s password manager selected" % managers[index][0] return managers[index] def get_password(self): self.print_message(self.password_title) while True: password = self.read_password("Password: ") if not password: print >>sys.stderr, "Password may not be empty" continue if password != password.strip() or password.split() != [password]: print >>sys.stderr, "Password may not contain spaces" continue break again = self.read_password("Verify password: ") if again != password: print >>sys.stderr, "Password not verified!" sys.exit(1) return password def print_message(self, message): if self.need_blank_line: print self.need_blank_line = False print message def get_password_managers(config_path=None): if not config_path: from zope.password.password import managers else: from zope.configuration import xmlconfig from zope.component import getUtilitiesFor from zope.password.interfaces import IPasswordManager print "Loading configuration..." config = xmlconfig.file(config_path) managers = [] for name, manager in getUtilitiesFor(IPasswordManager): if name == "Plain Text": managers.insert(0, (name, manager)) else: managers.append((name, manager)) if not managers: from zope.password.password import managers return managers def parse_args(argv): """Parse the command line, returning an object representing the input.""" path, prog = os.path.split(os.path.realpath(argv[0])) p = optparse.OptionParser(prog=prog, usage="%prog [options]", version=VERSION) p.add_option("-c", "--config", dest="config", metavar="FILE", help=("path to the site.zcml configuration file" " (more accurate but slow password managers registry creation)")) p.add_option("-o", "--output", dest="destination", metavar="FILE", help=("the file in which the output will be saved" " (STDOUT by default)")) options, args = p.parse_args(argv[1:]) options.managers = get_password_managers(options.config) options.program = prog options.version = VERSION if args: p.error("too many arguments") return options zope.password-3.6.1/src/zope/password/__init__.py0000644000175000017500000000127311377424153017712 0ustar jwjw############################################################################## # # Copyright (c) 2009 Zope Foundation 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. # ############################################################################## """ $Id: __init__.py 112030 2010-05-05 18:53:49Z tseaver $ """ zope.password-3.6.1/src/zope/password/tests/0000755000175000017500000000000011377424160016736 5ustar jwjwzope.password-3.6.1/src/zope/password/tests/test_zpasswd.py0000644000175000017500000001134311377424153022046 0ustar jwjw############################################################################## # # Copyright (c) 2004 Zope Foundation 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. # ############################################################################## """Tests for the zpasswd script. $Id: test_zpasswd.py 112138 2010-05-07 15:23:02Z ulif $ """ import os import sys import unittest, doctest from StringIO import StringIO from zope.password import password, zpasswd class TestBase(unittest.TestCase): def setUp(self): # Create a minimal site.zcml file open('testsite.zcml', 'wb').write( '\n' ) self.stdout = StringIO() self.stderr = StringIO() self.old_stdout = sys.stdout self.old_stderr = sys.stderr sys.stdout = self.stdout sys.stderr = self.stderr def tearDown(self): sys.stdout = self.old_stdout sys.stderr = self.old_stderr # Clean up os.unlink('testsite.zcml') class ArgumentParsingTestCase(TestBase): config = "testsite.zcml" def parse_args(self, args): argv = ["foo/bar.py"] + args options = zpasswd.parse_args(argv) self.assertEqual(options.program, "bar.py") self.assert_(options.version) return options def check_stdout_content(self, args): try: options = self.parse_args(args) except SystemExit, e: self.assertEqual(e.code, 0) self.assert_(self.stdout.getvalue()) self.failIf(self.stderr.getvalue()) else: self.fail("expected SystemExit") def test_no_arguments(self): options = self.parse_args([]) self.assert_(options.managers) self.assert_(not options.destination) def test_version_long(self): self.check_stdout_content(["--version"]) def test_help_long(self): self.check_stdout_content(["--help"]) def test_help_short(self): self.check_stdout_content(["-h"]) def test_destination_short(self): options = self.parse_args(["-o", "filename"]) self.assertEqual(options.destination, "filename") def test_destination_long(self): options = self.parse_args(["--output", "filename"]) self.assertEqual(options.destination, "filename") def test_config_short(self): options = self.parse_args(["-c", self.config]) self.assert_(options.managers) def test_config_long(self): options = self.parse_args(["--config", self.config]) self.assert_(options.managers) class ControlledInputApplication(zpasswd.Application): def __init__(self, options, input_lines): super(ControlledInputApplication, self).__init__(options) self.__input = input_lines def read_input_line(self, prompt): return self.__input.pop(0) read_password = read_input_line def all_input_consumed(self): return not self.__input class Options(object): config = None destination = None version = "[test-version]" program = "[test-program]" managers = password.managers class InputCollectionTestCase(TestBase): def createOptions(self): return Options() def check_principal(self, expected): output = self.stdout.getvalue() self.failUnless(output) principal_lines = output.splitlines()[-(len(expected) + 1):-1] for line, expline in zip(principal_lines, expected): self.failUnlessEqual(line.strip(), expline) def test_principal_information(self): options = self.createOptions() app = ControlledInputApplication(options, ["id", "title", "login", "1", "passwd", "passwd", "description"]) app.process() self.failUnless(not self.stderr.getvalue()) self.failUnless(app.all_input_consumed()) self.check_principal([ '' ]) def test_suite(): suite = doctest.DocTestSuite('zope.password.zpasswd') suite.addTest(unittest.makeSuite(ArgumentParsingTestCase)) suite.addTest(unittest.makeSuite(InputCollectionTestCase)) return suite if __name__ == '__main__': unittest.main(defaultTest='test_suite') zope.password-3.6.1/src/zope/password/tests/test_password.py0000644000175000017500000000173011377424153022214 0ustar jwjw############################################################################## # # Copyright (c) 2009 Zope Foundation 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. # ############################################################################## """Password Managers Tests $Id: test_password.py 112141 2010-05-07 15:31:39Z ulif $ """ import doctest import unittest def test_suite(): return unittest.TestSuite(( doctest.DocTestSuite('zope.password.password'), doctest.DocTestSuite( 'zope.password.testing', optionflags=doctest.ELLIPSIS), )) zope.password-3.6.1/src/zope/password/tests/__init__.py0000644000175000017500000000121111377424153021044 0ustar jwjw############################################################################## # # Copyright (c) 2010 Zope Foundation 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. # ############################################################################## """ $Id$ """ zope.password-3.6.1/src/zope/password/configure.zcml0000644000175000017500000000257011377424153020452 0ustar jwjw zope.password-3.6.1/src/zope/__init__.py0000644000175000017500000000031111377424153016040 0ustar jwjw# this is a namespace package try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) zope.password-3.6.1/buildout.cfg0000644000175000017500000000104611377424153014501 0ustar jwjw[buildout] develop = . parts = zpasswd test coverage-test coverage-report [test] recipe = zc.recipe.testrunner eggs = zope.password [test] [coverage-test] recipe = zc.recipe.testrunner eggs = zope.password [test] defaults = ['--coverage', '../../coverage'] [coverage-report] recipe = zc.recipe.egg eggs = z3c.coverage zope.password scripts = coverage=coverage-report arguments = ('coverage', 'coverage/report') interpreter = python [zpasswd] recipe = z3c.recipe.dev:script eggs = zope.password module = zope.password.zpasswd method = main zope.password-3.6.1/setup.cfg0000644000175000017500000000007311377424160014007 0ustar jwjw[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 zope.password-3.6.1/PKG-INFO0000644000175000017500000001744411377424160013275 0ustar jwjwMetadata-Version: 1.0 Name: zope.password Version: 3.6.1 Summary: Password encoding and checking utilities Home-page: http://pypi.python.org/pypi/zope.password Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: ================ Password Manager ================ This package provides a password manager mechanism. Password manager is an utility object that can encode and check encoded passwords. Beyond the generic interface, this package also provides four implementations: * PlainTextPasswordManager - the most simple and the less secure one. It does not do any password encoding and simply checks password by string equality. It's useful in tests or as a base class for more secure implementations. * MD5PasswordManager - a password manager that uses MD5 algorithm to encode passwords. It adds salt to the encoded password, but the salt is not used for encoding the password itself, so the use of salt in it is purely cosmetical. It's generally weak against dictionary attacks. * SHA1PasswordManager - a password manager that uses SHA1 algorithm to encode passwords. It has the same salt weakness as the MD5PasswordManager. * SSHAPasswordManager - the most secure password manager that is strong against dictionary attacks. It's basically SHA1-encoding password manager which also incorporates a salt into the password when encoding it. This password manager is compatible with passwords used in LDAP databases. It is strongly recommended to use SSHAPasswordManager, as it's the most secure. The package also provides a script `zpasswd` to generate principal entries in typical ``site.zcml`` files. Usage ----- It's very easy to use password managers. The ``zope.password.interfaces.IPasswordManager`` interface defines only two methods:: def encodePassword(password): """Return encoded data for the given password""" def checkPassword(encoded_password, password): """Return whether the given encoded data coincide with the given password""" The implementations mentioned above are in the ``zope.password.password`` module. Password Manager Names Vocabulary --------------------------------- The ``zope.password.vocabulary`` module provides a vocabulary of registered password manager utility names. It is typically registered as an `IVocabularyFactory` utility named "Password Manager Names". It's intended to be used with ``zope.component`` and ``zope.schema``, so you need to have them installed and the utility registrations needs to be done properly. The `configure.zcml` file, contained in ``zope.password`` does the registrations, as well as in `setUpPasswordManagers` function in ``zope.password.testing`` module. zpasswd script -------------- ``zpasswd`` is a script to generate principal entries in typical ``site.zcml`` files. You can create a ``zpasswd`` script in your package by adding a section like this to your ``buildout.cfg``:: [zpasswd] recipe = z3c.recipe.dev:script eggs = zope.password module = zope.password.zpasswd method = main This will generate a script ``zpasswd`` next time you run ``buildout``. When run, the script will ask you for all parameters needed to create a typical principal entry, including the encrypted password. Use:: $ bin/zpasswd --help to get a list of options. Using $ bin/zpasswd -c some/site.zcml the script will try to lookup any password manager you defined and registered in your environment. This is lookup is not necessary if you go with the standard password managers defined in `zope.password`. A typical ``zpasswd`` session:: $ ./bin/zpasswd Please choose an id for the principal. Id: foo Please choose a title for the principal. Title: The Foo Please choose a login for the principal. Login: foo Password manager: 1. Plain Text 2. MD5 3. SHA1 4. SSHA Password Manager Number [4]: SSHA password manager selected Please provide a password for the principal. Password: Verify password: Please provide an optional description for the principal. Description: The main foo ============================================ Principal information for inclusion in ZCML: ======= CHANGES ======= 3.6.1 (2010-05-27) ------------------ - The SSHAPasswordManager.checkPassword() would not handle unicode input (even if the string would only contain ascii characters). Now, the encoded_password input will be encoded to ascii, which is deemed safe as it should not contain non-ascii characters anyway. 3.6.0 (2010-05-07) ------------------ - Removed zope.testing dependency for tests. - Updated some copyright headers to comply to repository policy. - Added zpasswd script formerly hold in zope.app.server. Contrary to former zpasswd script, which used "Plain Text" as default password manager, now SSHA is used as default. 3.5.1 (2009-03-14) ------------------ - Make security protection directives in `configure.zcml` execute only if ``zope.security`` is installed. This will allow reuse of the `configure.zcml` file in environments without ``zope.security``, for example with ``repoze.zcml``. - Add "Password Manager Names" vocabulary for use with ``zope.schema`` and ``zope.component``, like it was in ``zope.app.authentication``. It's an optional feature so it doesn't add hard dependency. We use "vocabulary" extra to list dependencies needed for vocabulary functionality. 3.5.0 (2009-03-06) ------------------ First release. This package was splitted off from ``zope.app.authentication`` to separate password manager functionality that is greatly re-usable without any bit of ``zope.app.authentication`` and to reduce its dependencies. Keywords: zope authentication password zpasswd Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zope.password-3.6.1/COPYRIGHT.txt0000644000175000017500000000004011377424153014273 0ustar jwjwZope Foundation and Contributorszope.password-3.6.1/README.txt0000644000175000017500000001011011377424153013657 0ustar jwjw================ Password Manager ================ This package provides a password manager mechanism. Password manager is an utility object that can encode and check encoded passwords. Beyond the generic interface, this package also provides four implementations: * PlainTextPasswordManager - the most simple and the less secure one. It does not do any password encoding and simply checks password by string equality. It's useful in tests or as a base class for more secure implementations. * MD5PasswordManager - a password manager that uses MD5 algorithm to encode passwords. It adds salt to the encoded password, but the salt is not used for encoding the password itself, so the use of salt in it is purely cosmetical. It's generally weak against dictionary attacks. * SHA1PasswordManager - a password manager that uses SHA1 algorithm to encode passwords. It has the same salt weakness as the MD5PasswordManager. * SSHAPasswordManager - the most secure password manager that is strong against dictionary attacks. It's basically SHA1-encoding password manager which also incorporates a salt into the password when encoding it. This password manager is compatible with passwords used in LDAP databases. It is strongly recommended to use SSHAPasswordManager, as it's the most secure. The package also provides a script `zpasswd` to generate principal entries in typical ``site.zcml`` files. Usage ----- It's very easy to use password managers. The ``zope.password.interfaces.IPasswordManager`` interface defines only two methods:: def encodePassword(password): """Return encoded data for the given password""" def checkPassword(encoded_password, password): """Return whether the given encoded data coincide with the given password""" The implementations mentioned above are in the ``zope.password.password`` module. Password Manager Names Vocabulary --------------------------------- The ``zope.password.vocabulary`` module provides a vocabulary of registered password manager utility names. It is typically registered as an `IVocabularyFactory` utility named "Password Manager Names". It's intended to be used with ``zope.component`` and ``zope.schema``, so you need to have them installed and the utility registrations needs to be done properly. The `configure.zcml` file, contained in ``zope.password`` does the registrations, as well as in `setUpPasswordManagers` function in ``zope.password.testing`` module. zpasswd script -------------- ``zpasswd`` is a script to generate principal entries in typical ``site.zcml`` files. You can create a ``zpasswd`` script in your package by adding a section like this to your ``buildout.cfg``:: [zpasswd] recipe = z3c.recipe.dev:script eggs = zope.password module = zope.password.zpasswd method = main This will generate a script ``zpasswd`` next time you run ``buildout``. When run, the script will ask you for all parameters needed to create a typical principal entry, including the encrypted password. Use:: $ bin/zpasswd --help to get a list of options. Using $ bin/zpasswd -c some/site.zcml the script will try to lookup any password manager you defined and registered in your environment. This is lookup is not necessary if you go with the standard password managers defined in `zope.password`. A typical ``zpasswd`` session:: $ ./bin/zpasswd Please choose an id for the principal. Id: foo Please choose a title for the principal. Title: The Foo Please choose a login for the principal. Login: foo Password manager: 1. Plain Text 2. MD5 3. SHA1 4. SSHA Password Manager Number [4]: SSHA password manager selected Please provide a password for the principal. Password: Verify password: Please provide an optional description for the principal. Description: The main foo ============================================ Principal information for inclusion in ZCML: zope.password-3.6.1/LICENSE.txt0000644000175000017500000000402611377424153014015 0ustar jwjwZope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.