This repository was archived by the owner on Oct 21, 2024. It is now read-only.
sixfeetup/speak_friend
Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
speak_friend
============
Overview
--------
A stand-alone OpenID implementation in Pyramid.
Password Management
-------------------
This package provides a configuration plug point for specific implementations
to determine how to manage passwords over time. The configuration method is
called 'set_password_context' and it accepts one of four possible keyword
arguments:
* context: if provided, this must be a passlib.context.CryptContext instance
* ini_string: if provided must be a string containing configuration as written
by the 'to_string' method of the passlib.context.CryptContext class
* ini_file: if provided, must be a string which identifies a file in .ini
format which contains the configuration settings for a CryptContext (see the
'to_string' method of the passlib.context.CryptContext class for a way to
generate these settings)
* context_dict: if provided must be a dictionary of configuration values
suitable for constructing a CryptContext object (see the to_dict method of
the passlib.context.CryptContext class for details)
if more than one of these keywords is provided, the order above is obeyed.
CryptContext instances take precedence over ini_strings, etc.
An implementation might do something like the following:
in ``production.ini``:
.. code-block:: ini
[app:main]
password.context_file = /path/to/password/configuration.ini
in the package ``__init__.py``:
.. code-block:: python
def main(global_config, **settings):
ini_path = settings['password.context_file']
config = Configurator(settings=settings)
config.set_password_context(ini_path)
So long as the file identified by the path contains configuration suitable for
constructing a passlib Crypt.Context, the instance created will be found
thereafter at config.registry.password_context.
That CryptContext instance supports password encryption, verification, and
even deprecation. Given a login view with the following code, administrators
could automate the process of rolling their users from one password hashing
scheme to another automatically (example is from the passlib documentation):
.. code-block:: python
hash = get_hash_from_user(user)
if pass_ctx.verify(password, hash):
if pass_ctx.needs_update(hash):
new_hash = pass_ctx.encrypt(password)
replace_user_hash(user, new_hash)
do_successful_things()
else:
reject_user_login()
Username Validation
-------------------
This package provides a pluggable system for validating the format of user
names. If you would like to provide a custom validator,
.. code-block:: python
from pyramid.config import Configurator
from my_project.validators import NoBValidator
def main(global_config, **settings):
config = Configurator(settings=settings)
# registers the 'set_username_validator' directive
config.include('speak_friend')
# replace the default with our own validator
config.set_username_validator(NoBValidator)
Password Validation
-------------------
This package provides a pluggable system for validating the format of user
passwords. The package provides a default password validator with configurable
settings. This default validator can be replaced as well, allowing for maximal
flexibility. The validator may be found as an attribute of the current
registry: `config.registry.password_validator`. It is a callable, and calling
it will result either in `None` (if a password is valid) or a string
containing readable error messages indicating which validation rule has been
viiolated. Assuming that minimum length is set to 6, the following would
result:
.. code-block:: python
validator = config.registry.password_validator
password = 'secret'
result = validator(password)
result is None
# True
bad_password = 'short'
result = validator(bad_password)
print result
# 'Password must be longer than 6 characters.'
Default Validator
+++++++++++++++++
The default validation is provided by the
`speak_friend.passwords.PasswordValidator` class. This class has configuration
settings that can be set via the `.ini` file. The following settings are
supported:
**speak_friend.password.min_length**
Require a minimum length for passwords. *Default*: None
**speak_friend.password.max_length**
Require a maximum length for passwords. *Default*: None
**speak_friend.password.min_lower**
Require a minimum number of lower-case alphabetic characters. *Default*: 0
**speak_friend.password.min_upper**
Require a minimum number of upper-case alphabetic characters. *Default*: 0
**speak_friend.password.min_numeric**
Require a minimum number of numbers. *Default*: 0
**speak_friend.password.min_special**
Require a minimum number of *special* characters. *Special* characters are
defined by the Python regular expression `[\W|_]`. *Default*: 0
**speak_friend.password.disallowed**
If any characters should be forbidden from use in passwords, they may be set
with this setting. The forbidden characters should be written in a single
string all run together with no spaces (unless the space character itself
is forbidden). For example, a value for this settings of `)($%'"` would
result in the characters `)`, `(`, `$`, `%`, `'` and `"` being disallowed in
passwords.
Overriding the Default Validator
++++++++++++++++++++++++++++++++
The password validator is initialized by a call to the configuration directive
`set_password_validator`. By default, this directive is called without an
argument and sets the default password validator.
Should a specific implementation project require validation not provided by
the default validator, the directive may be called with a single positional
argument.
This argument must be a callable class. The `__call__` method must accept a
password as the sole argument and return `None` if the password passes
validation. If the password fails validation, the method must return a string
describing the reason for failure. This string will be used as a message to
the end-user and should be formatted appropriately.
The `__init__` method of the class will be passed `config.registry.settings`
as it's only positional argument. The validator need not use these settings,
but the `__init__` method must accept them.
For example, if the following class exists in `my_project.password`:
.. code-block:: python
class NoBValidator(object):
def __init__(self, settings):
pass
def __call__(self, password):
if 'B' not in password:
return None
else:
return 'Password may not contain the letter "B"'
This validator could be used in `my_project.__init__.py` like so:
.. code-block:: python
from pyramid.config import Configurator
from my_project.password import NoBValidator
def main(global_config, **settings):
config = Configurator(settings=settings)
# registers the 'set_password_validator' directive
# and sets the default validator
config.include('speak_friend')
# prevent config conflicts as we replace the default validator
config.commit()
# replace the default with our own validator
config.set_password_validator(NoBValidator)
After this, the validator will no longer accept any password containing the
uppercase letter 'B'.
Exception Handling
------------------
This package can integrate the pyramid_exclog and mailinglogger packages to automatically send email notifications when an exception is generated. To do so, include the following logging config:
.. code-block:: ini
:linenos:
# Begin logging configuration
[loggers]
keys = root, sfid, exc_logger
[handlers]
keys = console, filelog, exc_handler
[formatters]
keys = generic, exc_formatter
[logger_exc_logger]
level = ERROR
handlers = exc_handler
qualname = exc_logger
[handler_exc_handler]
class = mailinglogger.MailingLogger
args = ('info@example.org', ('ERROR_DESTINATION@example.org',), 'localhost', 'Error on example.org')
level = ERROR
formatter = exc_formatter
[formatter_exc_formatter]
format = %(asctime)s %(message)s
# End logging configuration
Overriding Assets
-----------------
There is a blank `speak_friend:static/css/custom.css` file that can be overridden by packages extending `speak_friend`.
This file is included in `base.pt`, so will be included on every page.
The following is a list of macros that can be overridden:
* `speak_friend:templates/macros/footer.pt`
* `speak_friend:templates/macros/quick_links.pt`
See http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/assets.html#overriding-assets-section .
Sessions
--------
By default, `speak_friend` uses `Beaker` for session management. This means that you need to configure it in your `paster.ini`:
http://docs.pylonsproject.org/projects/pyramid_beaker/en/latest/index.html#session-management
The recommended values are:
.. code-block:: ini
:linenos:
session.type = ext:database
session.url = postgresql+psycopg2://dbuser:dbpass@dbhost/dbname
session.lock_dir = %(here)s/sessions/lock
session.key = speak_friend
session.secret = SOME_SECRET
session.cookie_on_exception = true
session.secure = true
Cross-Site Request Forgery
--------------------------
`speak_friend` uses Pyramid's built-in support for mitigating CSRF attacks by storing a token in the user's session.
This token is included in forms, and the submitted value must match the current value in the session.
If not, the request will be rejected.