summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2011-04-26 16:24:07 -0400
committerEli Collins <elic@assurancetechnologies.com>2011-04-26 16:24:07 -0400
commitaa38d176519ae0744851e865b948e994ca8e89b3 (patch)
tree2a02e5fccbef5431225fbfea5d849e742e752bc1 /docs
parent6d54c06e246400e985e582b4d73ad1b4e3d62f37 (diff)
downloadpasslib-aa38d176519ae0744851e865b948e994ca8e89b3.tar.gz
rearranged/expanded CryptContext docs
Diffstat (limited to 'docs')
-rw-r--r--docs/contents.rst2
-rw-r--r--docs/lib/passlib.apps.rst4
-rw-r--r--docs/lib/passlib.context-interface.rst12
-rw-r--r--docs/lib/passlib.context-options.rst10
-rw-r--r--docs/lib/passlib.context-usage.rst310
-rw-r--r--docs/lib/passlib.context.rst266
-rw-r--r--docs/lib/passlib.hash.ldap_digests.rst1
-rw-r--r--docs/password_hash_api.rst1
8 files changed, 348 insertions, 258 deletions
diff --git a/docs/contents.rst b/docs/contents.rst
index 4912478..0388691 100644
--- a/docs/contents.rst
+++ b/docs/contents.rst
@@ -9,8 +9,6 @@ Table Of Contents
overview
lib/passlib.context
- lib/passlib.context-interface
- lib/passlib.context-options
lib/passlib.apps
lib/passlib.apache
lib/passlib.hosts
diff --git a/docs/lib/passlib.apps.rst b/docs/lib/passlib.apps.rst
index 2ee37b4..27e2058 100644
--- a/docs/lib/passlib.apps.rst
+++ b/docs/lib/passlib.apps.rst
@@ -7,8 +7,8 @@
This lists a number of :class:`!CryptContext` instances that are predefined
by PassLib for easily handling the multiple formats used by various applications.
-(For details about how to *use* a :class:`!CryptContext` instance,
-see the documentation for the :class:`CryptContext` class itself).
+(For details about how to use a :class:`!CryptContext` instance,
+see :doc:`passlib.context-usage`).
.. _quickstart-custom-applications:
diff --git a/docs/lib/passlib.context-interface.rst b/docs/lib/passlib.context-interface.rst
index 0c9d2e6..8331992 100644
--- a/docs/lib/passlib.context-interface.rst
+++ b/docs/lib/passlib.context-interface.rst
@@ -3,7 +3,7 @@
.. _cryptcontext-interface:
===============================================
-:mod:`passlib.context` - CryptContext Interface
+:mod:`passlib.context` - Module Contents
===============================================
.. currentmodule:: passlib.context
@@ -13,12 +13,18 @@ and :class:`!CryptPolicy`.
.. seealso::
- * :doc:`passlib.context-options` -- for a list of all the keyword options accepted by these classes.
+ * :doc:`passlib.context-usage`
- * :doc:`passlib.context` -- for an overview and some usage examples.
+ * :doc:`passlib.context-options`
+The Context Object
+==================
.. autoclass:: CryptContext(schemes=None, policy=<default policy>, \*\*kwds)
+The Policy Object
+=================
.. autoclass:: CryptPolicy(\*\*kwds)
+Other Helpers
+=============
.. autoclass:: LazyCryptContext([schemes=None,] **kwds [, create_policy=None])
diff --git a/docs/lib/passlib.context-options.rst b/docs/lib/passlib.context-options.rst
index b15dc5d..e799cdf 100644
--- a/docs/lib/passlib.context-options.rst
+++ b/docs/lib/passlib.context-options.rst
@@ -3,7 +3,7 @@
.. _cryptcontext-options:
=============================================
-:mod:`passlib.context` - CryptContext options
+:mod:`passlib.context` - Constructor Options
=============================================
.. currentmodule:: passlib.context
@@ -15,7 +15,9 @@ which affect the context treats a particular type of hash:
.. seealso::
- :doc:`passlib.context` -- for an overview of the classes and some usage examples.
+ * :doc:`passlib.context-usage`
+
+ * :doc:`passlib.context-interface`
Context Options
===============
@@ -190,7 +192,9 @@ or viewed in the source code under ``$SOURCE/passlib/default.cfg``.
Sample Policy File
==================
-A sample policy file::
+A sample policy file:
+
+.. code-block:: ini
[passlib]
#configure what schemes the context supports (note the "context." prefix is implied for these keys)
diff --git a/docs/lib/passlib.context-usage.rst b/docs/lib/passlib.context-usage.rst
new file mode 100644
index 0000000..8464a1e
--- /dev/null
+++ b/docs/lib/passlib.context-usage.rst
@@ -0,0 +1,310 @@
+.. index:: CryptContext; usage examples
+
+.. _cryptcontext-examples:
+
+====================================================
+:mod:`passlib.context` - Usage Examples
+====================================================
+
+.. currentmodule:: passlib.context
+
+This section gives examples on how to use the :class:`CryptContext` object
+for a number of different use cases.
+
+.. seealso::
+
+ * :doc:`passlib.context-interface`
+
+ * :doc:`passlib.context-options`
+
+Basic Usage
+===========
+To start off with a simple example of how to create and use a CryptContext::
+
+ >>> from passlib.context import CryptContext
+
+ >>> #create a new context that only understands Md5Crypt & DesCrypt:
+ >>> myctx = CryptContext([ "md5_crypt", "des_crypt" ])
+
+ >>> #unless overidden, the first hash listed
+ >>> #will be used as the default for encrypting
+ >>> #(in this case, md5_crypt):
+ >>> hash1 = myctx.encrypt("too many secrets")
+ >>> hash1
+ '$1$nH3CrcVr$pyYzik1UYyiZ4Bvl1uCtb.'
+
+ >>> #the scheme may be forced explicitly,
+ >>> #though it must be one of the ones recognized by the context:
+ >>> hash2 = myctx.encrypt("too many secrets", scheme="des_crypt")
+ >>> hash2
+ 'm9pvLj4.hWxJU'
+
+ >>> #verification will autodetect the correct type of hash:
+ >>> myctx.verify("too many secrets", hash1)
+ True
+ >>> myctx.verify("too many secrets", hash2)
+ True
+ >>> myctx.verify("too many socks", hash2)
+ False
+
+ >>> #you can also have it identify the algorithm in use:
+ >>> myctx.identify(hash1)
+ 'md5_crypt'
+
+ >>> #or just return the handler instance directly:
+ >>> myctx.identify(hash1, resolve=True)
+ <class 'passlib.handlers.md5_crypt.md5_crypt'>
+
+.. _using-predefined-contexts:
+
+Using Predefined CryptContexts
+==============================
+Passlib contains a number of pre-made :class:`!CryptContext` instances,
+configured for various purposes
+(see :mod:`passlib.apps` and :mod:`passlib.hosts`).
+These can be used directly by importing them from passlib,
+such as the following example:
+
+ >>> from passlib.apps import ldap_context as pwd_context
+ >>> pwd_context.encrypt("somepass")
+ '{SSHA}k4Ap0wYJWMrkgNhptlntsPGETBBwEoSH'
+
+However, applications which use the predefined contexts will frequently
+find they need to modify the context in some way, such as selecting
+a different default hash scheme. This is best done by importing
+the original context, and then making an application-specific
+copy; using the :meth:`CryptContext.replace` method to create
+a mutated copy of the original object::
+
+ >>> from passlib.apps import ldap_context
+ >>> pwd_context = ldap_context.replace(default="ldap_md5_crypt")
+ >>> pwd_context.encrypt("somepass")
+ '{CRYPT}$1$Cw7t4sbP$dwRgCMc67mOwwus9m33z71'
+
+Examining a CryptContext Instance
+=================================
+All configuration options for a :class:`!CryptContext` instance
+are stored in a :class:`!CryptPolicy` instance accessible through
+the :attr:`CryptContext.policy` attribute::
+
+ >>> from passlib.context import CryptContext
+ >>> myctx = CryptContext([ "md5_crypt", "des_crypt" ], deprecated="des_crypt")
+
+ >>> #get a list of schemes recognized in this context:
+ >>> myctx.policy.schemes()
+ [ 'md5-crypt', 'bcrypt' ]
+
+ >>> #get the default handler class :
+ >>> myctx.policy.get_handler()
+ <class 'passlib.handlers.md5_crypt.md5_crypt'>
+
+See the :class:`CryptPolicy` class for more details on it's interface.
+
+Full Integration Example
+========================
+The following is an extended example of how PassLib can be integrated into an existing
+application to provide runtime policy changes, deprecated hash migration,
+and other features. This is example uses a lot of different features,
+and many developers will want to pick and choose what they need from this example.
+The totality of this example is overkill for most simple applications.
+
+Policy Configuration File
+-------------------------
+
+While it is possible to create a CryptContext instance manually, or to import an existing one,
+applications with advanced policy requirements may want to create a hash policy file
+(options show below are detailed in :ref:`cryptcontext-options`):
+
+.. code-block:: ini
+
+ ; the options file uses the INI file format,
+ ; and passlib will only read the section named "passlib",
+ ; so it can be included along with other application configuration.
+
+ [passlib]
+
+ ;setup the context to support pbkdf2_sha1, along with legacy md5_crypt hashes:
+ schemes = pbkdf2_sha1, md5_crypt
+
+ ;flag md5_crypt as deprecated
+ ; (existing md5_crypt hashes will be flagged as needs-updating)
+ deprecated = md5_crypt
+
+ ;set verify to always take at least 1/10th of a second
+ min_verify_time = 0.1
+
+ ;set boundaries for pbkdf2 rounds parameter
+ ; (pbkdf2 hashes outside this range will be flagged as needs-updating)
+ pbkdf2_sha1.min_rounds = 10000
+ pbkdf2_sha1.max_rounds = 50000
+
+ ;set the default rounds to use when encrypting new passwords.
+ ;the 'vary' field will cause each new hash to randomly vary
+ ;from the default by the specified %.
+ pbkdf2_sha1.default_rounds = 20000
+ pbkdf2_sha1.vary_rounds = 10%
+
+ ;applications can choose to treat certain user accounts differently,
+ ;by assigning different types of account to a 'user category',
+ ;and setting special policy options for that category.
+ ;this create a category named 'admin', which will have a larger default rounds value.
+ admin.pbkdf2_sha1.min_rounds = 40000
+ admin.pbkdf2_sha1.default_rounds = 50000
+
+Initializing the CryptContext
+-----------------------------
+Applications which choose to use a policy file will typically want
+to create the CryptContext at the module level, and then load
+the configuration once the application starts:
+
+1. Within a common module in your application (eg ``myapp.model.security``)::
+
+ #
+ #create a crypt context that can be imported and used wherever is needed...
+ #the instance will be configured later.
+ #
+ from passlib.context import CryptContext
+ user_pwd_context = CryptContext()
+
+2. Within some startup function within your application::
+
+ #
+ #when the app starts, import the context from step 1 and
+ #configure it... such as by loading a policy file (see above)
+ #
+
+ from myapp.model.security import user_pwd_context
+ from passlib.context import CryptPolicy
+
+ def myapp_startup():
+
+ #
+ # ... other code ...
+ #
+
+ # vars:
+ # policy_path - path to policy file defined in previous step
+ #
+ user_pwd_context.policy = CryptPolicy.from_path(policy_path)
+
+ #
+ #if you want to reconfigure the context without restarting the application,
+ #simply repeat the above step at another point.
+ #
+
+ #
+ # ... other code ...
+ #
+
+Encrypting New Passwords
+------------------------
+When it comes time to create a new user's password, insert
+the following code in the correct function::
+
+ from myapp.model.security import user_pwd_context
+
+ def handle_user_creation():
+
+ #
+ # ... other code ...
+ #
+
+ # vars:
+ # 'secret' containing the putative password
+ # 'category' containing a category assigned to the user account
+ #
+
+ hash = user_pwd_context.encrypt(secret, category=category)
+
+ #... perform appropriate actions to store hash...
+
+ #
+ # ... other code ...
+ #
+
+.. note::
+
+ In the above code, the 'category' kwd can be omitted entirely, *OR*
+ set to a string matching a user category specified in the policy file.
+ In the latter case, any category-specific policy settings will be enforced.
+ For this example, assume it's ``None`` for most users, and ``"admin"`` for special users.
+ this namespace is entirely application chosen, it just has to match the policy file.
+
+ See :ref:`user-categories` for more details.
+
+Verifying Existing Passwords
+----------------------------
+Finally, when it comes time to check a users' password, insert
+the following code at the correct place::
+
+ from myapp.model.security import user_pwd_context
+
+ def handle_user_login():
+
+ #
+ # ... other code ...
+ #
+
+ #
+ #vars:
+ # 'hash' containing the specified user's hash,
+ # 'secret' containing the putative password
+ # 'category' containing a category assigned to the user account
+ #
+ #see note in "Encrypting New Passwords" about the category kwd
+ #
+
+ ok = user_pwd_context.verify(secret, hash, category=category)
+ if not ok:
+ #... password did not match. do mean things ...
+ pass
+
+ else:
+ #... password matched ...
+ #... do successful login actions ...
+ pass
+
+Verifying & Migrating Existing Passwords
+----------------------------------------
+The CryptContext object offers the ability to deprecate schemes,
+set lower strength bounds, and then flag any existing hashes which
+violate these limits.
+Applications which want to re-encrypt any deprecated hashes
+found in their database should use the following template
+instead of the one found in the previous step::
+
+ from myapp.model.security import user_pwd_context
+
+ def handle_user_login():
+
+ #
+ # ... other code ...
+ #
+
+ #
+ #this example both checks the user's password AND upgrades deprecated hashes...
+ #given the following variables:
+ #
+ #vars:
+ # 'hash' containing the specified user's hash,
+ # 'secret' containing the putative password
+ # 'category' containing a category assigned to the user account
+ #
+ #see note in "Encrypting New Passwords" about the category kwd
+ #
+
+ ok, new_hash = user_pwd_context.verify_and_update(secret, hash, category=category)
+ if not ok:
+ #... password did not match. do mean things ...
+ pass
+
+ else:
+ #... password matched ...
+
+ if new_hash:
+ # old hash was deprecated by policy.
+
+ # ... replace hash w/ new_hash for user account ...
+ pass
+
+ #... do successful login actions ...
diff --git a/docs/lib/passlib.context.rst b/docs/lib/passlib.context.rst
index 769815c..ecc795e 100644
--- a/docs/lib/passlib.context.rst
+++ b/docs/lib/passlib.context.rst
@@ -9,258 +9,30 @@
.. module:: passlib.context
:synopsis: CryptContext class for managing multiple password hash schemes
-Overview
-========
-Different storage contexts (eg: linux shadow files vs openbsd shadow files)
-may use different sets and subsets of the available algorithms.
-Similarly, over time, applications may need to deprecate password schemes
-in favor of newer ones, or raise the number of rounds required
-by existing hashes.
+Though there is a wide range of password hashing schemes,
+within a specific context (like a linux "shadow" file)
+only a select list of schemes will be used.
+As time goes on, new schemes are added and made the default,
+the strength of existing schemes is tweaked, and other schemes are deprecated entirely.
+Throughout all this, existing password hashes that don't comply
+with the new policies must be detected and rehashed using the
+new default configuration. In order to automate as much of these tasks as possible,
+this module provides the :class:`CryptContext` class.
-This module provides the :class:`CryptContext` class, which is designed
-to handle (as much as possible) of these tasks for an application.
Essentially, a :class:`!CryptContext` instance contains a list
of hash handlers that it should recognize, along with information
about which ones are deprecated, which is the default,
and what configuration constraints an application has placed
-on a particular hash.
+on a particular scheme. While contexts can be created explicitly,
+Passlib also offers a number of predefined :class:`!CryptContext` instances
+which can be used out-of-the box (see :mod:`passlib.apps` and :mod:`passlib.hosts`),
+or :ref:`modified <using-predefined-contexts>` to suit the application.
-.. seealso::
+New users should see the usage examples
+to get a feel for how the :class:`!CryptContext` class works.
- * :doc:`passlib.context-interface` -- for a list of all class and instance methods
+.. toctree::
- * :doc:`passlib.context-options` -- for a list of all the keyword options accepted by these classes.
-
-Usage Examples
-==============
-
-Basic Usage
------------
-To start off with a simple example of how to create and use a CryptContext::
-
- >>> from passlib.context import CryptContext
-
- >>> #create a new context that only understands Md5Crypt & DesCrypt:
- >>> myctx = CryptContext([ "md5_crypt", "des_crypt" ])
-
- >>> #unless overidden, the first hash listed
- >>> #will be used as the default for encrypting
- >>> #(in this case, md5_crypt):
- >>> hash1 = myctx.encrypt("too many secrets")
- >>> hash1
- '$1$nH3CrcVr$pyYzik1UYyiZ4Bvl1uCtb.'
-
- >>> #the scheme may be forced explicitly,
- >>> #though it must be one of the ones recognized by the context:
- >>> hash2 = myctx.encrypt("too many secrets", scheme="des_crypt")
- >>> hash2
- 'm9pvLj4.hWxJU'
-
- >>> #verification will autodetect the correct type of hash:
- >>> myctx.verify("too many secrets", hash1)
- True
- >>> myctx.verify("too many secrets", hash2)
- True
- >>> myctx.verify("too many socks", hash2)
- False
-
- >>> #you can also have it identify the algorithm in use:
- >>> myctx.identify(hash1)
- 'md5_crypt'
-
- >>> #or just return the handler instance directly:
- >>> myctx.identify(hash1, resolve=True)
- <class 'passlib.handlers.md5_crypt.md5_crypt'>
-
-Policy Examination
-------------------
-If introspection of a :class:`!CryptContext` instance
-is needed, all configuration options are stored in a :class:`!CryptPolicy` instance accessible through
-their ``policy`` attribute::
-
- >>> from passlib.context import CryptContext
- >>> myctx = CryptContext([ "md5_crypt", "des_crypt" ], deprecated="des_crypt")
-
- >>> #get a list of schemes recognized in this context:
- >>> myctx.policy.schemes()
- [ 'md5-crypt', 'bcrypt' ]
-
- >>> #get the default handler class :
- >>> myctx.policy.get_handler()
- <class 'passlib.handlers.md5_crypt.md5_crypt'>
-
-See the :class:`CryptPolicy` class for more details on it's interface.
-
-Full Integration
-----------------
-The following is an extended example of how PassLib can be integrated into an existing
-application to provide runtime policy changes, deprecated hash migration,
-and other features. This is example uses a lot of different features,
-and many developers will want to pick and choose what they need from this example.
-
-Policy Options File
-...................
-Instead of creating a CryptContext instance manually,
-or importing an existing one (eg :data:`~passlib.apps.custom_app_context`),
-applications with advanced policy requirements may want to create a hash policy file
-(options show below are detailed in :ref:`cryptcontext-options`)::
-
- ; the options file uses the INI file format,
- ; and passlib will only read the section named "passlib",
- ; so it can be included along with other application configuration.
-
- [passlib]
-
- ;setup the context to support pbkdf2_sha1, along with legacy md5_crypt hashes:
- schemes = pbkdf2_sha1, md5_crypt
-
- ;flag md5_crypt as deprecated
- ; (existing md5_crypt hashes will be flagged as needs-updating)
- deprecated = md5_crypt
-
- ;set verify to always take at least 1/10th of a second
- min_verify_time = 0.1
-
- ;set boundaries for pbkdf2 rounds parameter
- ; (pbkdf2 hashes outside this range will be flagged as needs-updating)
- pbkdf2_sha1.min_rounds = 10000
- pbkdf2_sha1.max_rounds = 50000
-
- ;set the default rounds to use when encrypting new passwords.
- ;the 'vary' field will cause each new hash to randomly vary
- ;from the default by the specified %.
- pbkdf2_sha1.default_rounds = 20000
- pbkdf2_sha1.vary_rounds = 10%
-
- ;applications can choose to treat certain user accounts differently,
- ;by assigning different types of account to a 'user category',
- ;and setting special policy options for that category.
- ;this create a category named 'admin', which will have a larger default rounds value.
- admin.pbkdf2_sha1.min_rounds = 40000
- admin.pbkdf2_sha1.default_rounds = 50000
-
-Integrating a CryptContext
---------------------------
-Integrating a crypt context is merely a matter of adding the following
-bits of code to your application.
-
-1. Within a common module in your application (eg ``myapp.model.security``)::
-
- #
- #create a crypt context that can be imported and used wherever is needed...
- #the instance will be configured later.
- #
- from passlib.context import CryptContext
- user_pwd_context = CryptContext()
-
-2. Within some startup function within your application::
-
- #
- #when the app starts, import the context from step 1 and
- #configure it... such as by loading a policy file (see above)
- #
-
- from myapp.model.security import user_pwd_context
- from passlib.context import CryptPolicy
-
- def myapp_startup():
-
- #
- # ... other code ...
- #
-
- user_pwd_context.policy = CryptPolicy.from_path(path_to_policy_file)
-
- #
- #if you want to reconfigure the context without restarting the application,
- #simply repeat the above step at another point.
- #
-
- #
- # ... other code ...
- #
-
-
-3. When it comes time to create a new user's password, insert
- the following code in the correct function::
-
-
- from myapp.model.security import user_pwd_context
-
- def handle_user_creation():
-
- #
- # ... other code ...
- #
-
- #
- # 'secret' containing the putative password
- # 'category' containing a category assigned to the user account
- #
- #the 'category' kwd can be omitted, OR:
- #set to a string matching a user category specified in the policy file,
- #in which case the category-specific policy settings will be enforced.
- #for this example, assume it's None for most users, and "admin" for special users.
- #this namespace is entirely application chosen, it just has to match the policy file.
- #
-
- hash = user_pwd_context.encrypt(secret, category=category)
-
- #... perform appropriate actions to store hash...
-
- #
- # ... other code ...
- #
-
-4. Finally, when it comes time to check a users' password, insert
- the following code at the correct place::
-
- from myapp.model.security import user_pwd_context
-
- def handle_user_login():
-
- #
- # ... other code ...
- #
-
- #
- #this example both checks the user's password AND upgrades deprecated hashes...
- #given the following variables:
- # 'hash' containing the specified user's hash,
- # 'secret' containing the putative password
- # 'category' containing a category assigned to the user account
- #
- #see note in step 3 about the category kwd
- #
-
-
- ok, new_hash = user_pwd_context.verify_and_update(secret, hash, category=category)
- if not ok:
- #... password did not match. do mean things ...
- else:
- #... password matched ...
-
- if new_hash:
- # old hash was deprecated by policy.
-
- # ... replace hash w/ new_hash for user account ...
-
- #... do successful login actions ...
-
- For those who don't want to use any of the hash update features,
- the following template can be used instead::
-
- from myapp.model.security import user_pwd_context
-
- def handle_user_login():
-
- #
- # ... other code ...
- #
-
- ok = user_pwd_context.verify(secret, hash, category=category)
- if not ok:
- #... password did not match. do mean things ...
- else:
- #... password matched ...
- #... do successful login actions ...
+ passlib.context-usage
+ passlib.context-interface
+ passlib.context-options
diff --git a/docs/lib/passlib.hash.ldap_digests.rst b/docs/lib/passlib.hash.ldap_digests.rst
index 8ed38e0..28f02a0 100644
--- a/docs/lib/passlib.hash.ldap_digests.rst
+++ b/docs/lib/passlib.hash.ldap_digests.rst
@@ -67,6 +67,7 @@ All of these classes follow a single basic format [#rfc]_:
ldap_md5, ldap_sha1
These hashes have the format :samp:`{prefix}{checksum}`.
+
* :samp:`{prefix}` is `{MD5}` for ldap_md5,
and `{SHA}` for ldap_sha1.
* :samp:`{checksum}` is the base64 encoding
diff --git a/docs/password_hash_api.rst b/docs/password_hash_api.rst
index 1491280..c450c41 100644
--- a/docs/password_hash_api.rst
+++ b/docs/password_hash_api.rst
@@ -428,7 +428,6 @@ the following attributes are usually exposed.
in that situtation should be documentated.
..
-
not yet documentated, want to make sure this is how we want to do things:
.. attribute:: PasswordHash.default_salt_size