Skip to content

rishiraj-rana/speak_friend

 
 

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 = ('[email protected]', ('[email protected]',), '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.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Python 95.8%
  • JavaScript 2.1%
  • CSS 1.9%
  • Mako 0.2%