.. _djangoauthfogbugz:

Django-Auth-FogBugz
===============================================
This authentication backend enables a Django project to authenticate against
any FogBugz (http://www.fogcreek.com/fogbugz/) server.

Source code, and issues can be found on GitHub (https://github.com/dougn/django-auth-fogbugz).

To use it, add :py:class:`.django_auth_fogbugz.backend.FogBugzBackend` to
``AUTHENTICATION_BACKENDS``. Additional functionality can be enabled if you
add ``django_auth_fogbugz`` to ``INSTALLED_APPLICATIONS``;
see :ref:`fogbugzprofile` for more information.

This has been tested with Django 1.3, 1.4 and 1.5-alpha w/ custom user model,
under python 2.6 and 2.7.

.. WARNING:: It is strongly recommended that you use an SSL (https) connection
             to perform authentication against th FogBugz server for security.



.. _config:

Basic Configuration
--------------------------------------
Here are a few examples of the most basic configurations. Please see the
:ref:`settings` section and the available :ref:`example` for a complete
description of the available options.
Also see :ref:`understanding` for how authentication with FogBugz works in
general.

**The most basic recommended configuration:**

.. code:: python

    AUTH_FOGBUGZ_SERVER = "https://my_account.fogbugz.com/"

    AUTHENTICATION_BACKENDS = (
        'django_auth_fogbugz.backend.FogBugzBackend',
        'django.contrib.auth.backends.ModelBackend',
    )

**FogBugz with LDAP/Active Directory:**

.. code:: python

    AUTH_FOGBUGZ_SERVER = "https://my_account.fogbugz.com/"

    AUTH_FOGBUGZ_SERVER_USES_LDAP = True
    
    AUTHENTICATION_BACKENDS = (
        'django_auth_fogbugz.backend.FogBugzBackend',
        'django.contrib.auth.backends.ModelBackend',
    )


.. _understanding:

Understanding FogBugz Authentication
--------------------------------------
The FogBugz (http://www.fogcreek.com/fogbugz/) bug tracker uses the e-mail
address of it's users as the username, with case-insensitive matching. This
puts a restriction on the users, that no two can have the same e-mail address.
This is not strictly true. It is possible to have more than one user with
the same e-mail address, but this will cause the login to fail for both users.

Under normal use, this is hard to cause, but FogBugz also
allows for integration with LDAP and Active Directory, and the auto-creation
of users on login when either of these is enabled. This can cause such a
conflict.

When LDAP or AD is used either the LDAP/AD username or the e-mail address may
be used, and again the matching is case-insensitive. For AD users, the
'DOMAIN\\' prefix can be used. 

If your FogBugz server is configured for LDAP or Active Directory integration,
and you wish for your Django login to accept those usernames as well, then you
should set :ref:`SERVER_USES_LDAP` to ``True``, but you should be be aware of
the :ref:`djangouser` associated with that.

There are also different classifications of users, where each user can be one
of:

:normal: Basic user.
:administrator: Superuser with full admin access.
:community: Special user that does not use a license, and has limited
            access to Wiki's, Discussion Groups, and maybe filing some bugs.
            This is intended for customer support to allow customers to have
            login's.
:virtual: These are non-login e-mail alias accounts for sendding out e-mails.

Users can also be marked 'inactive' similar to Django.

**django-auth-fogbugz** will allow for login of normal and administrative users.
If :ref:`ALLOW_COMMUNITY` is set to ``True``, then those users will also be
allowed to log in. There is no way to allow for virtual users to be
authenticated. Similarly there is no way to tell the difference between an
authentication failure for a user that is marked 'inactive', a user
that does not exist on the FogBugz server, a virtual user, or
an incorrect password.

You can create the Django users by hand so that only those you want to have
access will be allowed to log in, but you will need to make sure to adhere to
the :ref:`djangouser`.

You can set :ref:`AUTO_CREATE_USERS` to ``True`` to have any user on the
FogBugz server able to log in, and a new Django user will be created on their
first login. Some restrictions may apply if LDAP/AD integration is used.


.. _djangouser:

Django User Restrictions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Due to the way that FogBugz allows for e-mail and optional LDAP or Active
Directory login names in a case-insensitive manner, and due to the new
Django 1.5 User model abstraction, there are restrictions on setting up your
Django users.

Because FogBugz uses the e-mail address as the login, this means that the
e-mail address on the User model must be unique in order to have authentication
to work. The e-mail address matching will be case insensitive.

If you have :ref:`AUTO_CREATE_USERS` set to ``True`` then the username will
be set to be the same as the e-mail address, but will be forced to be
lower-case.

Additionally if your FogBugz server has LDAP or Active Directory authentication
enabled, and you want to allow for logging in with the LDAP/AD username, then
you need to set :ref:`SERVER_USES_LDAP` to ``True``. This will add further
restrictions when hand creating Django users:

* The username must be the LDAP/AD username.
* The username must be without the 'DOMAIN\\' prefix for Active Directory.
* The username must be all lowercase.

The need to lowercase is because FogBugz does case insensitive matching on the
username, which could be either the e-mail address or the LDAP/AD username.
The new User Model abstraction in Django 1.5 does not allow for case insentive
matching. to work around this we store the username in lowercase, and lowercase
the login supplied username for matching against the Django model. FogBugz
will still authenticate agains the lower-cased username, and the User model
lookup will match exactly.

Furthermore if you are using :ref:`AUTO_CREATE_USERS` and :ref:`SERVER_USES_LDAP`
together, then the first time a new user logs into Django, they must log in with
their LDAP/AD username. This is due to a limitation of the FogBugz API which
can supply the users e-mail address, but can not supply their LDAP/AD username.
As such we can discover the e-mail address from the LDAP/AD username based
authentication, but not visa-versa. Newly created users will have the username
forced to lowercase.



.. _fogbugzpy:

FogBugz Python API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FogBugz has an XML API (http://fogbugz.stackexchange.com/fogbugz-xml-api)
for accessing the server, and a python wrapper
FogBugzPy (https://developers.fogbugz.com/default.asp?W199) which is
available on PyPi (http://pypi.python.org/pypi/fogbugz/). 

It is not recommended to store the password in plaintext for repeated
access. Instead, the FogBugz XML API allows for a 30 character session token
generated on a per-session basis (https://developers.fogbugz.com/default.asp?W198#toc_2).
You must explicitly 'logoff' in to clear the token. In this way, you can
generate and store the token on authentication with the username and password
for later FogBugz XML API usage.

Only FogBugz users that are 'administrator' users can perform FogBugz XML API
operations as another user, and back-date actions. Typically for Django
applications, this means storing a token for an administrative user, and using
that to perform operations.

:ref:`djangoauthfogbugz` provides an alternative.
You can use :ref:`ENABLE_PROFILE` and :ref:`ENABLE_PROFILE_TOKEN` to
have the user's login token stored in the :ref:`fogbugzprofile`. With each
new Django login, if a token already exists, it will be cleared, and the new
one will be assigned. This will allow you to perform FogBugz interactions as
the logged in Django user, instead of having to have a perminently stored
administrative user.

.. warning:: Enabling the profile token extension will allow any code with
             access to the user models to have a login authentication token
             for non-expired users. This could allow Django code to access
             the FogBugz server as those users.

See :ref:`fogbugzprofile` for more details.


.. _fogbugzprofile:

FogBugzProfile User Model Extension for FogBugzPy
--------------------------------------------------

This is a django model for storing additional information about the users
which are authenticated with **django-auth-fogbugz**. This uses a OneToOne
relation with the Django User model, and will work in parallel to other
User model extensions. This will also work with the new Django 1.5 custom
User model system.

To enable this you must add ``django_auth_fogbugz`` to your ``INSTALLED_APPS``
setting, as well as set :ref:`ENABLE_PROFILE` to ``True``.

.. py:class:: django_auth_fogbugz.models.FogBugzProfile

    .. py:attribute:: user
    
        :type: OneToOneField
        :description: :py:class:`.django.contrib.auth.models.User` this profile is for.

    .. py:attribute:: ixPerson

        :type: PositiveIntegerField
        :description: The FogBugz id for the user in the FogBugz API.
        
    .. py:attribute:: is_normal
    
        :type: BooleanField
        :description: It the FogBugz user is not a community, administrator, or virtual user, this will be set to ``True``.

    .. py:attribute:: is_community
        
        :type: BooleanField
        :description: If the FogBugz user is a special community user, this will be set to ``True``.
        
    .. py:attribute:: is_administrator
    
        :type: BooleanField
        :description: If the FogBugz user is a special administrator user, this will be set to ``True``.
        
    .. py:attribute:: token
   
        :type: CharField
        :length: 30
        :default: ``''``
        :description: If :ref:`ENABLE_PROFILE_TOKEN` is set to ``TRUE``, then
                      this will contain the FogBugz Authentication token for
                      this user. See :ref:`understanding` for more details.

You can access the members of the :py:class:`FogBugzProfile` directly from the
Django user model (e.g. ``user.fogbugzprofile.is_community``)

The :py:attr:`is_normal`, :py:attr:`is_community` and
:py:attr:`is_administrator` fields will be updated with each Django login.

If :ref:`ENABLE_PROFILE_TOKEN` is set to ``True``, then instead of clearing the
FogBugz XML API token after authentication, it will be stored in the
:class:`FogBugzProfile` accessible from the Django User instance as
``user.fogbugzprofile.token``.

Example of using the :py:class:`FogBugzProfile` with FogBugzPy:


.. code:: python

    import fogbugz
    from django.conf import settings
    from django.shortcuts import render
    from django.contrib.auth.decorators import login_required
    
    @login_required
    def my_view(request):
        fb = fogbugz.FogBugz(settings.AUTH_FOGBUGZ_SERVER,
                             request.user.fogbugzprofile.token)
        resp = fb.search(q='assignedTo:"me" status:"Active"',
                         cols="ixBug,sTitle",
                         max=10)
        top_ten = []
        for case in resp.cases.findAll('case'):
             top_ten.append("%s: %s\n" % (case.ixbug.string, 
                                          case.stitle.string.encode('UTF-8')))
                                          
        return render(request, "fogbugz/my_top_ten.html",
                      {'top_ten': top_ten})
                      

See :ref:`fogbugzpy` for links to the FogBugz XML API and FogBugzPy
documentaiton from Frog Creek.

.. note:: If you enable token storage, make sure your SESSION_COOKIE_AGE
          is less than or equal to the FogBugz expiration time (2 weeks,
          same as the django default) and that FogBugz Server
          Configuraition for Authentication logon is set to
          ``"Remember Me" Allowed``.

.. warning:: Enabling the profile token extension will allow any code with
             access to the user models to have a login authentication token
             for non-expired users. This could allow Django code to access
             the FogBugz server as those users.



.. _logging:

Logging
--------------------------------------

:py:class:`.django_auth_fogbugz.backend.FogBugzBackend` uses the standard
logging module to log debug, warning, and error messages to the logger named
``'django_auth_fogbugz'``. If you need debug messages to help with
configuration issues, you should add a handler to this logger.

.. Note:: This logger works with the `django-debug-toolbar <https://github.com/django-debug-toolbar/django-debug-toolbar>`_ application implicitly.

You can get explicit access to the logger with the following code:

.. code-block:: python

    import logging

    logger = logging.getLogger('django_auth_fogbugz')
    logger.addHandler(logging.StreamHandler())
    logger.setLevel(logging.DEBUG)

.. TODO: add example of configuring for the logging section in the django settings file.



.. _settings:

Settings
--------------------------------------


.. _ALLOW_COMMUNITY:

AUTH_FOGBUGZ_ALLOW_COMMUNITY
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Default:** ``False``

FogBugz has a concept of 'community' users which do not have full access to the
issue tracker. Instead these users are typically end customers using the site
for technical support. They can see some wiki's and/or discussion databases.

You normally would not want these users to have access to your fogbugz site,
but if you do, set this to ``True``.

If you enable the :ref:`fogbugzprofile` with :ref:`ENABLE_PROFILE`, then the
:py:class:`.django_auth_fogbugz.models.FogBugzProfile` instance for the user
will have the field ``is_community`` set to ``True`` for community users.
This is accessed via ``user.fogbugzprofile.is_community``.




.. _AUTO_CREATE_USERS:

AUTH_FOGBUGZ_AUTO_CREATE_USERS
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Default:** ``False`` 

If the user authenticates against the FogBugz server, and there is no django
user, then create one. By default the e-mail address will be used for the
``username``, as FogBugz uses the e-mail address as the user login.

The FogBugz ``sFullname`` will be set as the user model ``first_name``.

If you have :ref:`SERVER_USES_LDAP` enabled, then the user *MUST* login with
their LDAP or Adctive Directory username the first time, when auto-creating
a new user. This is because FogBugz allows for logging in with both the
e-mail address as well as the LDAP username, but the FogBugz API only allows
for retrieving the e-mail address. As such we can discover the e-mail address
from the FogBugz server, but not the LDAP username.

See :ref:`understanding` for more information.


.. _ENABLE_PROFILE:

AUTH_FOGBUGZ_ENABLE_PROFILE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Default:** ``False`` 

Set this to ``True`` to enable the :ref:`fogbugzprofile`. You must also
add ``django_auth_fogbugz`` to your ``INSTALLED_APPS`` setting.

See :ref:`fogbugzpy` and :ref:`fogbugzprofile` for more details.


.. _ENABLE_PROFILE_TOKEN:

AUTH_FOGBUGZ_ENABLE_PROFILE_TOKEN
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Default:** ``False``

If set to ``True``, and :ref:`ENABLE_PROFILE` is set to ``True`` then instead
of clearing the FogBugz XML API token after authentication, it will be stored
in the :class:`FogBugzProfile` accessible from the Django User instance as
``user.fogbugzprofile.token``.

.. note:: If you enable token storage, make sure your SESSION_COOKIE_AGE
          is less than or equal to the FogBugz expiration time (2 weeks,
          same as the django default) and that FogBugz Server
          Configuraition for Authentication logon is set to
          ``"Remember Me" Allowed``.

.. warning:: Enabling the profile token extension will allow any code with
             access to the user models to have a login authentication token
             for non-expired users. This could allow Django code to access
             the FogBugz server as those users.

See :ref:`fogbugzpy` and :ref:`fogbugzprofile` for more details.


.. _MAP_ADMIN_AS_STAFF:

AUTH_FOGBUGZ_MAP_ADMIN_AS_STAFF
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Default:** ``False`` 

By setting this to ``True``, FogBugz users whom are assigned as an
"administrator" user, will have their Django user ``is_staff`` field set
to ``True``. This property will sync with each Django login, so if the
FogBugz user is changed to be a "normal" user the ``is_staff`` field will
be set to ``False`` on their next Django login.


.. _MAP_ADMIN_AS_SUPER:

AUTH_FOGBUGZ_MAP_ADMIN_AS_SUPER
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Default:** ``False`` 

By setting this to ``True``, FogBugz users whom are assigned as an
"administrator" user, will have their Django user ``is_superuser`` field set
to ``True``. This property will sync with each Django login, so if the
FogBugz user is changed to be a "normal" user the ``is_superuser`` field will
be set to ``False`` on their next Django login.


.. _SERVER:

AUTH_FOGBUGZ_SERVER
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Required: Must be set to a URL, or will error.

**Default:** ``None``

Required root URL to the FogBugz server (e.g. ``https://my_project.fogbugz.com/``).

.. WARNING:: It is strongly recommended that you use an SSL (https) connection
             to perform authentication against th FogBugz server for security.


.. _SERVER_USES_LDAP:

AUTH_FOGBUGZ_SERVER_USES_LDAP
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Default:** ``False`` 

You *SHOULD* set this to ``True`` if your FogBugz server is configured for LDAP
or Active Directory authentication. When you 

When you hand create user accounts on the Django server, you must use the
LDAP/AD username as the username, and it *MUST* be all lower case. This is
because the FogBugz username matching is case insensitive, but the
Django User model managemnet is not, and the new Django 1.5 ability to
swap out the User model does not allow for case insensitive lookup.

The e-mail address must also be properly set as the FogBugz server allows
for using either the e-mail address or the LDAP/AD username; but it may be
mixed case.

The :py:class:`.django_auth_fogbugz.backend.FogBugzBackend` will lowercase
the username internally.

If :ref:`AUTO_CREATE_USERS` is also set to ``True`` then the first time a new
user logs into Django, they *MUST* use their LDAP/AD username, otherwise the
login will fail. After that they may use either their LDAP/AD username or
their e-mail address.

See :ref:`understanding` for more information.


.. _example:

Settings Template
--------------------------------------

You can copy the sample configuration file and include it in your main
django settings file.

**File:** :file:`django_auth_fogbugz/django_auth_fogbugz_settings.py`

.. literalinclude:: ../django_auth_fogbugz/django_auth_fogbugz_settings.py
   :language: python


Future Work
--------------------------------------

* FogBugz group permissions matching
* Custom hooks for permissions
* Custom hooks for base User model (first_name, last_name, custom User model)
* Custom profile hooking via signals (connect up phone number, gravitar, etc.)
* Multiple FogBugz Servers

License
--------------------------------------

.. include:: ../LICENSE


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

