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 django_auth_fogbugz.backend.FogBugzBackend to AUTHENTICATION_BACKENDS. Additional functionality can be enabled if you add django_auth_fogbugz to INSTALLED_APPLICATIONS; see FogBugzProfile User Model Extension for FogBugzPy 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.

Basic Configuration

Here are a few examples of the most basic configurations. Please see the Settings section and the available Settings Template for a complete description of the available options. Also see Understanding FogBugz Authentication for how authentication with FogBugz works in general.

The most basic recommended configuration:

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:

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 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 AUTH_FOGBUGZ_SERVER_USES_LDAP to True, but you should be be aware of the Django User Restrictions 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 AUTH_FOGBUGZ_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 Django User Restrictions.

You can set AUTH_FOGBUGZ_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.

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 AUTH_FOGBUGZ_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 AUTH_FOGBUGZ_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 AUTH_FOGBUGZ_AUTO_CREATE_USERS and AUTH_FOGBUGZ_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.

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.

Django-Auth-FogBugz provides an alternative. You can use AUTH_FOGBUGZ_ENABLE_PROFILE and AUTH_FOGBUGZ_ENABLE_PROFILE_TOKEN to have the user’s login token stored in the FogBugzProfile User Model Extension for FogBugzPy. 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 FogBugzProfile User Model Extension for FogBugzPy for more details.

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 AUTH_FOGBUGZ_ENABLE_PROFILE to True.

class django_auth_fogbugz.models.FogBugzProfile
user
Type :OneToOneField
Description :django.contrib.auth.models.User this profile is for.
ixPerson
Type :PositiveIntegerField
Description :The FogBugz id for the user in the FogBugz API.
is_normal
Type :BooleanField
Description :It the FogBugz user is not a community, administrator, or virtual user, this will be set to True.
is_community
Type :BooleanField
Description :If the FogBugz user is a special community user, this will be set to True.
is_administrator
Type :BooleanField
Description :If the FogBugz user is a special administrator user, this will be set to True.
token
Type :CharField
Length :30
Default :''
Description :If AUTH_FOGBUGZ_ENABLE_PROFILE_TOKEN is set to TRUE, then this will contain the FogBugz Authentication token for this user. See Understanding FogBugz Authentication for more details.

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

The is_normal, is_community and is_administrator fields will be updated with each Django login.

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

Example of using the FogBugzProfile with FogBugzPy:

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 FogBugz Python API 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

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 application implicitly.

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

import logging

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

Settings

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 FogBugzProfile User Model Extension for FogBugzPy with AUTH_FOGBUGZ_ENABLE_PROFILE, then the 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.

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 AUTH_FOGBUGZ_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 Understanding FogBugz Authentication for more information.

AUTH_FOGBUGZ_ENABLE_PROFILE

Default: False

Set this to True to enable the FogBugzProfile User Model Extension for FogBugzPy. You must also add django_auth_fogbugz to your INSTALLED_APPS setting.

See FogBugz Python API and FogBugzProfile User Model Extension for FogBugzPy for more details.

AUTH_FOGBUGZ_ENABLE_PROFILE_TOKEN

Default: False

If set to True, and AUTH_FOGBUGZ_ENABLE_PROFILE is set to True then instead of clearing the FogBugz XML API token after authentication, it will be stored in the 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 FogBugz Python API and FogBugzProfile User Model Extension for FogBugzPy for more details.

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.

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.

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.

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 django_auth_fogbugz.backend.FogBugzBackend will lowercase the username internally.

If AUTH_FOGBUGZ_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 Understanding FogBugz Authentication for more information.

Settings Template

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

File: django_auth_fogbugz/django_auth_fogbugz_settings.py

# Settings for the django-auth-fogbugz authentication backend.
#
# This authentication backend for django, will authenticate against a
# FogBugz (http://www.fogcreek.com/fogbugz/) issue tracker. It uses the
# python interface (https://developers.fogbugz.com/default.asp?W199)
# to the FogBugz API (http://fogbugz.stackexchange.com/fogbugz-xml-api).
#
# It is HIGHLY recommended that you use an SSL connection to the FogBugz
# server for secure authentication.
#

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

# By default community users will not be authenticated. If you wish to include
# FogBugz community user logins, set this to True.
#
#AUTH_FOGBUGZ_ALLOW_COMMUNITY = True

# Have django-auth-fogbugz create the django user if it does not already
# exist, and the user authenticates.
#
#AUTH_FOGBUGZ_AUTO_CREATE_USERS = True

# If your FogBugz server is using the Active Directory or LDAP integration
# for authentication, then you need to set this to True in order to have
# authentication work properly.
# If you are also have AUTH_FOGBUGZ_AUTO_CREATE_USERS set to True, then the
# first time a user logs in to the django site, they must use their LDAP
# username, and not their e-mail address.
#
#AUTH_FOGBUGZ_SERVER_USES_LDAP = True

# FogBugz has a concept if a superuser, the 'administrator' flag on accounts.
# The following settings will map this information to the django account.
#
#AUTH_FOGBUGZ_MAP_ADMIN_AS_SUPER = True
#AUTH_FOGBUGZ_MAP_ADMIN_AS_STAFF = True

# There is an extension profile model which is included with this auth backend
# to help with integrating with the FogBugz API::
#
#     user.fogbugzprofile.token
#     user.fogbugzprofile.ixPerson
#     user.fogbugzprofile.is_normal
#     user.fogbugzprofile.is_community
#     user.fogbugzprofile.is_administrator
#
# You must also add 'django-auth-fogbugz' as django app in your
# INSTALLED_APPS when enabling this.
#
#AUTH_FOGBUGZ_ENABLE_PROFILE = True


# With the fogbugz profile extension enabled, there is the option to store
# the serurity login token for the FogBugz user. This token can be used
# instead of the username and password to log into the FogBugz server.
# The authentication token can be accessed via the profile::
#
#     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.
#
# Example::
#
#     import fogbugz
#     from django.conf import settings
#
#     fb = fogbugz.FogBugz(settings.AUTH_FOGBUGZ_SERVER,
#                          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 += "%s: %s\n" % (case.ixbug.string, 
#                                   case.stitle.string.encode('UTF-8'))
#
# You must also add 'django-auth-fogbugz' as django app in your
# INSTALLED_APPS and set AUTH_FOGBUGZ_ENABLE_PROFILE to true
# when enabling this.
#
#AUTH_FOGBUGZ_ENABLE_PROFILE_TOKEN = True
    
# Keep ModelBackend around for per-user permissions and maybe a local
# superuser.
#AUTHENTICATION_BACKENDS = (
#    'django_auth_fogbugz.backend.FogBugzBackend',
#    'django.contrib.auth.backends.ModelBackend',
#)

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

Copyright (c) 2012, Douglas Napoleone. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of Django nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS 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 OWNER OR CONTRIBUTORS 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.

Indices and tables