First bits of documentation using Sphinx.

This commit is contained in:
Mikaël Ates 2011-10-13 23:22:52 +02:00
parent d28263864d
commit ee3656aeaa
102 changed files with 8597 additions and 0 deletions

153
doc/Makefile Normal file
View File

@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Authentic2.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Authentic2.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Authentic2"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Authentic2"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

295
doc/README.rst.bak Normal file
View File

@ -0,0 +1,295 @@
.. _README:
======================================
Authentic2 - Versatile Identity Server
======================================
Authentic2 is a versatile identity provider aiming to address a broad
range of needs, from simple to complex setups; it has support for many
protocols and can bridge between them.
Authentic2 is under the GNU AGPL version 3 licence.
It has support for SAMLv2 thanks to Lasso, a free (GNU GPL)
implementation of the Liberty Alliance specifications.
Features
========
Authentic can authenticate users against:
- an LDAP directory,
- a SAML 2.0 identity provider,
- an OpenID identity provider,
- with an X509 certificate.
Authentic can provide authentication to web applications using the following
protocols:
- OpenID,
- SAML 2.0,
- CAS 1.0 & CAS 2.0.
Authentic can proxy authentication between any two different protocols it
support.
Installation
============
Dependencies
------------
You must install the following packages to use Authentic
- Python Lasso binding 2.3.5:
From sources: http://lasso.entrouvert.org/download
Debian based distribution: apt-get install python-lasso
- Django 1.3:
From sources: http://www.djangoproject.com/download/1.3/tarball/
- Django-registration 0.8-alpha-1:
From sources: http://bitbucket.org/ubernostrum/django-registration/downloads
Debian based distribution: apt-get install python-django-registration
- Django-authopenid 0.9.6:
From sources: http://bitbucket.org/benoitc/django-authopenid/downloads
- Django-south 0.7.3:
From sources:: http://south.aeracode.org/docs/installation.html
- Django-profiles 0.2:
From sources:: http://pypi.python.org/pypi/django-profiles
You install all the django libraries quickly using pip::
pip install django django-profiles django-registration \
django-debug-toolbar django-authopenid south
or easy_install::
easy_install django django-profiles django-registration \
django-debug-toolbar django-authopenid south
Quick Start
-----------
Then launch the following commands::
python manage.py syncdb --migrate
python manage.py runserver
You should see the following output::
Validating models...
0 errors found
Django version 1.2, using settings 'authentic.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
You can access the running application on http://127.0.0.1:8000/
Specifying a different database
-------------------------------
This is done by modifying the DATABASES dictionary in your local_settings.py file
(create it in Authentic project directory); for example::
DATABASES['default'] = {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'authentic',
'USER': 'admindb',
'PASSWORD': 'foobar',
'HOST': 'db.example.com',
'PORT': '', # empty string means default value
}
You should refer to the Django documentation on databases settings at
http://docs.djangoproject.com/en/dev/ref/settings/#databases for all
the details.
How to upgrade to a new version of authentic ?
----------------------------------------------
Authentic store all its data in a relational database as specified in its
settings.py or local_settings.py file. So in order to upgrade to a new version
of authentic you have to update your database schema using the
migration command — you will need to have installed the dependency django-south,
see the beginning of this README file.::
python ./manage.py migrate
Then you will need to create new tables if there are.::
python ./manage.py syncdb
Using Authentic with an LDAP directory
======================================
Authentic use the module django_auth_ldap to synchronize the Django user tables
with an LDAP. For complex use case, we will refer you to the django_auth_ldap
documentation, see http://packages.python.org/django-auth-ldap/.
How to authenticate users against an LDAP server with anonymous binding ?
-------------------------------------------------------------------------
1. Install the django_auth_ldap module for Django::
pip install django_auth_ldap
2. Configure your local_settings.py file for authenticating against LDAP.
The next lines must be added::
AUTHENTICATION_BACKENDS += ( 'django_auth_ldap.backend.LDAPBackend', )
import ldap
from django_auth_ldap.config import LDAPSearch
# Here put the LDAP URL of your server
AUTH_LDAP_SERVER_URI = 'ldap://ldap.example.com'
# Let the bind DN and bind password blank for anonymous binding
AUTH_LDAP_BIND_DN = ""
AUTH_LDAP_BIND_PASSWORD = ""
# Lookup user under the branch o=base and by mathcing their uid against the
# received login name
AUTH_LDAP_USER_SEARCH = LDAPSearch("o=base",
ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
How to allow members of an LDAP group to manage Authentic ?
-----------------------------------------------------------
1. First you must know the objectClass of groups in your LDAP schema, this FAQ
will show you the configuration for two usual classes: groupOfNames and
groupOfUniqueNames.
2. Find the relevant groupname. We will say it is: cn=admin,o=mycompany
3. Add the following lines::
from django_auth_ldap.config import GroupOfNamesType
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("o=mycompany",
ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)")
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
"is_staff": "cn=admin,o=mycompany"
}
For an objectClass of groupOfUniqueNames you would change the string
GroupOfNamesType to GroupOfUniqueNamesType and grouOfNames to
groupOfUniqueNames. For more complex cases see the django_auth_ldap
documentation.
SAML 2.0
========
How to I authenticate against Authentic2 with a SAMLv2 service provider ?
-------------------------------------------------------------------------
1. Grab the SAML2 IdP metadata:
http[s]://your.domain.com/idp/saml2/metadata
2. And configure your service provider with it.
Go to the providers admin panel on:
http[s]://your.domain.com/admin/saml/libertyprovider/add/
There create a new provider using the service provider metadata and enable it
as a service provider, you can customize some behaviours like the preferred
assertion consumer or encryption for the NameID or the Assertion element.
CAS
===
How to use Authentic2 as a CAS 1.0 or CAS 2.0 identity provider ?
-----------------------------------------------------------------
1. Activate CAS IdP support in settings.py::
IDP_CAS = True
2. Then create the database table to hold CAS service tickets::
python authentic2/manage.py syncdb --migrate
3. Also configure authentic2 to authenticate against your LDAP directory (see
above) if your want your user attributes to be accessible from your service,
if it is not necessary you can use the normal relational database storage
for you users.
4. Finally configure your service to point to the CAS endpoint at:
http[s]://your.domain.com/idp/cas/
5. If needed configure your service to resolve authenticated user with your
LDAP directory (if user attributes are needed for your service)
PAM authentication
==================
This module is copied from https://bitbucket.org/wnielson/django-pam/ by Weston
Nielson and the pam ctype module by Chris Atlee http://atlee.ca/software/pam/.
Add 'authentic2.vendor.dpam.backends.PAMBackend' to your
``settings.py``::
AUTHENTICATION_BACKENDS = (
...
'authentic2.vendor.dpam.backends.PAMBackend',
...
)
Now you can login via the system-login credentials. If the user is
successfully authenticated but has never logged-in before, a new ``User``
object is created. By default this new ``User`` has both ``is_staff`` and
``is_superuser`` set to ``False``. You can change this behavior by adding
``PAM_IS_STAFF=True`` and ``PAM_IS_SUPERUSER`` in your ``settings.py`` file.
The default PAM service used is ``login`` but you can change it by setting the
``PAM_SERVICE`` variable in your ``settings.py`` file.
Attribute Management in Authentic2
==================================
See `attribute management <attribute_management.html>`_ page.
Roadmap
=======
- All (or nearly) settings will be configurable from the /admin panels
- Login page will remember user choices for authentication and authenticate
the user passively using hidden iframes
- After a logout no passive login will be done
- CAS IdP will allow to whitelist service URL and proxy granting ticket URLs,
and to refuse request from unkown URLs. It will also allow to use patterns
as URLs.
- Extended CAS 2.0, with SAML attribute inside the CAS 2.0 validated ticket.
- A virtual LDAP directory based on the OpenLDAP socket backend would remove
the need for a real LDAP directory to pass user attributes to CAS relying
parties.
- WS-Trust token service endpoint
- Email forwarder, so that relying parties never get the real user email.
- Support slo in the CAS logout endpoint
Copyright
---------
Authentic is copyrighted by Entr'ouvert and is licensed through the GNU General
Public Licence, version 2 or later. A copy of the whole license text is
available in the COPYING file.
The OpenID IdP originates in the project django_openid_provider by Roman
Barczy¿ski, which is under the Apache 2.0 licence. This imply that you must
distribute authentic2 under the AGPL3 licence when distributing this part of the
project which is the only AGPL licence version compatible with the Apache 2.0
licence.

BIN
doc/_build/doctrees/README.doctree vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
doc/_build/doctrees/auth_ldap.doctree vendored Normal file

Binary file not shown.

BIN
doc/_build/doctrees/auth_pam.doctree vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
doc/_build/doctrees/download.doctree vendored Normal file

Binary file not shown.

BIN
doc/_build/doctrees/environment.pickle vendored Normal file

Binary file not shown.

BIN
doc/_build/doctrees/features.doctree vendored Normal file

Binary file not shown.

BIN
doc/_build/doctrees/index.doctree vendored Normal file

Binary file not shown.

BIN
doc/_build/doctrees/installation.doctree vendored Normal file

Binary file not shown.

4
doc/_build/html/.buildinfo vendored Normal file
View File

@ -0,0 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 9a63a4e352955e4e1c10b0bedfb3135a
tags: fbb0d17656682115ca4d033fb2f83ba1

421
doc/_build/html/README.html vendored Normal file
View File

@ -0,0 +1,421 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Authentic2 - Versatile Identity Server &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="prev" title="Welcome to Authentic2s documentation!" href="index.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="index.html" title="Welcome to Authentic2s documentation!"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="authentic2-versatile-identity-server">
<span id="readme"></span><h1>Authentic2 - Versatile Identity Server<a class="headerlink" href="#authentic2-versatile-identity-server" title="Permalink to this headline"></a></h1>
<p>Authentic2 is a versatile identity provider aiming to address a broad
range of needs, from simple to complex setups; it has support for many
protocols and can bridge between them.</p>
<p>Authentic2 is under the GNU AGPL version 3 licence.</p>
<p>It has support for SAMLv2 thanks to Lasso, a free (GNU GPL)
implementation of the Liberty Alliance specifications.</p>
<div class="section" id="features">
<h2>Features<a class="headerlink" href="#features" title="Permalink to this headline"></a></h2>
<p>Authentic can authenticate users against:
- an LDAP directory,
- a SAML 2.0 identity provider,
- an OpenID identity provider,
- with an X509 certificate.</p>
<p>Authentic can provide authentication to web applications using the following
protocols:
- OpenID,
- SAML 2.0,
- CAS 1.0 &amp; CAS 2.0.</p>
<p>Authentic can proxy authentication between any two different protocols it
support.</p>
</div>
<div class="section" id="installation">
<h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline"></a></h2>
<div class="section" id="dependencies">
<h3>Dependencies<a class="headerlink" href="#dependencies" title="Permalink to this headline"></a></h3>
<p>You must install the following packages to use Authentic</p>
<ul>
<li><p class="first">Python Lasso binding 2.3.5:</p>
<blockquote>
<div><p>From sources: <a class="reference external" href="http://lasso.entrouvert.org/download">http://lasso.entrouvert.org/download</a>
Debian based distribution: apt-get install python-lasso</p>
</div></blockquote>
</li>
<li><p class="first">Django 1.3:</p>
<blockquote>
<div><p>From sources: <a class="reference external" href="http://www.djangoproject.com/download/1.3/tarball/">http://www.djangoproject.com/download/1.3/tarball/</a></p>
</div></blockquote>
</li>
<li><p class="first">Django-registration 0.8-alpha-1:</p>
<blockquote>
<div><p>From sources: <a class="reference external" href="http://bitbucket.org/ubernostrum/django-registration/downloads">http://bitbucket.org/ubernostrum/django-registration/downloads</a>
Debian based distribution: apt-get install python-django-registration</p>
</div></blockquote>
</li>
<li><p class="first">Django-authopenid 0.9.6:</p>
<blockquote>
<div><p>From sources: <a class="reference external" href="http://bitbucket.org/benoitc/django-authopenid/downloads">http://bitbucket.org/benoitc/django-authopenid/downloads</a></p>
</div></blockquote>
</li>
<li><p class="first">Django-south 0.7.3:</p>
<blockquote>
<div><p>From sources:: <a class="reference external" href="http://south.aeracode.org/docs/installation.html">http://south.aeracode.org/docs/installation.html</a></p>
</div></blockquote>
</li>
<li><p class="first">Django-profiles 0.2:</p>
<blockquote>
<div><p>From sources:: <a class="reference external" href="http://pypi.python.org/pypi/django-profiles">http://pypi.python.org/pypi/django-profiles</a></p>
</div></blockquote>
</li>
</ul>
<p>You install all the django libraries quickly using pip:</p>
<div class="highlight-python"><pre>pip install django django-profiles django-registration \
django-debug-toolbar django-authopenid south</pre>
</div>
<p>or easy_install:</p>
<div class="highlight-python"><pre>easy_install django django-profiles django-registration \
django-debug-toolbar django-authopenid south</pre>
</div>
</div>
<div class="section" id="quick-start">
<h3>Quick Start<a class="headerlink" href="#quick-start" title="Permalink to this headline"></a></h3>
<p>Then launch the following commands:</p>
<div class="highlight-python"><pre>python manage.py syncdb --migrate
python manage.py runserver</pre>
</div>
<p>You should see the following output:</p>
<div class="highlight-python"><pre>Validating models...
0 errors found
Django version 1.2, using settings 'authentic.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
You can access the running application on http://127.0.0.1:8000/</pre>
</div>
</div>
<div class="section" id="specifying-a-different-database">
<h3>Specifying a different database<a class="headerlink" href="#specifying-a-different-database" title="Permalink to this headline"></a></h3>
<p>This is done by modifying the DATABASES dictionary in your local_settings.py file
(create it in Authentic project directory); for example:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">DATABASES</span><span class="p">[</span><span class="s">&#39;default&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">&#39;ENGINE&#39;</span><span class="p">:</span> <span class="s">&#39;django.db.backends.postgresql&#39;</span><span class="p">,</span>
<span class="s">&#39;NAME&#39;</span><span class="p">:</span> <span class="s">&#39;authentic&#39;</span><span class="p">,</span>
<span class="s">&#39;USER&#39;</span><span class="p">:</span> <span class="s">&#39;admindb&#39;</span><span class="p">,</span>
<span class="s">&#39;PASSWORD&#39;</span><span class="p">:</span> <span class="s">&#39;foobar&#39;</span><span class="p">,</span>
<span class="s">&#39;HOST&#39;</span><span class="p">:</span> <span class="s">&#39;db.example.com&#39;</span><span class="p">,</span>
<span class="s">&#39;PORT&#39;</span><span class="p">:</span> <span class="s">&#39;&#39;</span><span class="p">,</span> <span class="c"># empty string means default value</span>
<span class="p">}</span>
</pre></div>
</div>
<p>You should refer to the Django documentation on databases settings at
<a class="reference external" href="http://docs.djangoproject.com/en/dev/ref/settings/#databases">http://docs.djangoproject.com/en/dev/ref/settings/#databases</a> for all
the details.</p>
</div>
<div class="section" id="how-to-upgrade-to-a-new-version-of-authentic">
<h3>How to upgrade to a new version of authentic ?<a class="headerlink" href="#how-to-upgrade-to-a-new-version-of-authentic" title="Permalink to this headline"></a></h3>
<p>Authentic store all its data in a relational database as specified in its
settings.py or local_settings.py file. So in order to upgrade to a new version
of authentic you have to update your database schema using the
migration command — you will need to have installed the dependency django-south,
see the beginning of this README file.:</p>
<div class="highlight-python"><pre>python ./manage.py migrate</pre>
</div>
<p>Then you will need to create new tables if there are.:</p>
<div class="highlight-python"><pre>python ./manage.py syncdb</pre>
</div>
</div>
</div>
<div class="section" id="using-authentic-with-an-ldap-directory">
<h2>Using Authentic with an LDAP directory<a class="headerlink" href="#using-authentic-with-an-ldap-directory" title="Permalink to this headline"></a></h2>
<p>Authentic use the module django_auth_ldap to synchronize the Django user tables
with an LDAP. For complex use case, we will refer you to the django_auth_ldap
documentation, see <a class="reference external" href="http://packages.python.org/django-auth-ldap/">http://packages.python.org/django-auth-ldap/</a>.</p>
<div class="section" id="how-to-authenticate-users-against-an-ldap-server-with-anonymous-binding">
<h3>How to authenticate users against an LDAP server with anonymous binding ?<a class="headerlink" href="#how-to-authenticate-users-against-an-ldap-server-with-anonymous-binding" title="Permalink to this headline"></a></h3>
<ol class="arabic">
<li><p class="first">Install the django_auth_ldap module for Django:</p>
<div class="highlight-python"><pre>pip install django_auth_ldap</pre>
</div>
</li>
<li><p class="first">Configure your local_settings.py file for authenticating against LDAP.</p>
</li>
</ol>
<p>The next lines must be added:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">AUTHENTICATION_BACKENDS</span> <span class="o">+=</span> <span class="p">(</span> <span class="s">&#39;django_auth_ldap.backend.LDAPBackend&#39;</span><span class="p">,</span> <span class="p">)</span>
<span class="kn">import</span> <span class="nn">ldap</span>
<span class="kn">from</span> <span class="nn">django_auth_ldap.config</span> <span class="kn">import</span> <span class="n">LDAPSearch</span>
<span class="c"># Here put the LDAP URL of your server</span>
<span class="n">AUTH_LDAP_SERVER_URI</span> <span class="o">=</span> <span class="s">&#39;ldap://ldap.example.com&#39;</span>
<span class="c"># Let the bind DN and bind password blank for anonymous binding</span>
<span class="n">AUTH_LDAP_BIND_DN</span> <span class="o">=</span> <span class="s">&quot;&quot;</span>
<span class="n">AUTH_LDAP_BIND_PASSWORD</span> <span class="o">=</span> <span class="s">&quot;&quot;</span>
<span class="c"># Lookup user under the branch o=base and by mathcing their uid against the</span>
<span class="c"># received login name</span>
<span class="n">AUTH_LDAP_USER_SEARCH</span> <span class="o">=</span> <span class="n">LDAPSearch</span><span class="p">(</span><span class="s">&quot;o=base&quot;</span><span class="p">,</span>
<span class="n">ldap</span><span class="o">.</span><span class="n">SCOPE_SUBTREE</span><span class="p">,</span> <span class="s">&quot;(uid=</span><span class="si">%(user)s</span><span class="s">)&quot;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="how-to-allow-members-of-an-ldap-group-to-manage-authentic">
<h3>How to allow members of an LDAP group to manage Authentic ?<a class="headerlink" href="#how-to-allow-members-of-an-ldap-group-to-manage-authentic" title="Permalink to this headline"></a></h3>
<ol class="arabic">
<li><p class="first">First you must know the objectClass of groups in your LDAP schema, this FAQ
will show you the configuration for two usual classes: groupOfNames and
groupOfUniqueNames.</p>
</li>
<li><p class="first">Find the relevant groupname. We will say it is: cn=admin,o=mycompany</p>
</li>
<li><p class="first">Add the following lines:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">django_auth_ldap.config</span> <span class="kn">import</span> <span class="n">GroupOfNamesType</span>
<span class="n">AUTH_LDAP_GROUP_TYPE</span> <span class="o">=</span> <span class="n">GroupOfNamesType</span><span class="p">()</span>
<span class="n">AUTH_LDAP_GROUP_SEARCH</span> <span class="o">=</span> <span class="n">LDAPSearch</span><span class="p">(</span><span class="s">&quot;o=mycompany&quot;</span><span class="p">,</span>
<span class="n">ldap</span><span class="o">.</span><span class="n">SCOPE_SUBTREE</span><span class="p">,</span> <span class="s">&quot;(objectClass=groupOfNames)&quot;</span><span class="p">)</span>
<span class="n">AUTH_LDAP_USER_FLAGS_BY_GROUP</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">&quot;is_staff&quot;</span><span class="p">:</span> <span class="s">&quot;cn=admin,o=mycompany&quot;</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
</ol>
<p>For an objectClass of groupOfUniqueNames you would change the string
GroupOfNamesType to GroupOfUniqueNamesType and grouOfNames to
groupOfUniqueNames. For more complex cases see the django_auth_ldap
documentation.</p>
</div>
</div>
<div class="section" id="saml-2-0">
<h2>SAML 2.0<a class="headerlink" href="#saml-2-0" title="Permalink to this headline"></a></h2>
<div class="section" id="how-to-i-authenticate-against-authentic2-with-a-samlv2-service-provider">
<h3>How to I authenticate against Authentic2 with a SAMLv2 service provider ?<a class="headerlink" href="#how-to-i-authenticate-against-authentic2-with-a-samlv2-service-provider" title="Permalink to this headline"></a></h3>
<ol class="arabic">
<li><p class="first">Grab the SAML2 IdP metadata:</p>
<blockquote>
<div><p>http[s]://your.domain.com/idp/saml2/metadata</p>
</div></blockquote>
</li>
<li><p class="first">And configure your service provider with it.</p>
</li>
</ol>
<p>Go to the providers admin panel on:</p>
<blockquote>
<div>http[s]://your.domain.com/admin/saml/libertyprovider/add/</div></blockquote>
<p>There create a new provider using the service provider metadata and enable it
as a service provider, you can customize some behaviours like the preferred
assertion consumer or encryption for the NameID or the Assertion element.</p>
</div>
</div>
<div class="section" id="cas">
<h2>CAS<a class="headerlink" href="#cas" title="Permalink to this headline"></a></h2>
<div class="section" id="how-to-use-authentic2-as-a-cas-1-0-or-cas-2-0-identity-provider">
<h3>How to use Authentic2 as a CAS 1.0 or CAS 2.0 identity provider ?<a class="headerlink" href="#how-to-use-authentic2-as-a-cas-1-0-or-cas-2-0-identity-provider" title="Permalink to this headline"></a></h3>
<ol class="arabic">
<li><p class="first">Activate CAS IdP support in settings.py:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">IDP_CAS</span> <span class="o">=</span> <span class="bp">True</span>
</pre></div>
</div>
</li>
<li><p class="first">Then create the database table to hold CAS service tickets:</p>
<div class="highlight-python"><pre>python authentic2/manage.py syncdb --migrate</pre>
</div>
</li>
<li><p class="first">Also configure authentic2 to authenticate against your LDAP directory (see
above) if your want your user attributes to be accessible from your service,
if it is not necessary you can use the normal relational database storage
for you users.</p>
</li>
<li><p class="first">Finally configure your service to point to the CAS endpoint at:</p>
<blockquote>
<div><p>http[s]://your.domain.com/idp/cas/</p>
</div></blockquote>
</li>
<li><p class="first">If needed configure your service to resolve authenticated user with your
LDAP directory (if user attributes are needed for your service)</p>
</li>
</ol>
</div>
</div>
<div class="section" id="pam-authentication">
<h2>PAM authentication<a class="headerlink" href="#pam-authentication" title="Permalink to this headline"></a></h2>
<p>This module is copied from <a class="reference external" href="https://bitbucket.org/wnielson/django-pam/">https://bitbucket.org/wnielson/django-pam/</a> by Weston
Nielson and the pam ctype module by Chris Atlee <a class="reference external" href="http://atlee.ca/software/pam/">http://atlee.ca/software/pam/</a>.</p>
<p>Add &#8216;authentic2.vendor.dpam.backends.PAMBackend&#8217; to your
<tt class="docutils literal"><span class="pre">settings.py</span></tt>:</p>
<div class="highlight-python"><pre>AUTHENTICATION_BACKENDS = (
...
'authentic2.vendor.dpam.backends.PAMBackend',
...
)</pre>
</div>
<p>Now you can login via the system-login credentials. If the user is
successfully authenticated but has never logged-in before, a new <tt class="docutils literal"><span class="pre">User</span></tt>
object is created. By default this new <tt class="docutils literal"><span class="pre">User</span></tt> has both <tt class="docutils literal"><span class="pre">is_staff</span></tt> and
<tt class="docutils literal"><span class="pre">is_superuser</span></tt> set to <tt class="docutils literal"><span class="pre">False</span></tt>. You can change this behavior by adding
<tt class="docutils literal"><span class="pre">PAM_IS_STAFF=True</span></tt> and <tt class="docutils literal"><span class="pre">PAM_IS_SUPERUSER</span></tt> in your <tt class="docutils literal"><span class="pre">settings.py</span></tt> file.</p>
<p>The default PAM service used is <tt class="docutils literal"><span class="pre">login</span></tt> but you can change it by setting the
<tt class="docutils literal"><span class="pre">PAM_SERVICE</span></tt> variable in your <tt class="docutils literal"><span class="pre">settings.py</span></tt> file.</p>
</div>
<div class="section" id="attribute-management-in-authentic2">
<h2>Attribute Management in Authentic2<a class="headerlink" href="#attribute-management-in-authentic2" title="Permalink to this headline"></a></h2>
<p>See <a class="reference external" href="attribute_management.html">attribute management</a> page.</p>
</div>
<div class="section" id="roadmap">
<h2>Roadmap<a class="headerlink" href="#roadmap" title="Permalink to this headline"></a></h2>
<blockquote>
<div><ul class="simple">
<li>All (or nearly) settings will be configurable from the /admin panels</li>
<li>Login page will remember user choices for authentication and authenticate
the user passively using hidden iframes</li>
<li>After a logout no passive login will be done</li>
<li>CAS IdP will allow to whitelist service URL and proxy granting ticket URLs,
and to refuse request from unkown URLs. It will also allow to use patterns
as URLs.</li>
<li>Extended CAS 2.0, with SAML attribute inside the CAS 2.0 validated ticket.</li>
<li>A virtual LDAP directory based on the OpenLDAP socket backend would remove
the need for a real LDAP directory to pass user attributes to CAS relying
parties.</li>
<li>WS-Trust token service endpoint</li>
<li>Email forwarder, so that relying parties never get the real user email.</li>
<li>Support slo in the CAS logout endpoint</li>
</ul>
</div></blockquote>
<div class="section" id="copyright">
<h3>Copyright<a class="headerlink" href="#copyright" title="Permalink to this headline"></a></h3>
<p>Authentic is copyrighted by Entr&#8217;ouvert and is licensed through the GNU General
Public Licence, version 2 or later. A copy of the whole license text is
available in the COPYING file.</p>
<p>The OpenID IdP originates in the project django_openid_provider by Roman
Barczy¿ski, which is under the Apache 2.0 licence. This imply that you must
distribute authentic2 under the AGPL3 licence when distributing this part of the
project which is the only AGPL licence version compatible with the Apache 2.0
licence.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Authentic2 - Versatile Identity Server</a><ul>
<li><a class="reference internal" href="#features">Features</a></li>
<li><a class="reference internal" href="#installation">Installation</a><ul>
<li><a class="reference internal" href="#dependencies">Dependencies</a></li>
<li><a class="reference internal" href="#quick-start">Quick Start</a></li>
<li><a class="reference internal" href="#specifying-a-different-database">Specifying a different database</a></li>
<li><a class="reference internal" href="#how-to-upgrade-to-a-new-version-of-authentic">How to upgrade to a new version of authentic ?</a></li>
</ul>
</li>
<li><a class="reference internal" href="#using-authentic-with-an-ldap-directory">Using Authentic with an LDAP directory</a><ul>
<li><a class="reference internal" href="#how-to-authenticate-users-against-an-ldap-server-with-anonymous-binding">How to authenticate users against an LDAP server with anonymous binding ?</a></li>
<li><a class="reference internal" href="#how-to-allow-members-of-an-ldap-group-to-manage-authentic">How to allow members of an LDAP group to manage Authentic ?</a></li>
</ul>
</li>
<li><a class="reference internal" href="#saml-2-0">SAML 2.0</a><ul>
<li><a class="reference internal" href="#how-to-i-authenticate-against-authentic2-with-a-samlv2-service-provider">How to I authenticate against Authentic2 with a SAMLv2 service provider ?</a></li>
</ul>
</li>
<li><a class="reference internal" href="#cas">CAS</a><ul>
<li><a class="reference internal" href="#how-to-use-authentic2-as-a-cas-1-0-or-cas-2-0-identity-provider">How to use Authentic2 as a CAS 1.0 or CAS 2.0 identity provider ?</a></li>
</ul>
</li>
<li><a class="reference internal" href="#pam-authentication">PAM authentication</a></li>
<li><a class="reference internal" href="#attribute-management-in-authentic2">Attribute Management in Authentic2</a></li>
<li><a class="reference internal" href="#roadmap">Roadmap</a><ul>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="index.html"
title="previous chapter">Welcome to Authentic2&#8217;s documentation!</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/README.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="index.html" title="Welcome to Authentic2s documentation!"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
doc/_build/html/_images/ldapsource.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
doc/_build/html/_images/policy_pull.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

295
doc/_build/html/_sources/README.txt vendored Normal file
View File

@ -0,0 +1,295 @@
.. _README:
======================================
Authentic2 - Versatile Identity Server
======================================
Authentic2 is a versatile identity provider aiming to address a broad
range of needs, from simple to complex setups; it has support for many
protocols and can bridge between them.
Authentic2 is under the GNU AGPL version 3 licence.
It has support for SAMLv2 thanks to Lasso, a free (GNU GPL)
implementation of the Liberty Alliance specifications.
Features
========
Authentic can authenticate users against:
- an LDAP directory,
- a SAML 2.0 identity provider,
- an OpenID identity provider,
- with an X509 certificate.
Authentic can provide authentication to web applications using the following
protocols:
- OpenID,
- SAML 2.0,
- CAS 1.0 & CAS 2.0.
Authentic can proxy authentication between any two different protocols it
support.
Installation
============
Dependencies
------------
You must install the following packages to use Authentic
- Python Lasso binding 2.3.5:
From sources: http://lasso.entrouvert.org/download
Debian based distribution: apt-get install python-lasso
- Django 1.3:
From sources: http://www.djangoproject.com/download/1.3/tarball/
- Django-registration 0.8-alpha-1:
From sources: http://bitbucket.org/ubernostrum/django-registration/downloads
Debian based distribution: apt-get install python-django-registration
- Django-authopenid 0.9.6:
From sources: http://bitbucket.org/benoitc/django-authopenid/downloads
- Django-south 0.7.3:
From sources:: http://south.aeracode.org/docs/installation.html
- Django-profiles 0.2:
From sources:: http://pypi.python.org/pypi/django-profiles
You install all the django libraries quickly using pip::
pip install django django-profiles django-registration \
django-debug-toolbar django-authopenid south
or easy_install::
easy_install django django-profiles django-registration \
django-debug-toolbar django-authopenid south
Quick Start
-----------
Then launch the following commands::
python manage.py syncdb --migrate
python manage.py runserver
You should see the following output::
Validating models...
0 errors found
Django version 1.2, using settings 'authentic.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
You can access the running application on http://127.0.0.1:8000/
Specifying a different database
-------------------------------
This is done by modifying the DATABASES dictionary in your local_settings.py file
(create it in Authentic project directory); for example::
DATABASES['default'] = {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'authentic',
'USER': 'admindb',
'PASSWORD': 'foobar',
'HOST': 'db.example.com',
'PORT': '', # empty string means default value
}
You should refer to the Django documentation on databases settings at
http://docs.djangoproject.com/en/dev/ref/settings/#databases for all
the details.
How to upgrade to a new version of authentic ?
----------------------------------------------
Authentic store all its data in a relational database as specified in its
settings.py or local_settings.py file. So in order to upgrade to a new version
of authentic you have to update your database schema using the
migration command — you will need to have installed the dependency django-south,
see the beginning of this README file.::
python ./manage.py migrate
Then you will need to create new tables if there are.::
python ./manage.py syncdb
Using Authentic with an LDAP directory
======================================
Authentic use the module django_auth_ldap to synchronize the Django user tables
with an LDAP. For complex use case, we will refer you to the django_auth_ldap
documentation, see http://packages.python.org/django-auth-ldap/.
How to authenticate users against an LDAP server with anonymous binding ?
-------------------------------------------------------------------------
1. Install the django_auth_ldap module for Django::
pip install django_auth_ldap
2. Configure your local_settings.py file for authenticating against LDAP.
The next lines must be added::
AUTHENTICATION_BACKENDS += ( 'django_auth_ldap.backend.LDAPBackend', )
import ldap
from django_auth_ldap.config import LDAPSearch
# Here put the LDAP URL of your server
AUTH_LDAP_SERVER_URI = 'ldap://ldap.example.com'
# Let the bind DN and bind password blank for anonymous binding
AUTH_LDAP_BIND_DN = ""
AUTH_LDAP_BIND_PASSWORD = ""
# Lookup user under the branch o=base and by mathcing their uid against the
# received login name
AUTH_LDAP_USER_SEARCH = LDAPSearch("o=base",
ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
How to allow members of an LDAP group to manage Authentic ?
-----------------------------------------------------------
1. First you must know the objectClass of groups in your LDAP schema, this FAQ
will show you the configuration for two usual classes: groupOfNames and
groupOfUniqueNames.
2. Find the relevant groupname. We will say it is: cn=admin,o=mycompany
3. Add the following lines::
from django_auth_ldap.config import GroupOfNamesType
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("o=mycompany",
ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)")
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
"is_staff": "cn=admin,o=mycompany"
}
For an objectClass of groupOfUniqueNames you would change the string
GroupOfNamesType to GroupOfUniqueNamesType and grouOfNames to
groupOfUniqueNames. For more complex cases see the django_auth_ldap
documentation.
SAML 2.0
========
How to I authenticate against Authentic2 with a SAMLv2 service provider ?
-------------------------------------------------------------------------
1. Grab the SAML2 IdP metadata:
http[s]://your.domain.com/idp/saml2/metadata
2. And configure your service provider with it.
Go to the providers admin panel on:
http[s]://your.domain.com/admin/saml/libertyprovider/add/
There create a new provider using the service provider metadata and enable it
as a service provider, you can customize some behaviours like the preferred
assertion consumer or encryption for the NameID or the Assertion element.
CAS
===
How to use Authentic2 as a CAS 1.0 or CAS 2.0 identity provider ?
-----------------------------------------------------------------
1. Activate CAS IdP support in settings.py::
IDP_CAS = True
2. Then create the database table to hold CAS service tickets::
python authentic2/manage.py syncdb --migrate
3. Also configure authentic2 to authenticate against your LDAP directory (see
above) if your want your user attributes to be accessible from your service,
if it is not necessary you can use the normal relational database storage
for you users.
4. Finally configure your service to point to the CAS endpoint at:
http[s]://your.domain.com/idp/cas/
5. If needed configure your service to resolve authenticated user with your
LDAP directory (if user attributes are needed for your service)
PAM authentication
==================
This module is copied from https://bitbucket.org/wnielson/django-pam/ by Weston
Nielson and the pam ctype module by Chris Atlee http://atlee.ca/software/pam/.
Add 'authentic2.vendor.dpam.backends.PAMBackend' to your
``settings.py``::
AUTHENTICATION_BACKENDS = (
...
'authentic2.vendor.dpam.backends.PAMBackend',
...
)
Now you can login via the system-login credentials. If the user is
successfully authenticated but has never logged-in before, a new ``User``
object is created. By default this new ``User`` has both ``is_staff`` and
``is_superuser`` set to ``False``. You can change this behavior by adding
``PAM_IS_STAFF=True`` and ``PAM_IS_SUPERUSER`` in your ``settings.py`` file.
The default PAM service used is ``login`` but you can change it by setting the
``PAM_SERVICE`` variable in your ``settings.py`` file.
Attribute Management in Authentic2
==================================
See `attribute management <attribute_management.html>`_ page.
Roadmap
=======
- All (or nearly) settings will be configurable from the /admin panels
- Login page will remember user choices for authentication and authenticate
the user passively using hidden iframes
- After a logout no passive login will be done
- CAS IdP will allow to whitelist service URL and proxy granting ticket URLs,
and to refuse request from unkown URLs. It will also allow to use patterns
as URLs.
- Extended CAS 2.0, with SAML attribute inside the CAS 2.0 validated ticket.
- A virtual LDAP directory based on the OpenLDAP socket backend would remove
the need for a real LDAP directory to pass user attributes to CAS relying
parties.
- WS-Trust token service endpoint
- Email forwarder, so that relying parties never get the real user email.
- Support slo in the CAS logout endpoint
Copyright
---------
Authentic is copyrighted by Entr'ouvert and is licensed through the GNU General
Public Licence, version 2 or later. A copy of the whole license text is
available in the COPYING file.
The OpenID IdP originates in the project django_openid_provider by Roman
Barczy¿ski, which is under the Apache 2.0 licence. This imply that you must
distribute authentic2 under the AGPL3 licence when distributing this part of the
project which is the only AGPL licence version compatible with the Apache 2.0
licence.

View File

@ -0,0 +1,653 @@
.. _attribute_management:
==================================
Attribute Management in Authentic2
==================================
Summary
=======
Attribute management currently allows to configure attribute policies
associated with SAML2 service providers to define attributes that are
pushed in SAML2 successful authentication response delivered by Authentic2.
User attributes can be taken from LDAP directories, the user Django
profile or taken from the user Django session if Authentic2 is also configured
as a SAML2 service provider.
Indeed, when Authentic2 acts also as a SAML2 service provider,
attributes contained in the SAML2 assertion received from third IdP are put in
the user session.
Attributes can thus be proxyfied during SSO with Authentic2
configured as a SAML2 proxy.
The namespace of attributes received from another SAML2 IdP or pushed in the
assertion given in to service providers can be configured per attribute or per
service provider.
By default, the namespace and format of attributes in assertion is conformant
to the SAMLV2.0 X500/LDAP Attribute profile::
<saml:Attribute
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:2.5.4.42" FriendlyName="givenName">
<saml:AttributeValue xsi:type="xs:string"
x500:Encoding="LDAP">Mikaël</saml:AttributeValue>
</saml:Attribute>
But the http://schemas.xmlsoap.org/ws/2005/05/identity/claims from the ISI
profile can also be used, for instance::
<saml:Attribute
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
FriendlyName="First Name">
<saml:AttributeValue>Mikaël</saml:AttributeValue>
</saml:Attribute>
Configuration
=============
Configure sources of attributes
-------------------------------
The source of attributes for authentic2 are of two kinds. The LDAP sources and
the user django profile.
Declare the Django profile source
_________________________________
Add an attribute source named USER_PROFILE with namespace 'Default'.
Then, it is necessary that users create their profile.
Add an LDAP Source
__________________
For LDAP sources, objects of type 'LDAPSource' must be created.
**Even if the authentication is based on LDAP authentification, thus that a
server is configured in settings.py, it is
necessary to create a corresponding 'LDAPSource' to use it as a source of
attribute.**
1. Go to http[s]://your.domain.com/admin/attribute_aggregator/ldapsource/add/
2. Fill form fields
Only the field Name, Server, User, Password, Base and Port are used for now.
**The namespace of LDAP source must be kept to 'Default', since the system
namespace is based on LDAP.**
.. image:: pictures/ldapsource.png
:width: 800 px
3. Save
.. image:: pictures/ldapsource_saved.png
:width: 800 px
Manage user distinguished names in LDAP directories
___________________________________________________
To find the user in a LDAP directory, authentic2 must know its distinguished
name (DN). If this LDAP has been used when the user has authenticated,
Authentic2 learn the user DN. Nothing has to be done from this point of view.
However, if it is expected that user attributes be taken in a directory that
is not used by the user for authentication, it is necessary to manually
indicate to Authentic2 what is the user DN in the directory. For this, a
user alias in source is created for the user:
1. Go to http[s]://your.domain.com/admin/attribute_aggregator/useraliasinsource/add/
2. Fill form fields
.. image:: pictures/alias_in_source.png
:width: 800 px
3. Save
.. image:: pictures/alias_in_source_saved.png
:width: 800 px
Configure attributes pushed to SAML2 service providers in SSO response
----------------------------------------------------------------------
Reminder:
- The default name format in SAML2 assertions is URI
- The default namespace called 'Default' is LDAP
In summary:
1. Create attribute items indicating an attribute name, a source, the name format expected and the namespace expected for the attribute name and friendly name if any.
2. Create a named list of attribute items.
3. Create an attribute policy and associate the previous list or associate the previous list to a existing attribute policy.
4. Associate the policy to a service provider.
Create attribute items
______________________
1. Go to http[s]://your.domain.com/admin/idp/attributeitem/add/
2. Fill form fields
.. image:: pictures/attribute_item.png
:width: 800 px
3. Save
.. image:: pictures/attribute_item_saved.png
:width: 800 px
Create a named list of attribute items
______________________________________
1. Go to http[s]://your.domain.com/admin/idp/attributelist/add/
2. Name the list and add items to list
.. image:: pictures/attribute_list.png
:width: 800 px
3. Save
.. image:: pictures/attribute_list_saved.png
:width: 800 px
Create or modify an attribute policy
____________________________________
1. Go to http[s]://your.domain.com/admin/idp/attributepolicy/add/
2. Add list to the policy
.. image:: pictures/policy_pull.png
:width: 800 px
3. Save
.. image:: pictures/policy_pull_saved.png
:width: 800 px
Associate the policy to a service provider
__________________________________________
1. Go to http[s]://your.domain.com/admin/saml/libertyprovider/1/
2. Add policy to the service provider
.. image:: pictures/sp_policy_pull.png
:width: 800 px
3. Save
.. image:: pictures/sp_policy_pull_saved.png
:width: 800 px
4. The display name of the policy has changed
.. image:: pictures/policy_pull_renamed.png
:width: 800 px
Handle attributes provided by other Identity providers, proxy attributes
------------------------------------------------------------------------
Link to configure first Authentic as a sp to have attributes in session
Add a source if mapping set to true
Modifying supported namespaces and attribute name mappings
==========================================================
TBD
Explanation (Draft)
===================
Attribute aggegrator module
---------------------------
The core attribute management is based on the attribute aggregator module.
Intro
_____
Attribute aggregator provides a main Model class called UserAttributeProfile,
functions to load attributes and extract attributes.
The mapping between attribute namespaces is built-in and depends on a unique
file (mapping.py).
A main schema is defined and is based on LDAP/X500 for naming. The support
of http://schemas.xmlsoap.org/ws/2005/05/identity/claims is partly complete.
Source of attributes are connected with attribute loading functions using
signals.
FAQ
___
Why not use the Django User profile?
The django user profile needs to define attributes as class attributes and
then support form filling or mapping with LDAP.
That is useful and may be used, especially because the profile can be used as
a source of attribute to load in the attribute_aggregator profile.
The attribute_aggregator profile allow to load multivalued attributes from any
source supported (LDAP, Django profile and attributes in Django session for
now) from any namespace defined in mapping.py (LDAP/X500 and claims for now).
The profile can be loaded giving a source or a list of attribute, or can be
from any known source, or with a dictionnary.
Attributes can be extracted with many functions in any namespace supported.
Quick explanation
_________________
The schema is defined in mapping.py and is made of definitions like this::
"sn": {
"oid": "2.5.4.4",
"display_name": _("sn surname"),
"alias": ['surname'],
"profile_field_name": 'last_name',
"type": "http://www.w3.org/2001/XMLSchema#string",
"namespaces": {
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims": {
"identifiers":
[
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
],
"friendly_names":
[
"Last Name",
],
}
}
},
The profile store all the data in a text field taht contains a cPickle list of
instances of the class AttributeData.
The profile is attached to a user and then can be created or loaded with::
profile = load_or_create_user_profile(user=user)
User may be None to create a temporary profile for an anonymous user. But
that need a DB cleaning function not implemented.
The model *UserAttributeProfile*
________________________________
The model 'UserAttributeProfile' can be attached to a user and then persist
(as a Model).
When the profile is loaded, all data stored are removed expect if the
the data has an expiration date later.
The profile provide several methods to store and extract attributes.
All the methods to add attributes are based on a main one accepting a
dictionnary of attribute is parameters 'load_by_dic()'. The other methods
('load_listed_attributes()', 'load_greedy()') send a signal with a list of
attributes (listed_attributes_call) or not (any_attributes_call) to grab a
dictionnary. The list is given with the definition name, oid or friendly name
of the attribute in the system namespace.
Into the dictionnary, attributes are given with their name, oid or friendly
name in the default namespace or with their name in a namepsace. An expiration
date can also be given (ISO8601 format), if none, attribute will be deleted at
next profile loading. The dictionnary format is as follows::
attributes = dict()
data_from_source = list()
a1 = dict()
a1['oid'] = definition_name
Or
a1['definition'] = definition_name
definition may be the definition name like 'gn'
or an alias like 'givenName'
Or
a1['name'] = attribute_name_in_ns
a1['namespace'] = ns_name
a1['expiration_date'] = date
a1['values'] = list_of_values
data_from_source.append(a1)
...
data_from_source.append(a2)
attributes[source_name] = data_from_source
Getters are defined to extract data from a profile. Only AttributeData
instances are extracted that assume that any attribute namespace can be used.
* get_data_of_definition(definition)
Return a list of AttributeData instances corresponding to the definition
given.
* get_freshest_data_of_definition(definition)
Return the freshest AttributeData instance. If multiple with no or same exp
date, random. Should use the creation date soon.
* get_data_of_source
Return a list of AttributeData instances corresponding to the source given.
* get_data_of_source_by_name
Idem but source name is given, not a Source instance.
* get_data_of_definition_and_source
Return a list of AttributeData instances corresponding to the definition and
source given.
* get_data_of_definition_and_source_by_name
Idem but source name is given, not a Source instance.
SAML2 attribute representation in assertions
--------------------------------------------
SAML2 attribute profile (saml-profiles-2.0-os - Section 8) defines two kind of
attribute element syntax in the attribute statement of assertions, also
called *name format*:
- BASIC::
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
- URI::
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
*URI should be used when attributes have "universally" known unique names
like OID.*
Example::
<saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
Name="FirstName">
<saml:AttributeValue xsi:type="xs:string">By-Tor</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:2.5.4.42" FriendlyName="givenName">
<saml:AttributeValue xsi:type="xs:string"
x500:Encoding="LDAP">Steven</saml:AttributeValue>
</saml:Attribute>
BASIC
_____
Two <Attribute> elements refer to the same SAML attribute if and only if the
values of their Name XML attributes are equal in the sense of Section 3.3.6 of
[Schema2].
No additional XML attributes are defined for use with the <Attribute> element.
The schema type of the contents of the <AttributeValue> element MUST be drawn
from one of the types defined in Section 3.3 of [Schema2]. The xsi:type
attribute MUST be present and be given the appropriate value.
X.500/LDAP Attribute Profile (URI)
__________________________________
**Extracted from the SAML2 core specifications**
Two <Attribute> elements refer to the same SAML attribute if and only if their
Name XML attribute values are equal in the sense of [RFC3061]. The
FriendlyName attribute plays no role in the comparison.
Directory attribute type definitions for use in native X.500 directories
specify the syntax of the attribute using ASN.1 [ASN.1]. For use in LDAP,
directory attribute definitions additionally include an LDAP syntax which
specifies how attribute or assertion values conforming to the syntax are to be
represented when transferred in the LDAP protocol (known as an LDAP-specific
encoding). The LDAP-specific encoding commonly produces Unicode characters in
UTF-8 form. This SAML attribute profile specifies the form of SAML attribute
values only for those directory attributes which have LDAP syntaxes. Future
extensions to this profile may define attribute value formats for directory
attributes whose syntaxes specify other encodings.
To represent the encoding rules in use for a particular attribute value, the
<AttributeValue> element MUST contain an XML attribute named Encoding defined
in the XML namespace urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500.
For any directory attribute with a syntax whose LDAP-specific encoding
exclusively produces UTF-8 character strings as values, the SAML attribute
value is encoded as simply the UTF-8 string itself, as the content of the
<AttributeValue> element, with no additional whitespace.
In such cases, the xsi:type XML attribute MUST be set to xs:string.
The profile-specific Encoding XML attribute is provided, with a value of LDAP.
The AttributeData instances have a field expiration_data. It the profile
exists, obsolete data are removed at loading.
When authentic 2 deals with attributes and needs mapping?
---------------------------------------------------------
Authentic2 behaves as an attribute provider:
* At the SSO login
* When an attribute request is received
Authentic requests (e.g. by soap) are not yet supported.
When Authentic2 behaves as an attribute provider at SSO login
_____________________________________________________________
At a SSO request, just before responding to the service provider, the saml2
idp module sends the signal 'add_attributes_to_response' giving the SP entity
ID.
The signal is connected to the function 'provide_attributes_at_sso()' in
charge of providing the attributes at the SSO for this SP.
**Attributes sources are of two kinds. The first ones are the sources that can
be requested by the IdP with a syncrhonous binding without user intercations.
These sources are called pull sources. They are for now limited to LDAP
sources. The other ones are sources are asyncrhonous bindings, usually
requiring user interactions. These sources are called push sources. They are
now limited to the attributes provided at SSO requests when the IdP acts as a
SAML2 SP. There attributes are put/found in the Django session.**
Each source in the system is declared with an instance of the AttributeSource
model. We'll see later that to forward attributes of push sources it is not
necessary that a source is declared in some circumstances.
To manage these sources an attribute policy is attached to services providers.
Then the service provider model must be extended with a attribute
attributes_at_sso_policy. The service provider must send the signal
'add_attributes_to_response'.
The implementation is actually done for SAML2 providers.
**In such a policy attributes from pull and push sources are treated
differently.**
**For pull sources, a list of attributes is indicated. Either an attribute is
searched in all the pull sources and whatever attribute value found is
returned. Or each attribute is indicated with a source. With each attribute is
indicated the output format and namespace.**
**The policy may also indicate that all the attributes in the Django session
must be forwarded. Then, no AttributeSource instance is required. All the
attributes are then forwarded without treating input namespace considerations.
When an AttributeSource instance is found, the input namespace of this source
is considered. An option can then be set to tell that the output format and
namespace must be taken. A list of attribute can also be given.
This list can be use to filter attributes to forward without or without taking
care of the source. The output namespace and format can also be trated per
attribute.**
If the namespace is default, the attribute names will be taken from the
system namespace. In BASIC the name will be the definition name. In URI, the
Name will be the OID in urn format and the friendly name will be the
definition name. If a namespace is given, the first identifier of this
attribute is taken as Name in BASIC. In URI, the same and the first friendly
name is taken.
::
class LibertyServiceProvider(models.Model):
...
attribute_policy = models.ForeignKey(AttributePolicy,
verbose_name=_("Attribute policy"), null=True, blank=True)
class AttributePolicy(models.Model):
# List of attributes to provide from pull sources at SSO Login.
# If an attribute is indicate without a source, from any source.
# The output format and namespace is given by each attribute.
attribute_list_for_sso_from_pull_sources = \
models.ForeignKey(LibertyAttributeMap,
related_name = "attributes of pull sources",
blank = True, null = True)
# Set to true for proxying attributes from pull sources at SSO Login.
# Attributes are in session.
# All attributes are forwarded as is except if the parameter
# 'attribute_list_for_sso_from_push_sources' is initialized
forward_attributes_from_pull_sources = models.BooleanField(default=False)
# Map attributes in session
# forward_attributes_in_session must be true
# At False, all attributes are forwarded as is
# At true, look for the namespace of the source for input, If not found,
# system namespace. Look for the options attribute_name_format and
# output_namespace of the attribute policy for output.
map_attributes_from_pull_sources = models.BooleanField(default=False)
# ATTRIBUTE_VALUE_FORMATS[0] =>
# (lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC, 'SAMLv2 BASIC')
output_name_format = models.CharField(max_length = 100,
choices = ATTRIBUTE_VALUE_FORMATS,
default = ATTRIBUTE_VALUE_FORMATS[0])
#ATTRIBUTES_NS[0] => ('Default', 'Default')
output_namespace = models.CharField(max_length = 100,
choices = ATTRIBUTES_NS, default = ATTRIBUTES_NS[0])
# Filter attributes pushed from source.
source_filter_for_sso_from_push_sources = \
models.ManyToManyField(AttributeSource,
related_name = "attributes of pull sources",
blank = True, null = True)
# List of attributes to filter from pull sources at SSO Login.
attribute_filter_for_sso_from_push_sources = \
models.ForeignKey(LibertyAttributeMap,
related_name = "attributes of pull sources",
blank = True, null = True)
# The sources of attributes of the previous list are considered.
# May be used conjointly with 'source_filter_for_sso_from_push_sources'
filter_source_of_filtered_attributes = models.BooleanField(default=False)
# To map the attributes of forwarded attributes with the defaut output
# format and namespace, use 'map_attributes_from_pull_sources'
# Use the following option to use the output format and namespace
# indicated for each attribute.
map_attributes_of_filtered_attributes = models.BooleanField(default=False)
# Set to true to take in account missing required attributes
send_error_and_no_attrs_if_missing_required_attrs = \
models.BooleanField(default=False)
class Meta:
verbose_name = _('attribute options policy')
verbose_name_plural = _('attribute options policies')
class AttributeList(models.Model):
name = models.CharField(max_length = 40, unique = True)
attributes = models.ManyToManyField(AttributeItem,
related_name = "attributes of the list",
blank = True, null = True)
class AttributeItem(models.Model):
attribute_name = models.CharField(max_length = 100, choices = ATTRIBUTES,
default = ATTRIBUTES[0])
# ATTRIBUTE_VALUE_FORMATS[0] =>
# (lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC, 'SAMLv2 BASIC')
output_attribute_name_format = models.CharField(max_length = 100,
choices = ATTRIBUTE_VALUE_FORMATS,
default = ATTRIBUTE_VALUE_FORMATS[0])
#ATTRIBUTES_NS[0] => ('Default', 'Default')
output_namespace = models.CharField(max_length = 100,
choices = ATTRIBUTES_NS, default = ATTRIBUTES_NS[0])
required = models.BooleanField(default=False)
source = models.ForeignKey(AttributeSource, blank = True, null = True)
A list of attributes can also be taken from the service provider metadata and
added to 'attribute_list_for_sso_from_pull_sources'. The namespace may be
extracted from the metadata. This namespace is then used to look for the
corresponding definition and then to provide the attribute in the right
namespace. Read attributes from metadata is not yet supported.
For the attributes of pull sources, once the list of attributes is defined,
They are loaded in the user profile.
As explained before the attribute_aggregator loading function send signals to
grab dictionnary of attributes. Up to know, only the ldap loading function are
connected to these signals. The namespace of LDAP sources is assumed to be
the same as the system namespace. There is here then no mapping needed. Other
kind of sources than LDAP can be defined in attribute aggregator.
To grab attributes from a LDAP the user dn in the LDAP or at least a local
identifier in the LDAP is required. For this purpose, each user has alias
associated with LDAP source. These aliases must their DN in the LDAP. When
the authentication LDAP backend will be taken in account, the dn will be taken
direclty from the user Model instance.
Each LDAP sources are declared with the binding parameters. The LDAP namespace
is always 'Default'.
If an attribute to load is not found and is required the answer should report
an error (Not yet implemented).
Attributes in response can also be provided with other means than from an LDAP
source. Attributes can be put in the user Django session and then loaded in
the profile. An option of the service provier indicate if attributes in the
session must be provided to the service provider.
To have the attribute loaded from the session, they must be provided in the
session as follows:
request.session['attributes'][source_name] = list()
The source_name must be the name of an existing instance of an
'AttributeSource'. Such an instance contains a field namespace indicating the
namespace of attributes.
This is currently implemented only for the SAML2 service provider module of
authentic2. Authsaml2, the SP module, parse the assertion and put the
attributes in the session.
::
if not 'multisource_attributes' in request.session:
request.session['attributes'] = dict{}
request.session['multisource_attributes'] \
[login.assertion.issuer.content] = attributes
Then, Authentic2 can be used as a SAML2 proxy forwarding attributes in
assertion, eventually doing a namespace mapping. For this, the option
forward attributes in sesion must be set (by default False).

61
doc/_build/html/_sources/auth_ldap.txt vendored Normal file
View File

@ -0,0 +1,61 @@
.. _auth_ldap:
==============================================
Authentication with an existing LDAP directory
==============================================
Authentic use the module django_auth_ldap to synchronize the Django user tables
with an LDAP. For complex use case, we will refer you to the django_auth_ldap
documentation, see http://packages.python.org/django-auth-ldap/.
How to authenticate users against an LDAP server with anonymous binding ?
-------------------------------------------------------------------------
1. Install the django_auth_ldap module for Django::
pip install django_auth_ldap
2. Configure your local_settings.py file for authenticating against LDAP.
The next lines must be added::
AUTHENTICATION_BACKENDS += ( 'django_auth_ldap.backend.LDAPBackend', )
import ldap
from django_auth_ldap.config import LDAPSearch
# Here put the LDAP URL of your server
AUTH_LDAP_SERVER_URI = 'ldap://ldap.example.com'
# Let the bind DN and bind password blank for anonymous binding
AUTH_LDAP_BIND_DN = ""
AUTH_LDAP_BIND_PASSWORD = ""
# Lookup user under the branch o=base and by mathcing their uid against the
# received login name
AUTH_LDAP_USER_SEARCH = LDAPSearch("o=base",
ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
How to allow members of an LDAP group to manage Authentic ?
-----------------------------------------------------------
1. First you must know the objectClass of groups in your LDAP schema, this FAQ
will show you the configuration for two usual classes: groupOfNames and
groupOfUniqueNames.
2. Find the relevant groupname. We will say it is: cn=admin,o=mycompany
3. Add the following lines::
from django_auth_ldap.config import GroupOfNamesType
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("o=mycompany",
ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)")
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
"is_staff": "cn=admin,o=mycompany"
}
For an objectClass of groupOfUniqueNames you would change the string
GroupOfNamesType to GroupOfUniqueNamesType and grouOfNames to
groupOfUniqueNames. For more complex cases see the django_auth_ldap
documentation.

26
doc/_build/html/_sources/auth_pam.txt vendored Normal file
View File

@ -0,0 +1,26 @@
.. _auth_pam:
=====================================
Authentication on Authentic2 with PAM
=====================================
This module is copied from https://bitbucket.org/wnielson/django-pam/ by Weston
Nielson and the pam ctype module by Chris Atlee http://atlee.ca/software/pam/.
Add 'authentic2.vendor.dpam.backends.PAMBackend' to your
``settings.py``::
AUTHENTICATION_BACKENDS = (
...
'authentic2.vendor.dpam.backends.PAMBackend',
...
)
Now you can login via the system-login credentials. If the user is
successfully authenticated but has never logged-in before, a new ``User``
object is created. By default this new ``User`` has both ``is_staff`` and
``is_superuser`` set to ``False``. You can change this behavior by adding
``PAM_IS_STAFF=True`` and ``PAM_IS_SUPERUSER`` in your ``settings.py`` file.
The default PAM service used is ``login`` but you can change it by setting the
``PAM_SERVICE`` variable in your ``settings.py`` file.

View File

@ -0,0 +1,5 @@
.. _config_cas_idp:
====================================
Configure Authentic2 as a CAS client
====================================

View File

@ -0,0 +1,28 @@
.. _config_cas_sp:
====================================
Configure Authentic2 as a CAS server
====================================
How to use Authentic2 as a CAS 1.0 or CAS 2.0 identity provider ?
-----------------------------------------------------------------
1. Activate CAS IdP support in settings.py::
IDP_CAS = True
2. Then create the database table to hold CAS service tickets::
python authentic2/manage.py syncdb --migrate
3. Also configure authentic2 to authenticate against your LDAP directory (see
above) if your want your user attributes to be accessible from your service,
if it is not necessary you can use the normal relational database storage
for you users.
4. Finally configure your service to point to the CAS endpoint at:
http[s]://your.domain.com/idp/cas/
5. If needed configure your service to resolve authenticated user with your
LDAP directory (if user attributes are needed for your service)

View File

@ -0,0 +1,12 @@
.. _config_saml2_idp:
=================================================================
Configure Authentic2 as a SAML2 service provider or a SAML2 proxy
=================================================================
1. Create instance of SP settings
2. Declare IdP
3. Get authsaml2 md

View File

@ -0,0 +1,23 @@
.. _config_saml2_sp:
====================================
Configure SAML 2.0 service providers
====================================
How to I authenticate against Authentic2 with a SAMLv2 service provider ?
-------------------------------------------------------------------------
1. Grab the SAML2 IdP metadata:
http[s]://your.domain.com/idp/saml2/metadata
2. And configure your service provider with it.
3. Go to the providers admin panel on:
http[s]://your.domain.com/admin/saml/libertyprovider/add/
There create a new provider using the service provider metadata and enable it
as a service provider, you can customize some behaviours like the preferred
assertion consumer or encryption for the NameID or the Assertion element.

13
doc/_build/html/_sources/download.txt vendored Normal file
View File

@ -0,0 +1,13 @@
.. _download:
========
Download
========
1. Pypi: http://pypi.python.org/pypi/authentic2/1.9.0
2. Git repository: http://repos.entrouvert.org/authentic.git
3. `Browse source <http://dev.entrouvert.org/projects/authentic/repository>`_

23
doc/_build/html/_sources/features.txt vendored Normal file
View File

@ -0,0 +1,23 @@
.. _features:
========
Features
========
Authentic can authenticate users against:
- an LDAP directory,
- a SAML 2.0 identity provider,
- an OpenID identity provider,
- with an X509 certificate.
Authentic can provide authentication to web applications using the following
protocols:
- OpenID,
- SAML 2.0,
- CAS 1.0 & CAS 2.0.
Authentic can proxy authentication between any two different protocols it
support.

71
doc/_build/html/_sources/index.txt vendored Normal file
View File

@ -0,0 +1,71 @@
.. Authentic2 documentation master file, created by
sphinx-quickstart on Thu Oct 13 09:53:03 2011.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
==========================
Authentic2's documentation
==========================
Authentic2 is a versatile identity provider addressing a broad
range of needs, from simple to advanced setups, around web authentication,
attribute sharing, namespace mapping and authorization management.
Authentic2 supports many protocols and standards, including SAML2, CAS, OpenID,
LDAP, X509, OATH, and can bridge between them.
Authentic2 is under the GNU AGPL version 3 licence.
It has support for SAMLv2 thanks to `Lasso <http://lasso.entrouvert.org>`_,
a free (GNU GPL) implementation of the Liberty Alliance and OASIS
specifications of SAML2, ID-FF1.2 and ID-WSF2.
- `Authentic2 project site <http://dev.entrouvert.org/projects/authentic>`_
- `Authentic2 roadmap <http://dev.entrouvert.org/projects/authentic/roadmap>`_
Documentation content
=====================
.. toctree::
:maxdepth: 2
features
download
installation
auth_ldap
auth_pam
config_saml2_sp
config_saml2_idp
config_cas_sp
config_cas_idp
attribute_management
Copyright
=========
Authentic is copyrighted by Entr'ouvert and is licensed through the GNU General
Public Licence, version 2 or later. A copy of the whole license text is
available in the COPYING file.
The OpenID IdP originates in the project django_openid_provider by Roman
Barczy¿ski, which is under the Apache 2.0 licence. This imply that you must
distribute authentic2 under the AGPL3 licence when distributing this part of the
project which is the only AGPL licence version compatible with the Apache 2.0
licence.
.. Indices and tables
.. ==================
.. * :ref:`genindex`
.. * :ref:`modindex`
.. * :ref:`search`

View File

@ -0,0 +1,100 @@
.. _installation:
============
Installation
============
Dependencies
------------
You must install the following packages to use Authentic
- Python Lasso binding 2.3.5:
From sources: http://lasso.entrouvert.org/download
Debian based distribution: apt-get install python-lasso
- Django 1.3:
From sources: http://www.djangoproject.com/download/1.3/tarball/
- Django-registration 0.8-alpha-1:
From sources: http://bitbucket.org/ubernostrum/django-registration/downloads
Debian based distribution: apt-get install python-django-registration
- Django-authopenid 0.9.6:
From sources: http://bitbucket.org/benoitc/django-authopenid/downloads
- Django-south 0.7.3:
From sources:: http://south.aeracode.org/docs/installation.html
- Django-profiles 0.2:
From sources:: http://pypi.python.org/pypi/django-profiles
You install all the django libraries quickly using pip::
pip install django django-profiles django-registration \
django-debug-toolbar django-authopenid south
or easy_install::
easy_install django django-profiles django-registration \
django-debug-toolbar django-authopenid south
Quick Start
-----------
Then launch the following commands::
python manage.py syncdb --migrate
python manage.py runserver
You should see the following output::
Validating models...
0 errors found
Django version 1.2, using settings 'authentic.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
You can access the running application on http://127.0.0.1:8000/
Specifying a different database
-------------------------------
This is done by modifying the DATABASES dictionary in your local_settings.py file
(create it in Authentic project directory); for example::
DATABASES['default'] = {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'authentic',
'USER': 'admindb',
'PASSWORD': 'foobar',
'HOST': 'db.example.com',
'PORT': '', # empty string means default value
}
You should refer to the Django documentation on databases settings at
http://docs.djangoproject.com/en/dev/ref/settings/#databases for all
the details.
How to upgrade to a new version of authentic ?
----------------------------------------------
Authentic store all its data in a relational database as specified in its
settings.py or local_settings.py file. So in order to upgrade to a new version
of authentic you have to update your database schema using the
migration command — you will need to have installed the dependency django-south,
see the beginning of this README file.::
python ./manage.py migrate
Then you will need to create new tables if there are.::
python ./manage.py syncdb

BIN
doc/_build/html/_static/ajax-loader.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

540
doc/_build/html/_static/basic.css vendored Normal file
View File

@ -0,0 +1,540 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar input[type="text"] {
width: 170px;
}
div.sphinxsidebar input[type="submit"] {
width: 30px;
}
img {
border: 0;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- general body styles --------------------------------------------------- */
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.field-list ul {
padding-left: 1em;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #ffe;
width: 40%;
float: right;
}
p.sidebar-title {
font-weight: bold;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.field-list td, table.field-list th {
border: 0 !important;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, .highlighted {
background-color: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.refcount {
color: #060;
}
.optional {
font-size: 1.3em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
tt.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
tt.descclassname {
background-color: transparent;
}
tt.xref, a tt {
background-color: transparent;
font-weight: bold;
}
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
doc/_build/html/_static/comment.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

256
doc/_build/html/_static/default.css vendored Normal file
View File

@ -0,0 +1,256 @@
/*
* default.css_t
* ~~~~~~~~~~~~~
*
* Sphinx stylesheet -- default theme.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: sans-serif;
font-size: 100%;
background-color: #11303d;
color: #000;
margin: 0;
padding: 0;
}
div.document {
background-color: #1c4e63;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 230px;
}
div.body {
background-color: #ffffff;
color: #000000;
padding: 0 20px 30px 20px;
}
div.footer {
color: #ffffff;
width: 100%;
padding: 9px 0 9px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #ffffff;
text-decoration: underline;
}
div.related {
background-color: #133f52;
line-height: 30px;
color: #ffffff;
}
div.related a {
color: #ffffff;
}
div.sphinxsidebar {
}
div.sphinxsidebar h3 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.4em;
font-weight: normal;
margin: 0;
padding: 0;
}
div.sphinxsidebar h3 a {
color: #ffffff;
}
div.sphinxsidebar h4 {
font-family: 'Trebuchet MS', sans-serif;
color: #ffffff;
font-size: 1.3em;
font-weight: normal;
margin: 5px 0 0 0;
padding: 0;
}
div.sphinxsidebar p {
color: #ffffff;
}
div.sphinxsidebar p.topless {
margin: 5px 10px 10px 10px;
}
div.sphinxsidebar ul {
margin: 10px;
padding: 0;
color: #ffffff;
}
div.sphinxsidebar a {
color: #98dbcc;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
/* -- hyperlink styles ------------------------------------------------------ */
a {
color: #355f7c;
text-decoration: none;
}
a:visited {
color: #355f7c;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* -- body styles ----------------------------------------------------------- */
div.body h1,
div.body h2,
div.body h3,
div.body h4,
div.body h5,
div.body h6 {
font-family: 'Trebuchet MS', sans-serif;
background-color: #f2f2f2;
font-weight: normal;
color: #20435c;
border-bottom: 1px solid #ccc;
margin: 20px -20px 10px -20px;
padding: 3px 0 3px 10px;
}
div.body h1 { margin-top: 0; font-size: 200%; }
div.body h2 { font-size: 160%; }
div.body h3 { font-size: 140%; }
div.body h4 { font-size: 120%; }
div.body h5 { font-size: 110%; }
div.body h6 { font-size: 100%; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.body p, div.body dd, div.body li {
text-align: justify;
line-height: 130%;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.admonition p {
margin-bottom: 5px;
}
div.admonition pre {
margin-bottom: 5px;
}
div.admonition ul, div.admonition ol {
margin-bottom: 5px;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 5px;
background-color: #eeffcc;
color: #333333;
line-height: 120%;
border: 1px solid #ac9;
border-left: none;
border-right: none;
}
tt {
background-color: #ecf0f3;
padding: 0 1px 0 1px;
font-size: 0.95em;
}
th {
background-color: #ede;
}
.warning tt {
background: #efc2c2;
}
.note tt {
background: #d6d6d6;
}
.viewcode-back {
font-family: sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}

247
doc/_build/html/_static/doctools.js vendored Normal file
View File

@ -0,0 +1,247 @@
/*
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilties for all documentation.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*/
jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' ');
}
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s == 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* small function to check if an array contains
* a given item.
*/
jQuery.contains = function(arr, item) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == item)
return true;
}
return false;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this);
});
}
}
return this.each(function() {
highlight(this);
});
};
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated == 'undefined')
return string;
return (typeof translated == 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated == 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash && $.browser.mozilla)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});

BIN
doc/_build/html/_static/down-pressed.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

BIN
doc/_build/html/_static/down.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

BIN
doc/_build/html/_static/file.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

154
doc/_build/html/_static/jquery.js vendored Normal file
View File

@ -0,0 +1,154 @@
/*!
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Sat Feb 13 22:33:48 2010 -0500
*/
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);

BIN
doc/_build/html/_static/minus.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

BIN
doc/_build/html/_static/plus.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

62
doc/_build/html/_static/pygments.css vendored Normal file
View File

@ -0,0 +1,62 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #eeffcc; }
.highlight .c { color: #408090; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #007020; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #007020 } /* Comment.Preproc */
.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #303030 } /* Generic.Output */
.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0040D0 } /* Generic.Traceback */
.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #007020 } /* Keyword.Pseudo */
.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #902000 } /* Keyword.Type */
.highlight .m { color: #208050 } /* Literal.Number */
.highlight .s { color: #4070a0 } /* Literal.String */
.highlight .na { color: #4070a0 } /* Name.Attribute */
.highlight .nb { color: #007020 } /* Name.Builtin */
.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.highlight .no { color: #60add5 } /* Name.Constant */
.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #007020 } /* Name.Exception */
.highlight .nf { color: #06287e } /* Name.Function */
.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */
.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #bb60d5 } /* Name.Variable */
.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #208050 } /* Literal.Number.Float */
.highlight .mh { color: #208050 } /* Literal.Number.Hex */
.highlight .mi { color: #208050 } /* Literal.Number.Integer */
.highlight .mo { color: #208050 } /* Literal.Number.Oct */
.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */
.highlight .sc { color: #4070a0 } /* Literal.String.Char */
.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #4070a0 } /* Literal.String.Double */
.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */
.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.highlight .sx { color: #c65d09 } /* Literal.String.Other */
.highlight .sr { color: #235388 } /* Literal.String.Regex */
.highlight .s1 { color: #4070a0 } /* Literal.String.Single */
.highlight .ss { color: #517918 } /* Literal.String.Symbol */
.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */

560
doc/_build/html/_static/searchtools.js vendored Normal file
View File

@ -0,0 +1,560 @@
/*
* searchtools.js_t
* ~~~~~~~~~~~~~~~~
*
* Sphinx JavaScript utilties for the full-text search.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* helper function to return a node containing the
* search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed
* words. the first one is used to find the occurance, the
* latter for highlighting it.
*/
jQuery.makeSearchSummary = function(text, keywords, hlwords) {
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
var i = textLower.indexOf(this.toLowerCase());
if (i > -1)
start = i;
});
start = Math.max(start - 120, 0);
var excerpt = ((start > 0) ? '...' : '') +
$.trim(text.substr(start, 240)) +
((start + 240 - text.length) ? '...' : '');
var rv = $('<div class="context"></div>').text(excerpt);
$.each(hlwords, function() {
rv = rv.highlightText(this, 'highlighted');
});
return rv;
}
/**
* Porter Stemmer
*/
var Stemmer = function() {
var step2list = {
ational: 'ate',
tional: 'tion',
enci: 'ence',
anci: 'ance',
izer: 'ize',
bli: 'ble',
alli: 'al',
entli: 'ent',
eli: 'e',
ousli: 'ous',
ization: 'ize',
ation: 'ate',
ator: 'ate',
alism: 'al',
iveness: 'ive',
fulness: 'ful',
ousness: 'ous',
aliti: 'al',
iviti: 'ive',
biliti: 'ble',
logi: 'log'
};
var step3list = {
icate: 'ic',
ative: '',
alize: 'al',
iciti: 'ic',
ical: 'ic',
ful: '',
ness: ''
};
var c = "[^aeiou]"; // consonant
var v = "[aeiouy]"; // vowel
var C = c + "[^aeiouy]*"; // consonant sequence
var V = v + "[aeiou]*"; // vowel sequence
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
var s_v = "^(" + C + ")?" + v; // vowel in stem
this.stemWord = function (w) {
var stem;
var suffix;
var firstch;
var origword = w;
if (w.length < 3)
return w;
var re;
var re2;
var re3;
var re4;
firstch = w.substr(0,1);
if (firstch == "y")
w = firstch.toUpperCase() + w.substr(1);
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w))
w = w.replace(re,"$1$2");
else if (re2.test(w))
w = w.replace(re2,"$1$2");
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
}
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w))
w = w + "e";
else if (re3.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
else if (re4.test(w))
w = w + "e";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem))
w = stem + "i";
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step2list[suffix];
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step3list[suffix];
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem))
w = stem;
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem))
w = stem;
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
w = stem;
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y")
w = firstch.toLowerCase() + w.substr(1);
return w;
}
}
/**
* Search Module
*/
var Search = {
_index : null,
_queued_query : null,
_pulse_status : -1,
init : function() {
var params = $.getQueryParameters();
if (params.q) {
var query = params.q[0];
$('input[name="q"]')[0].value = query;
this.performSearch(query);
}
},
loadIndex : function(url) {
$.ajax({type: "GET", url: url, data: null, success: null,
dataType: "script", cache: true});
},
setIndex : function(index) {
var q;
this._index = index;
if ((q = this._queued_query) !== null) {
this._queued_query = null;
Search.query(q);
}
},
hasIndex : function() {
return this._index !== null;
},
deferQuery : function(query) {
this._queued_query = query;
},
stopPulse : function() {
this._pulse_status = 0;
},
startPulse : function() {
if (this._pulse_status >= 0)
return;
function pulse() {
Search._pulse_status = (Search._pulse_status + 1) % 4;
var dotString = '';
for (var i = 0; i < Search._pulse_status; i++)
dotString += '.';
Search.dots.text(dotString);
if (Search._pulse_status > -1)
window.setTimeout(pulse, 500);
};
pulse();
},
/**
* perform a search for something
*/
performSearch : function(query) {
// create the required interface elements
this.out = $('#search-results');
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
this.dots = $('<span></span>').appendTo(this.title);
this.status = $('<p style="display: none"></p>').appendTo(this.out);
this.output = $('<ul class="search"/>').appendTo(this.out);
$('#search-progress').text(_('Preparing search...'));
this.startPulse();
// index already loaded, the browser was quick!
if (this.hasIndex())
this.query(query);
else
this.deferQuery(query);
},
query : function(query) {
var stopwords = ["and","then","into","it","as","are","in","if","for","no","there","their","was","is","be","to","that","but","they","not","such","with","by","a","on","these","of","will","this","near","the","or","at"];
// Stem the searchterms and add them to the correct list
var stemmer = new Stemmer();
var searchterms = [];
var excluded = [];
var hlterms = [];
var tmp = query.split(/\s+/);
var objectterms = [];
for (var i = 0; i < tmp.length; i++) {
if (tmp[i] != "") {
objectterms.push(tmp[i].toLowerCase());
}
if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
tmp[i] == "") {
// skip this "word"
continue;
}
// stem the word
var word = stemmer.stemWord(tmp[i]).toLowerCase();
// select the correct list
if (word[0] == '-') {
var toAppend = excluded;
word = word.substr(1);
}
else {
var toAppend = searchterms;
hlterms.push(tmp[i].toLowerCase());
}
// only add if not already in the list
if (!$.contains(toAppend, word))
toAppend.push(word);
};
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
// console.debug('SEARCH: searching for:');
// console.info('required: ', searchterms);
// console.info('excluded: ', excluded);
// prepare search
var filenames = this._index.filenames;
var titles = this._index.titles;
var terms = this._index.terms;
var fileMap = {};
var files = null;
// different result priorities
var importantResults = [];
var objectResults = [];
var regularResults = [];
var unimportantResults = [];
$('#search-progress').empty();
// lookup as object
for (var i = 0; i < objectterms.length; i++) {
var others = [].concat(objectterms.slice(0,i),
objectterms.slice(i+1, objectterms.length))
var results = this.performObjectSearch(objectterms[i], others);
// Assume first word is most likely to be the object,
// other words more likely to be in description.
// Therefore put matches for earlier words first.
// (Results are eventually used in reverse order).
objectResults = results[0].concat(objectResults);
importantResults = results[1].concat(importantResults);
unimportantResults = results[2].concat(unimportantResults);
}
// perform the search on the required terms
for (var i = 0; i < searchterms.length; i++) {
var word = searchterms[i];
// no match but word was a required one
if ((files = terms[word]) == null)
break;
if (files.length == undefined) {
files = [files];
}
// create the mapping
for (var j = 0; j < files.length; j++) {
var file = files[j];
if (file in fileMap)
fileMap[file].push(word);
else
fileMap[file] = [word];
}
}
// now check if the files don't contain excluded terms
for (var file in fileMap) {
var valid = true;
// check if all requirements are matched
if (fileMap[file].length != searchterms.length)
continue;
// ensure that none of the excluded terms is in the
// search result.
for (var i = 0; i < excluded.length; i++) {
if (terms[excluded[i]] == file ||
$.contains(terms[excluded[i]] || [], file)) {
valid = false;
break;
}
}
// if we have still a valid result we can add it
// to the result list
if (valid)
regularResults.push([filenames[file], titles[file], '', null]);
}
// delete unused variables in order to not waste
// memory until list is retrieved completely
delete filenames, titles, terms;
// now sort the regular results descending by title
regularResults.sort(function(a, b) {
var left = a[1].toLowerCase();
var right = b[1].toLowerCase();
return (left > right) ? -1 : ((left < right) ? 1 : 0);
});
// combine all results
var results = unimportantResults.concat(regularResults)
.concat(objectResults).concat(importantResults);
// print the results
var resultCount = results.length;
function displayNextItem() {
// results left, load the summary and display it
if (results.length) {
var item = results.pop();
var listItem = $('<li style="display:none"></li>');
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') {
// dirhtml builder
var dirname = item[0] + '/';
if (dirname.match(/\/index\/$/)) {
dirname = dirname.substring(0, dirname.length-6);
} else if (dirname == 'index/') {
dirname = '';
}
listItem.append($('<a/>').attr('href',
DOCUMENTATION_OPTIONS.URL_ROOT + dirname +
highlightstring + item[2]).html(item[1]));
} else {
// normal html builders
listItem.append($('<a/>').attr('href',
item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX +
highlightstring + item[2]).html(item[1]));
}
if (item[3]) {
listItem.append($('<span> (' + item[3] + ')</span>'));
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
$.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' +
item[0] + '.txt', function(data) {
if (data != '') {
listItem.append($.makeSearchSummary(data, searchterms, hlterms));
Search.output.append(listItem);
}
listItem.slideDown(5, function() {
displayNextItem();
});
}, "text");
} else {
// no source available, just display title
Search.output.append(listItem);
listItem.slideDown(5, function() {
displayNextItem();
});
}
}
// search finished, update title and status message
else {
Search.stopPulse();
Search.title.text(_('Search Results'));
if (!resultCount)
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
else
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
Search.status.fadeIn(500);
}
}
displayNextItem();
},
performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames;
var objects = this._index.objects;
var objnames = this._index.objnames;
var titles = this._index.titles;
var importantResults = [];
var objectResults = [];
var unimportantResults = [];
for (var prefix in objects) {
for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) {
var match = objects[prefix][name];
var objname = objnames[match[1]][2];
var title = titles[match[0]];
// If more than one term searched for, we require other words to be
// found in the name/title/description
if (otherterms.length > 0) {
var haystack = (prefix + ' ' + name + ' ' +
objname + ' ' + title).toLowerCase();
var allfound = true;
for (var i = 0; i < otherterms.length; i++) {
if (haystack.indexOf(otherterms[i]) == -1) {
allfound = false;
break;
}
}
if (!allfound) {
continue;
}
}
var descr = objname + _(', in ') + title;
anchor = match[3];
if (anchor == '')
anchor = fullname;
else if (anchor == '-')
anchor = objnames[match[1]][1] + '-' + fullname;
result = [filenames[match[0]], fullname, '#'+anchor, descr];
switch (match[2]) {
case 1: objectResults.push(result); break;
case 0: importantResults.push(result); break;
case 2: unimportantResults.push(result); break;
}
}
}
}
// sort results descending
objectResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
importantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
unimportantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
return [importantResults, objectResults, unimportantResults]
}
}
$(document).ready(function() {
Search.init();
});

151
doc/_build/html/_static/sidebar.js vendored Normal file
View File

@ -0,0 +1,151 @@
/*
* sidebar.js
* ~~~~~~~~~~
*
* This script makes the Sphinx sidebar collapsible.
*
* .sphinxsidebar contains .sphinxsidebarwrapper. This script adds
* in .sphixsidebar, after .sphinxsidebarwrapper, the #sidebarbutton
* used to collapse and expand the sidebar.
*
* When the sidebar is collapsed the .sphinxsidebarwrapper is hidden
* and the width of the sidebar and the margin-left of the document
* are decreased. When the sidebar is expanded the opposite happens.
* This script saves a per-browser/per-session cookie used to
* remember the position of the sidebar among the pages.
* Once the browser is closed the cookie is deleted and the position
* reset to the default (expanded).
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
$(function() {
// global elements used by the functions.
// the 'sidebarbutton' element is defined as global after its
// creation, in the add_sidebar_button function
var bodywrapper = $('.bodywrapper');
var sidebar = $('.sphinxsidebar');
var sidebarwrapper = $('.sphinxsidebarwrapper');
// for some reason, the document has no sidebar; do not run into errors
if (!sidebar.length) return;
// original margin-left of the bodywrapper and width of the sidebar
// with the sidebar expanded
var bw_margin_expanded = bodywrapper.css('margin-left');
var ssb_width_expanded = sidebar.width();
// margin-left of the bodywrapper and width of the sidebar
// with the sidebar collapsed
var bw_margin_collapsed = '.8em';
var ssb_width_collapsed = '.8em';
// colors used by the current theme
var dark_color = $('.related').css('background-color');
var light_color = $('.document').css('background-color');
function sidebar_is_collapsed() {
return sidebarwrapper.is(':not(:visible)');
}
function toggle_sidebar() {
if (sidebar_is_collapsed())
expand_sidebar();
else
collapse_sidebar();
}
function collapse_sidebar() {
sidebarwrapper.hide();
sidebar.css('width', ssb_width_collapsed);
bodywrapper.css('margin-left', bw_margin_collapsed);
sidebarbutton.css({
'margin-left': '0',
'height': bodywrapper.height()
});
sidebarbutton.find('span').text('»');
sidebarbutton.attr('title', _('Expand sidebar'));
document.cookie = 'sidebar=collapsed';
}
function expand_sidebar() {
bodywrapper.css('margin-left', bw_margin_expanded);
sidebar.css('width', ssb_width_expanded);
sidebarwrapper.show();
sidebarbutton.css({
'margin-left': ssb_width_expanded-12,
'height': bodywrapper.height()
});
sidebarbutton.find('span').text('«');
sidebarbutton.attr('title', _('Collapse sidebar'));
document.cookie = 'sidebar=expanded';
}
function add_sidebar_button() {
sidebarwrapper.css({
'float': 'left',
'margin-right': '0',
'width': ssb_width_expanded - 28
});
// create the button
sidebar.append(
'<div id="sidebarbutton"><span>&laquo;</span></div>'
);
var sidebarbutton = $('#sidebarbutton');
light_color = sidebarbutton.css('background-color');
// find the height of the viewport to center the '<<' in the page
var viewport_height;
if (window.innerHeight)
viewport_height = window.innerHeight;
else
viewport_height = $(window).height();
sidebarbutton.find('span').css({
'display': 'block',
'margin-top': (viewport_height - sidebar.position().top - 20) / 2
});
sidebarbutton.click(toggle_sidebar);
sidebarbutton.attr('title', _('Collapse sidebar'));
sidebarbutton.css({
'color': '#FFFFFF',
'border-left': '1px solid ' + dark_color,
'font-size': '1.2em',
'cursor': 'pointer',
'height': bodywrapper.height(),
'padding-top': '1px',
'margin-left': ssb_width_expanded - 12
});
sidebarbutton.hover(
function () {
$(this).css('background-color', dark_color);
},
function () {
$(this).css('background-color', light_color);
}
);
}
function set_position_from_cookie() {
if (!document.cookie)
return;
var items = document.cookie.split(';');
for(var k=0; k<items.length; k++) {
var key_val = items[k].split('=');
var key = key_val[0];
if (key == 'sidebar') {
var value = key_val[1];
if ((value == 'collapsed') && (!sidebar_is_collapsed()))
collapse_sidebar();
else if ((value == 'expanded') && (sidebar_is_collapsed()))
expand_sidebar();
}
}
}
add_sidebar_button();
var sidebarbutton = $('#sidebarbutton');
set_position_from_cookie();
});

23
doc/_build/html/_static/underscore.js vendored Normal file
View File

@ -0,0 +1,23 @@
// Underscore.js 0.5.5
// (c) 2009 Jeremy Ashkenas, DocumentCloud Inc.
// Underscore is freely distributable under the terms of the MIT license.
// Portions of Underscore are inspired by or borrowed from Prototype.js,
// Oliver Steele's Functional, and John Resig's Micro-Templating.
// For all details and documentation:
// http://documentcloud.github.com/underscore/
(function(){var j=this,n=j._,i=function(a){this._wrapped=a},m=typeof StopIteration!=="undefined"?StopIteration:"__break__",b=j._=function(a){return new i(a)};if(typeof exports!=="undefined")exports._=b;var k=Array.prototype.slice,o=Array.prototype.unshift,p=Object.prototype.toString,q=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;b.VERSION="0.5.5";b.each=function(a,c,d){try{if(a.forEach)a.forEach(c,d);else if(b.isArray(a)||b.isArguments(a))for(var e=0,f=a.length;e<f;e++)c.call(d,
a[e],e,a);else{var g=b.keys(a);f=g.length;for(e=0;e<f;e++)c.call(d,a[g[e]],g[e],a)}}catch(h){if(h!=m)throw h;}return a};b.map=function(a,c,d){if(a&&b.isFunction(a.map))return a.map(c,d);var e=[];b.each(a,function(f,g,h){e.push(c.call(d,f,g,h))});return e};b.reduce=function(a,c,d,e){if(a&&b.isFunction(a.reduce))return a.reduce(b.bind(d,e),c);b.each(a,function(f,g,h){c=d.call(e,c,f,g,h)});return c};b.reduceRight=function(a,c,d,e){if(a&&b.isFunction(a.reduceRight))return a.reduceRight(b.bind(d,e),c);
var f=b.clone(b.toArray(a)).reverse();b.each(f,function(g,h){c=d.call(e,c,g,h,a)});return c};b.detect=function(a,c,d){var e;b.each(a,function(f,g,h){if(c.call(d,f,g,h)){e=f;b.breakLoop()}});return e};b.select=function(a,c,d){if(a&&b.isFunction(a.filter))return a.filter(c,d);var e=[];b.each(a,function(f,g,h){c.call(d,f,g,h)&&e.push(f)});return e};b.reject=function(a,c,d){var e=[];b.each(a,function(f,g,h){!c.call(d,f,g,h)&&e.push(f)});return e};b.all=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.every))return a.every(c,
d);var e=true;b.each(a,function(f,g,h){(e=e&&c.call(d,f,g,h))||b.breakLoop()});return e};b.any=function(a,c,d){c=c||b.identity;if(a&&b.isFunction(a.some))return a.some(c,d);var e=false;b.each(a,function(f,g,h){if(e=c.call(d,f,g,h))b.breakLoop()});return e};b.include=function(a,c){if(b.isArray(a))return b.indexOf(a,c)!=-1;var d=false;b.each(a,function(e){if(d=e===c)b.breakLoop()});return d};b.invoke=function(a,c){var d=b.rest(arguments,2);return b.map(a,function(e){return(c?e[c]:e).apply(e,d)})};b.pluck=
function(a,c){return b.map(a,function(d){return d[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);var e={computed:-Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g>=e.computed&&(e={value:f,computed:g})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};b.each(a,function(f,g,h){g=c?c.call(d,f,g,h):f;g<e.computed&&(e={value:f,computed:g})});return e.value};b.sortBy=function(a,c,d){return b.pluck(b.map(a,
function(e,f,g){return{value:e,criteria:c.call(d,e,f,g)}}).sort(function(e,f){e=e.criteria;f=f.criteria;return e<f?-1:e>f?1:0}),"value")};b.sortedIndex=function(a,c,d){d=d||b.identity;for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?(e=g+1):(f=g)}return e};b.toArray=function(a){if(!a)return[];if(a.toArray)return a.toArray();if(b.isArray(a))return a;if(b.isArguments(a))return k.call(a);return b.values(a)};b.size=function(a){return b.toArray(a).length};b.first=function(a,c,d){return c&&!d?k.call(a,
0,c):a[0]};b.rest=function(a,c,d){return k.call(a,b.isUndefined(c)||d?1:c)};b.last=function(a){return a[a.length-1]};b.compact=function(a){return b.select(a,function(c){return!!c})};b.flatten=function(a){return b.reduce(a,[],function(c,d){if(b.isArray(d))return c.concat(b.flatten(d));c.push(d);return c})};b.without=function(a){var c=b.rest(arguments);return b.select(a,function(d){return!b.include(c,d)})};b.uniq=function(a,c){return b.reduce(a,[],function(d,e,f){if(0==f||(c===true?b.last(d)!=e:!b.include(d,
e)))d.push(e);return d})};b.intersect=function(a){var c=b.rest(arguments);return b.select(b.uniq(a),function(d){return b.all(c,function(e){return b.indexOf(e,d)>=0})})};b.zip=function(){for(var a=b.toArray(arguments),c=b.max(b.pluck(a,"length")),d=new Array(c),e=0;e<c;e++)d[e]=b.pluck(a,String(e));return d};b.indexOf=function(a,c){if(a.indexOf)return a.indexOf(c);for(var d=0,e=a.length;d<e;d++)if(a[d]===c)return d;return-1};b.lastIndexOf=function(a,c){if(a.lastIndexOf)return a.lastIndexOf(c);for(var d=
a.length;d--;)if(a[d]===c)return d;return-1};b.range=function(a,c,d){var e=b.toArray(arguments),f=e.length<=1;a=f?0:e[0];c=f?e[0]:e[1];d=e[2]||1;e=Math.ceil((c-a)/d);if(e<=0)return[];e=new Array(e);f=a;for(var g=0;1;f+=d){if((d>0?f-c:c-f)>=0)return e;e[g++]=f}};b.bind=function(a,c){var d=b.rest(arguments,2);return function(){return a.apply(c||j,d.concat(b.toArray(arguments)))}};b.bindAll=function(a){var c=b.rest(arguments);if(c.length==0)c=b.functions(a);b.each(c,function(d){a[d]=b.bind(a[d],a)});
return a};b.delay=function(a,c){var d=b.rest(arguments,2);return setTimeout(function(){return a.apply(a,d)},c)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(b.rest(arguments)))};b.wrap=function(a,c){return function(){var d=[a].concat(b.toArray(arguments));return c.apply(c,d)}};b.compose=function(){var a=b.toArray(arguments);return function(){for(var c=b.toArray(arguments),d=a.length-1;d>=0;d--)c=[a[d].apply(this,c)];return c[0]}};b.keys=function(a){if(b.isArray(a))return b.range(0,a.length);
var c=[];for(var d in a)q.call(a,d)&&c.push(d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=function(a){return b.select(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a,c){for(var d in c)a[d]=c[d];return a};b.clone=function(a){if(b.isArray(a))return a.slice(0);return b.extend({},a)};b.tap=function(a,c){c(a);return a};b.isEqual=function(a,c){if(a===c)return true;var d=typeof a;if(d!=typeof c)return false;if(a==c)return true;if(!a&&c||a&&!c)return false;
if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return true;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return false;if(a.length&&a.length!==c.length)return false;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return false;for(var f in a)if(!b.isEqual(a[f],c[f]))return false;return true};b.isEmpty=function(a){return b.keys(a).length==
0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=function(a){return!!(a&&a.concat&&a.unshift)};b.isArguments=function(a){return a&&b.isNumber(a.length)&&!b.isArray(a)&&!r.call(a,"length")};b.isFunction=function(a){return!!(a&&a.constructor&&a.call&&a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return p.call(a)==="[object Number]"};b.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};b.isRegExp=function(a){return!!(a&&
a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};b.isNaN=function(a){return b.isNumber(a)&&isNaN(a)};b.isNull=function(a){return a===null};b.isUndefined=function(a){return typeof a=="undefined"};b.noConflict=function(){j._=n;return this};b.identity=function(a){return a};b.breakLoop=function(){throw m;};var s=0;b.uniqueId=function(a){var c=s++;return a?a+c:c};b.template=function(a,c){a=new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g,
" ").replace(/'(?=[^%]*%>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<%=(.+?)%>/g,"',$1,'").split("<%").join("');").split("%>").join("p.push('")+"');}return p.join('');");return c?a(c):a};b.forEach=b.each;b.foldl=b.inject=b.reduce;b.foldr=b.reduceRight;b.filter=b.select;b.every=b.all;b.some=b.any;b.head=b.first;b.tail=b.rest;b.methods=b.functions;var l=function(a,c){return c?b(a).chain():a};b.each(b.functions(b),function(a){var c=b[a];i.prototype[a]=function(){var d=b.toArray(arguments);
o.call(d,this._wrapped);return l(c.apply(b,d),this._chain)}});b.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){c.apply(this._wrapped,arguments);return l(this._wrapped,this._chain)}});b.each(["concat","join","slice"],function(a){var c=Array.prototype[a];i.prototype[a]=function(){return l(c.apply(this._wrapped,arguments),this._chain)}});i.prototype.chain=function(){this._chain=true;return this};i.prototype.value=function(){return this._wrapped}})();

BIN
doc/_build/html/_static/up-pressed.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

BIN
doc/_build/html/_static/up.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

808
doc/_build/html/_static/websupport.js vendored Normal file
View File

@ -0,0 +1,808 @@
/*
* websupport.js
* ~~~~~~~~~~~~~
*
* sphinx.websupport utilties for all documentation.
*
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
(function($) {
$.fn.autogrow = function() {
return this.each(function() {
var textarea = this;
$.fn.autogrow.resize(textarea);
$(textarea)
.focus(function() {
textarea.interval = setInterval(function() {
$.fn.autogrow.resize(textarea);
}, 500);
})
.blur(function() {
clearInterval(textarea.interval);
});
});
};
$.fn.autogrow.resize = function(textarea) {
var lineHeight = parseInt($(textarea).css('line-height'), 10);
var lines = textarea.value.split('\n');
var columns = textarea.cols;
var lineCount = 0;
$.each(lines, function() {
lineCount += Math.ceil(this.length / columns) || 1;
});
var height = lineHeight * (lineCount + 1);
$(textarea).css('height', height);
};
})(jQuery);
(function($) {
var comp, by;
function init() {
initEvents();
initComparator();
}
function initEvents() {
$('a.comment-close').live("click", function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
});
$('a.vote').live("click", function(event) {
event.preventDefault();
handleVote($(this));
});
$('a.reply').live("click", function(event) {
event.preventDefault();
openReply($(this).attr('id').substring(2));
});
$('a.close-reply').live("click", function(event) {
event.preventDefault();
closeReply($(this).attr('id').substring(2));
});
$('a.sort-option').live("click", function(event) {
event.preventDefault();
handleReSort($(this));
});
$('a.show-proposal').live("click", function(event) {
event.preventDefault();
showProposal($(this).attr('id').substring(2));
});
$('a.hide-proposal').live("click", function(event) {
event.preventDefault();
hideProposal($(this).attr('id').substring(2));
});
$('a.show-propose-change').live("click", function(event) {
event.preventDefault();
showProposeChange($(this).attr('id').substring(2));
});
$('a.hide-propose-change').live("click", function(event) {
event.preventDefault();
hideProposeChange($(this).attr('id').substring(2));
});
$('a.accept-comment').live("click", function(event) {
event.preventDefault();
acceptComment($(this).attr('id').substring(2));
});
$('a.delete-comment').live("click", function(event) {
event.preventDefault();
deleteComment($(this).attr('id').substring(2));
});
$('a.comment-markup').live("click", function(event) {
event.preventDefault();
toggleCommentMarkupBox($(this).attr('id').substring(2));
});
}
/**
* Set comp, which is a comparator function used for sorting and
* inserting comments into the list.
*/
function setComparator() {
// If the first three letters are "asc", sort in ascending order
// and remove the prefix.
if (by.substring(0,3) == 'asc') {
var i = by.substring(3);
comp = function(a, b) { return a[i] - b[i]; };
} else {
// Otherwise sort in descending order.
comp = function(a, b) { return b[by] - a[by]; };
}
// Reset link styles and format the selected sort option.
$('a.sel').attr('href', '#').removeClass('sel');
$('a.by' + by).removeAttr('href').addClass('sel');
}
/**
* Create a comp function. If the user has preferences stored in
* the sortBy cookie, use those, otherwise use the default.
*/
function initComparator() {
by = 'rating'; // Default to sort by rating.
// If the sortBy cookie is set, use that instead.
if (document.cookie.length > 0) {
var start = document.cookie.indexOf('sortBy=');
if (start != -1) {
start = start + 7;
var end = document.cookie.indexOf(";", start);
if (end == -1) {
end = document.cookie.length;
by = unescape(document.cookie.substring(start, end));
}
}
}
setComparator();
}
/**
* Show a comment div.
*/
function show(id) {
$('#ao' + id).hide();
$('#ah' + id).show();
var context = $.extend({id: id}, opts);
var popup = $(renderTemplate(popupTemplate, context)).hide();
popup.find('textarea[name="proposal"]').hide();
popup.find('a.by' + by).addClass('sel');
var form = popup.find('#cf' + id);
form.submit(function(event) {
event.preventDefault();
addComment(form);
});
$('#s' + id).after(popup);
popup.slideDown('fast', function() {
getComments(id);
});
}
/**
* Hide a comment div.
*/
function hide(id) {
$('#ah' + id).hide();
$('#ao' + id).show();
var div = $('#sc' + id);
div.slideUp('fast', function() {
div.remove();
});
}
/**
* Perform an ajax request to get comments for a node
* and insert the comments into the comments tree.
*/
function getComments(id) {
$.ajax({
type: 'GET',
url: opts.getCommentsURL,
data: {node: id},
success: function(data, textStatus, request) {
var ul = $('#cl' + id);
var speed = 100;
$('#cf' + id)
.find('textarea[name="proposal"]')
.data('source', data.source);
if (data.comments.length === 0) {
ul.html('<li>No comments yet.</li>');
ul.data('empty', true);
} else {
// If there are comments, sort them and put them in the list.
var comments = sortComments(data.comments);
speed = data.comments.length * 100;
appendComments(comments, ul);
ul.data('empty', false);
}
$('#cn' + id).slideUp(speed + 200);
ul.slideDown(speed);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem retrieving the comments.');
},
dataType: 'json'
});
}
/**
* Add a comment via ajax and insert the comment into the comment tree.
*/
function addComment(form) {
var node_id = form.find('input[name="node"]').val();
var parent_id = form.find('input[name="parent"]').val();
var text = form.find('textarea[name="comment"]').val();
var proposal = form.find('textarea[name="proposal"]').val();
if (text == '') {
showError('Please enter a comment.');
return;
}
// Disable the form that is being submitted.
form.find('textarea,input').attr('disabled', 'disabled');
// Send the comment to the server.
$.ajax({
type: "POST",
url: opts.addCommentURL,
dataType: 'json',
data: {
node: node_id,
parent: parent_id,
text: text,
proposal: proposal
},
success: function(data, textStatus, error) {
// Reset the form.
if (node_id) {
hideProposeChange(node_id);
}
form.find('textarea')
.val('')
.add(form.find('input'))
.removeAttr('disabled');
var ul = $('#cl' + (node_id || parent_id));
if (ul.data('empty')) {
$(ul).empty();
ul.data('empty', false);
}
insertComment(data.comment);
var ao = $('#ao' + node_id);
ao.find('img').attr({'src': opts.commentBrightImage});
if (node_id) {
// if this was a "root" comment, remove the commenting box
// (the user can get it back by reopening the comment popup)
$('#ca' + node_id).slideUp();
}
},
error: function(request, textStatus, error) {
form.find('textarea,input').removeAttr('disabled');
showError('Oops, there was a problem adding the comment.');
}
});
}
/**
* Recursively append comments to the main comment list and children
* lists, creating the comment tree.
*/
function appendComments(comments, ul) {
$.each(comments, function() {
var div = createCommentDiv(this);
ul.append($(document.createElement('li')).html(div));
appendComments(this.children, div.find('ul.comment-children'));
// To avoid stagnating data, don't store the comments children in data.
this.children = null;
div.data('comment', this);
});
}
/**
* After adding a new comment, it must be inserted in the correct
* location in the comment tree.
*/
function insertComment(comment) {
var div = createCommentDiv(comment);
// To avoid stagnating data, don't store the comments children in data.
comment.children = null;
div.data('comment', comment);
var ul = $('#cl' + (comment.node || comment.parent));
var siblings = getChildren(ul);
var li = $(document.createElement('li'));
li.hide();
// Determine where in the parents children list to insert this comment.
for(i=0; i < siblings.length; i++) {
if (comp(comment, siblings[i]) <= 0) {
$('#cd' + siblings[i].id)
.parent()
.before(li.html(div));
li.slideDown('fast');
return;
}
}
// If we get here, this comment rates lower than all the others,
// or it is the only comment in the list.
ul.append(li.html(div));
li.slideDown('fast');
}
function acceptComment(id) {
$.ajax({
type: 'POST',
url: opts.acceptCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
$('#cm' + id).fadeOut('fast');
$('#cd' + id).removeClass('moderate');
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem accepting the comment.');
}
});
}
function deleteComment(id) {
$.ajax({
type: 'POST',
url: opts.deleteCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
var div = $('#cd' + id);
if (data == 'delete') {
// Moderator mode: remove the comment and all children immediately
div.slideUp('fast', function() {
div.remove();
});
return;
}
// User mode: only mark the comment as deleted
div
.find('span.user-id:first')
.text('[deleted]').end()
.find('div.comment-text:first')
.text('[deleted]').end()
.find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
.remove();
var comment = div.data('comment');
comment.username = '[deleted]';
comment.text = '[deleted]';
div.data('comment', comment);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem deleting the comment.');
}
});
}
function showProposal(id) {
$('#sp' + id).hide();
$('#hp' + id).show();
$('#pr' + id).slideDown('fast');
}
function hideProposal(id) {
$('#hp' + id).hide();
$('#sp' + id).show();
$('#pr' + id).slideUp('fast');
}
function showProposeChange(id) {
$('#pc' + id).hide();
$('#hc' + id).show();
var textarea = $('#pt' + id);
textarea.val(textarea.data('source'));
$.fn.autogrow.resize(textarea[0]);
textarea.slideDown('fast');
}
function hideProposeChange(id) {
$('#hc' + id).hide();
$('#pc' + id).show();
var textarea = $('#pt' + id);
textarea.val('').removeAttr('disabled');
textarea.slideUp('fast');
}
function toggleCommentMarkupBox(id) {
$('#mb' + id).toggle();
}
/** Handle when the user clicks on a sort by link. */
function handleReSort(link) {
var classes = link.attr('class').split(/\s+/);
for (var i=0; i<classes.length; i++) {
if (classes[i] != 'sort-option') {
by = classes[i].substring(2);
}
}
setComparator();
// Save/update the sortBy cookie.
var expiration = new Date();
expiration.setDate(expiration.getDate() + 365);
document.cookie= 'sortBy=' + escape(by) +
';expires=' + expiration.toUTCString();
$('ul.comment-ul').each(function(index, ul) {
var comments = getChildren($(ul), true);
comments = sortComments(comments);
appendComments(comments, $(ul).empty());
});
}
/**
* Function to process a vote when a user clicks an arrow.
*/
function handleVote(link) {
if (!opts.voting) {
showError("You'll need to login to vote.");
return;
}
var id = link.attr('id');
if (!id) {
// Didn't click on one of the voting arrows.
return;
}
// If it is an unvote, the new vote value is 0,
// Otherwise it's 1 for an upvote, or -1 for a downvote.
var value = 0;
if (id.charAt(1) != 'u') {
value = id.charAt(0) == 'u' ? 1 : -1;
}
// The data to be sent to the server.
var d = {
comment_id: id.substring(2),
value: value
};
// Swap the vote and unvote links.
link.hide();
$('#' + id.charAt(0) + (id.charAt(1) == 'u' ? 'v' : 'u') + d.comment_id)
.show();
// The div the comment is displayed in.
var div = $('div#cd' + d.comment_id);
var data = div.data('comment');
// If this is not an unvote, and the other vote arrow has
// already been pressed, unpress it.
if ((d.value !== 0) && (data.vote === d.value * -1)) {
$('#' + (d.value == 1 ? 'd' : 'u') + 'u' + d.comment_id).hide();
$('#' + (d.value == 1 ? 'd' : 'u') + 'v' + d.comment_id).show();
}
// Update the comments rating in the local data.
data.rating += (data.vote === 0) ? d.value : (d.value - data.vote);
data.vote = d.value;
div.data('comment', data);
// Change the rating text.
div.find('.rating:first')
.text(data.rating + ' point' + (data.rating == 1 ? '' : 's'));
// Send the vote information to the server.
$.ajax({
type: "POST",
url: opts.processVoteURL,
data: d,
error: function(request, textStatus, error) {
showError('Oops, there was a problem casting that vote.');
}
});
}
/**
* Open a reply form used to reply to an existing comment.
*/
function openReply(id) {
// Swap out the reply link for the hide link
$('#rl' + id).hide();
$('#cr' + id).show();
// Add the reply li to the children ul.
var div = $(renderTemplate(replyTemplate, {id: id})).hide();
$('#cl' + id)
.prepend(div)
// Setup the submit handler for the reply form.
.find('#rf' + id)
.submit(function(event) {
event.preventDefault();
addComment($('#rf' + id));
closeReply(id);
})
.find('input[type=button]')
.click(function() {
closeReply(id);
});
div.slideDown('fast', function() {
$('#rf' + id).find('textarea').focus();
});
}
/**
* Close the reply form opened with openReply.
*/
function closeReply(id) {
// Remove the reply div from the DOM.
$('#rd' + id).slideUp('fast', function() {
$(this).remove();
});
// Swap out the hide link for the reply link
$('#cr' + id).hide();
$('#rl' + id).show();
}
/**
* Recursively sort a tree of comments using the comp comparator.
*/
function sortComments(comments) {
comments.sort(comp);
$.each(comments, function() {
this.children = sortComments(this.children);
});
return comments;
}
/**
* Get the children comments from a ul. If recursive is true,
* recursively include childrens' children.
*/
function getChildren(ul, recursive) {
var children = [];
ul.children().children("[id^='cd']")
.each(function() {
var comment = $(this).data('comment');
if (recursive)
comment.children = getChildren($(this).find('#cl' + comment.id), true);
children.push(comment);
});
return children;
}
/** Create a div to display a comment in. */
function createCommentDiv(comment) {
if (!comment.displayed && !opts.moderator) {
return $('<div class="moderate">Thank you! Your comment will show up '
+ 'once it is has been approved by a moderator.</div>');
}
// Prettify the comment rating.
comment.pretty_rating = comment.rating + ' point' +
(comment.rating == 1 ? '' : 's');
// Make a class (for displaying not yet moderated comments differently)
comment.css_class = comment.displayed ? '' : ' moderate';
// Create a div for this comment.
var context = $.extend({}, opts, comment);
var div = $(renderTemplate(commentTemplate, context));
// If the user has voted on this comment, highlight the correct arrow.
if (comment.vote) {
var direction = (comment.vote == 1) ? 'u' : 'd';
div.find('#' + direction + 'v' + comment.id).hide();
div.find('#' + direction + 'u' + comment.id).show();
}
if (opts.moderator || comment.text != '[deleted]') {
div.find('a.reply').show();
if (comment.proposal_diff)
div.find('#sp' + comment.id).show();
if (opts.moderator && !comment.displayed)
div.find('#cm' + comment.id).show();
if (opts.moderator || (opts.username == comment.username))
div.find('#dc' + comment.id).show();
}
return div;
}
/**
* A simple template renderer. Placeholders such as <%id%> are replaced
* by context['id'] with items being escaped. Placeholders such as <#id#>
* are not escaped.
*/
function renderTemplate(template, context) {
var esc = $(document.createElement('div'));
function handle(ph, escape) {
var cur = context;
$.each(ph.split('.'), function() {
cur = cur[this];
});
return escape ? esc.text(cur || "").html() : cur;
}
return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
return handle(arguments[2], arguments[1] == '%' ? true : false);
});
}
/** Flash an error message briefly. */
function showError(message) {
$(document.createElement('div')).attr({'class': 'popup-error'})
.append($(document.createElement('div'))
.attr({'class': 'error-message'}).text(message))
.appendTo('body')
.fadeIn("slow")
.delay(2000)
.fadeOut("slow");
}
/** Add a link the user uses to open the comments popup. */
$.fn.comment = function() {
return this.each(function() {
var id = $(this).attr('id').substring(1);
var count = COMMENT_METADATA[id];
var title = count + ' comment' + (count == 1 ? '' : 's');
var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
var addcls = count == 0 ? ' nocomment' : '';
$(this)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-open' + addcls,
id: 'ao' + id
})
.append($(document.createElement('img')).attr({
src: image,
alt: 'comment',
title: title
}))
.click(function(event) {
event.preventDefault();
show($(this).attr('id').substring(2));
})
)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-close hidden',
id: 'ah' + id
})
.append($(document.createElement('img')).attr({
src: opts.closeCommentImage,
alt: 'close',
title: 'close'
}))
.click(function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
})
);
});
};
var opts = {
processVoteURL: '/_process_vote',
addCommentURL: '/_add_comment',
getCommentsURL: '/_get_comments',
acceptCommentURL: '/_accept_comment',
deleteCommentURL: '/_delete_comment',
commentImage: '/static/_static/comment.png',
closeCommentImage: '/static/_static/comment-close.png',
loadingImage: '/static/_static/ajax-loader.gif',
commentBrightImage: '/static/_static/comment-bright.png',
upArrow: '/static/_static/up.png',
downArrow: '/static/_static/down.png',
upArrowPressed: '/static/_static/up-pressed.png',
downArrowPressed: '/static/_static/down-pressed.png',
voting: false,
moderator: false
};
if (typeof COMMENT_OPTIONS != "undefined") {
opts = jQuery.extend(opts, COMMENT_OPTIONS);
}
var popupTemplate = '\
<div class="sphinx-comments" id="sc<%id%>">\
<p class="sort-options">\
Sort by:\
<a href="#" class="sort-option byrating">best rated</a>\
<a href="#" class="sort-option byascage">newest</a>\
<a href="#" class="sort-option byage">oldest</a>\
</p>\
<div class="comment-header">Comments</div>\
<div class="comment-loading" id="cn<%id%>">\
loading comments... <img src="<%loadingImage%>" alt="" /></div>\
<ul id="cl<%id%>" class="comment-ul"></ul>\
<div id="ca<%id%>">\
<p class="add-a-comment">Add a comment\
(<a href="#" class="comment-markup" id="ab<%id%>">markup</a>):</p>\
<div class="comment-markup-box" id="mb<%id%>">\
reStructured text markup: <i>*emph*</i>, <b>**strong**</b>, \
<tt>``code``</tt>, \
code blocks: <tt>::</tt> and an indented block after blank line</div>\
<form method="post" id="cf<%id%>" class="comment-form" action="">\
<textarea name="comment" cols="80"></textarea>\
<p class="propose-button">\
<a href="#" id="pc<%id%>" class="show-propose-change">\
Propose a change &#9657;\
</a>\
<a href="#" id="hc<%id%>" class="hide-propose-change">\
Propose a change &#9663;\
</a>\
</p>\
<textarea name="proposal" id="pt<%id%>" cols="80"\
spellcheck="false"></textarea>\
<input type="submit" value="Add comment" />\
<input type="hidden" name="node" value="<%id%>" />\
<input type="hidden" name="parent" value="" />\
</form>\
</div>\
</div>';
var commentTemplate = '\
<div id="cd<%id%>" class="sphinx-comment<%css_class%>">\
<div class="vote">\
<div class="arrow">\
<a href="#" id="uv<%id%>" class="vote" title="vote up">\
<img src="<%upArrow%>" />\
</a>\
<a href="#" id="uu<%id%>" class="un vote" title="vote up">\
<img src="<%upArrowPressed%>" />\
</a>\
</div>\
<div class="arrow">\
<a href="#" id="dv<%id%>" class="vote" title="vote down">\
<img src="<%downArrow%>" id="da<%id%>" />\
</a>\
<a href="#" id="du<%id%>" class="un vote" title="vote down">\
<img src="<%downArrowPressed%>" />\
</a>\
</div>\
</div>\
<div class="comment-content">\
<p class="tagline comment">\
<span class="user-id"><%username%></span>\
<span class="rating"><%pretty_rating%></span>\
<span class="delta"><%time.delta%></span>\
</p>\
<div class="comment-text comment"><#text#></div>\
<p class="comment-opts comment">\
<a href="#" class="reply hidden" id="rl<%id%>">reply &#9657;</a>\
<a href="#" class="close-reply" id="cr<%id%>">reply &#9663;</a>\
<a href="#" id="sp<%id%>" class="show-proposal">proposal &#9657;</a>\
<a href="#" id="hp<%id%>" class="hide-proposal">proposal &#9663;</a>\
<a href="#" id="dc<%id%>" class="delete-comment hidden">delete</a>\
<span id="cm<%id%>" class="moderation hidden">\
<a href="#" id="ac<%id%>" class="accept-comment">accept</a>\
</span>\
</p>\
<pre class="proposal" id="pr<%id%>">\
<#proposal_diff#>\
</pre>\
<ul class="comment-children" id="cl<%id%>"></ul>\
</div>\
<div class="clearleft"></div>\
</div>\
</div>';
var replyTemplate = '\
<li>\
<div class="reply-div" id="rd<%id%>">\
<form id="rf<%id%>">\
<textarea name="comment" cols="80"></textarea>\
<input type="submit" value="Add reply" />\
<input type="button" value="Cancel" />\
<input type="hidden" name="parent" value="<%id%>" />\
<input type="hidden" name="node" value="" />\
</form>\
</div>\
</li>';
$(document).ready(function() {
init();
});
})(jQuery);
$(document).ready(function() {
// add comment anchors for all paragraphs that are commentable
$('.sphinx-has-comment').comment();
// highlight search words in search results
$("div.context").each(function() {
var params = $.getQueryParameters();
var terms = (params.q) ? params.q[0].split(/\s+/) : [];
var result = $(this);
$.each(terms, function() {
result.highlightText(this.toLowerCase(), 'highlighted');
});
});
// directly open comment window if requested
var anchor = document.location.hash;
if (anchor.substring(0, 9) == '#comment-') {
$('#ao' + anchor.substring(9)).click();
document.location.hash = '#s' + anchor.substring(9);
}
});

View File

@ -0,0 +1,697 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Attribute Management in Authentic2 &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="prev" title="Configure Authentic2 as a CAS client" href="config_cas_idp.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="config_cas_idp.html" title="Configure Authentic2 as a CAS client"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="attribute-management-in-authentic2">
<span id="attribute-management"></span><h1>Attribute Management in Authentic2<a class="headerlink" href="#attribute-management-in-authentic2" title="Permalink to this headline"></a></h1>
<div class="section" id="summary">
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline"></a></h2>
<p>Attribute management currently allows to configure attribute policies
associated with SAML2 service providers to define attributes that are
pushed in SAML2 successful authentication response delivered by Authentic2.</p>
<p>User attributes can be taken from LDAP directories, the user Django
profile or taken from the user Django session if Authentic2 is also configured
as a SAML2 service provider.</p>
<p>Indeed, when Authentic2 acts also as a SAML2 service provider,
attributes contained in the SAML2 assertion received from third IdP are put in
the user session.</p>
<p>Attributes can thus be proxyfied during SSO with Authentic2
configured as a SAML2 proxy.</p>
<p>The namespace of attributes received from another SAML2 IdP or pushed in the
assertion given in to service providers can be configured per attribute or per
service provider.</p>
<p>By default, the namespace and format of attributes in assertion is conformant
to the SAMLV2.0 X500/LDAP Attribute profile:</p>
<div class="highlight-python"><pre>&lt;saml:Attribute
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:2.5.4.42" FriendlyName="givenName"&gt;
&lt;saml:AttributeValue xsi:type="xs:string"
x500:Encoding="LDAP"&gt;Mikaël&lt;/saml:AttributeValue&gt;
&lt;/saml:Attribute&gt;</pre>
</div>
<p>But the <a class="reference external" href="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">http://schemas.xmlsoap.org/ws/2005/05/identity/claims</a> from the ISI
profile can also be used, for instance:</p>
<div class="highlight-python"><pre>&lt;saml:Attribute
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
FriendlyName="First Name"&gt;
&lt;saml:AttributeValue&gt;Mikaël&lt;/saml:AttributeValue&gt;
&lt;/saml:Attribute&gt;</pre>
</div>
</div>
<div class="section" id="configuration">
<h2>Configuration<a class="headerlink" href="#configuration" title="Permalink to this headline"></a></h2>
<div class="section" id="configure-sources-of-attributes">
<h3>Configure sources of attributes<a class="headerlink" href="#configure-sources-of-attributes" title="Permalink to this headline"></a></h3>
<p>The source of attributes for authentic2 are of two kinds. The LDAP sources and
the user django profile.</p>
<div class="section" id="declare-the-django-profile-source">
<h4>Declare the Django profile source<a class="headerlink" href="#declare-the-django-profile-source" title="Permalink to this headline"></a></h4>
<p>Add an attribute source named USER_PROFILE with namespace &#8216;Default&#8217;.</p>
<p>Then, it is necessary that users create their profile.</p>
</div>
<div class="section" id="add-an-ldap-source">
<h4>Add an LDAP Source<a class="headerlink" href="#add-an-ldap-source" title="Permalink to this headline"></a></h4>
<p>For LDAP sources, objects of type &#8216;LDAPSource&#8217; must be created.</p>
<p><strong>Even if the authentication is based on LDAP authentification, thus that a
server is configured in settings.py, it is
necessary to create a corresponding &#8216;LDAPSource&#8217; to use it as a source of
attribute.</strong></p>
<ol class="arabic simple">
<li>Go to http[s]://your.domain.com/admin/attribute_aggregator/ldapsource/add/</li>
<li>Fill form fields</li>
</ol>
<p>Only the field Name, Server, User, Password, Base and Port are used for now.
<strong>The namespace of LDAP source must be kept to &#8216;Default&#8217;, since the system
namespace is based on LDAP.</strong></p>
<img alt="_images/ldapsource.png" src="_images/ldapsource.png" style="width: 800px;" />
<ol class="arabic simple" start="3">
<li>Save</li>
</ol>
<img alt="_images/ldapsource_saved.png" src="_images/ldapsource_saved.png" style="width: 800px;" />
</div>
<div class="section" id="manage-user-distinguished-names-in-ldap-directories">
<h4>Manage user distinguished names in LDAP directories<a class="headerlink" href="#manage-user-distinguished-names-in-ldap-directories" title="Permalink to this headline"></a></h4>
<p>To find the user in a LDAP directory, authentic2 must know its distinguished
name (DN). If this LDAP has been used when the user has authenticated,
Authentic2 learn the user DN. Nothing has to be done from this point of view.</p>
<p>However, if it is expected that user attributes be taken in a directory that
is not used by the user for authentication, it is necessary to manually
indicate to Authentic2 what is the user DN in the directory. For this, a
user alias in source is created for the user:</p>
<ol class="arabic simple">
<li>Go to http[s]://your.domain.com/admin/attribute_aggregator/useraliasinsource/add/</li>
<li>Fill form fields</li>
</ol>
<img alt="_images/alias_in_source.png" src="_images/alias_in_source.png" style="width: 800px;" />
<ol class="arabic simple" start="3">
<li>Save</li>
</ol>
<img alt="_images/alias_in_source_saved.png" src="_images/alias_in_source_saved.png" style="width: 800px;" />
</div>
</div>
<div class="section" id="configure-attributes-pushed-to-saml2-service-providers-in-sso-response">
<h3>Configure attributes pushed to SAML2 service providers in SSO response<a class="headerlink" href="#configure-attributes-pushed-to-saml2-service-providers-in-sso-response" title="Permalink to this headline"></a></h3>
<p>Reminder:</p>
<ul class="simple">
<li>The default name format in SAML2 assertions is URI</li>
<li>The default namespace called &#8216;Default&#8217; is LDAP</li>
</ul>
<p>In summary:</p>
<ol class="arabic simple">
<li>Create attribute items indicating an attribute name, a source, the name format expected and the namespace expected for the attribute name and friendly name if any.</li>
<li>Create a named list of attribute items.</li>
<li>Create an attribute policy and associate the previous list or associate the previous list to a existing attribute policy.</li>
<li>Associate the policy to a service provider.</li>
</ol>
<div class="section" id="create-attribute-items">
<h4>Create attribute items<a class="headerlink" href="#create-attribute-items" title="Permalink to this headline"></a></h4>
<ol class="arabic simple">
<li>Go to http[s]://your.domain.com/admin/idp/attributeitem/add/</li>
<li>Fill form fields</li>
</ol>
<img alt="_images/attribute_item.png" src="_images/attribute_item.png" style="width: 800px;" />
<ol class="arabic simple" start="3">
<li>Save</li>
</ol>
<img alt="_images/attribute_item_saved.png" src="_images/attribute_item_saved.png" style="width: 800px;" />
</div>
<div class="section" id="create-a-named-list-of-attribute-items">
<h4>Create a named list of attribute items<a class="headerlink" href="#create-a-named-list-of-attribute-items" title="Permalink to this headline"></a></h4>
<ol class="arabic simple">
<li>Go to http[s]://your.domain.com/admin/idp/attributelist/add/</li>
<li>Name the list and add items to list</li>
</ol>
<img alt="_images/attribute_list.png" src="_images/attribute_list.png" style="width: 800px;" />
<ol class="arabic simple" start="3">
<li>Save</li>
</ol>
<img alt="_images/attribute_list_saved.png" src="_images/attribute_list_saved.png" style="width: 800px;" />
</div>
<div class="section" id="create-or-modify-an-attribute-policy">
<h4>Create or modify an attribute policy<a class="headerlink" href="#create-or-modify-an-attribute-policy" title="Permalink to this headline"></a></h4>
<ol class="arabic simple">
<li>Go to http[s]://your.domain.com/admin/idp/attributepolicy/add/</li>
<li>Add list to the policy</li>
</ol>
<img alt="_images/policy_pull.png" src="_images/policy_pull.png" style="width: 800px;" />
<ol class="arabic simple" start="3">
<li>Save</li>
</ol>
<img alt="_images/policy_pull_saved.png" src="_images/policy_pull_saved.png" style="width: 800px;" />
</div>
<div class="section" id="associate-the-policy-to-a-service-provider">
<h4>Associate the policy to a service provider<a class="headerlink" href="#associate-the-policy-to-a-service-provider" title="Permalink to this headline"></a></h4>
<ol class="arabic simple">
<li>Go to http[s]://your.domain.com/admin/saml/libertyprovider/1/</li>
<li>Add policy to the service provider</li>
</ol>
<img alt="_images/sp_policy_pull.png" src="_images/sp_policy_pull.png" style="width: 800px;" />
<ol class="arabic simple" start="3">
<li>Save</li>
</ol>
<img alt="_images/sp_policy_pull_saved.png" src="_images/sp_policy_pull_saved.png" style="width: 800px;" />
<ol class="arabic simple" start="4">
<li>The display name of the policy has changed</li>
</ol>
<img alt="_images/policy_pull_renamed.png" src="_images/policy_pull_renamed.png" style="width: 800px;" />
</div>
</div>
<div class="section" id="handle-attributes-provided-by-other-identity-providers-proxy-attributes">
<h3>Handle attributes provided by other Identity providers, proxy attributes<a class="headerlink" href="#handle-attributes-provided-by-other-identity-providers-proxy-attributes" title="Permalink to this headline"></a></h3>
<p>Link to configure first Authentic as a sp to have attributes in session</p>
<p>Add a source if mapping set to true</p>
</div>
</div>
<div class="section" id="modifying-supported-namespaces-and-attribute-name-mappings">
<h2>Modifying supported namespaces and attribute name mappings<a class="headerlink" href="#modifying-supported-namespaces-and-attribute-name-mappings" title="Permalink to this headline"></a></h2>
<p>TBD</p>
</div>
<div class="section" id="explanation-draft">
<h2>Explanation (Draft)<a class="headerlink" href="#explanation-draft" title="Permalink to this headline"></a></h2>
<div class="section" id="attribute-aggegrator-module">
<h3>Attribute aggegrator module<a class="headerlink" href="#attribute-aggegrator-module" title="Permalink to this headline"></a></h3>
<p>The core attribute management is based on the attribute aggregator module.</p>
<div class="section" id="intro">
<h4>Intro<a class="headerlink" href="#intro" title="Permalink to this headline"></a></h4>
<p>Attribute aggregator provides a main Model class called UserAttributeProfile,
functions to load attributes and extract attributes.</p>
<p>The mapping between attribute namespaces is built-in and depends on a unique
file (mapping.py).</p>
<p>A main schema is defined and is based on LDAP/X500 for naming. The support
of <a class="reference external" href="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">http://schemas.xmlsoap.org/ws/2005/05/identity/claims</a> is partly complete.</p>
<p>Source of attributes are connected with attribute loading functions using
signals.</p>
</div>
<div class="section" id="faq">
<h4>FAQ<a class="headerlink" href="#faq" title="Permalink to this headline"></a></h4>
<p>Why not use the Django User profile?</p>
<p>The django user profile needs to define attributes as class attributes and
then support form filling or mapping with LDAP.</p>
<p>That is useful and may be used, especially because the profile can be used as
a source of attribute to load in the attribute_aggregator profile.</p>
<p>The attribute_aggregator profile allow to load multivalued attributes from any
source supported (LDAP, Django profile and attributes in Django session for
now) from any namespace defined in mapping.py (LDAP/X500 and claims for now).</p>
<p>The profile can be loaded giving a source or a list of attribute, or can be
from any known source, or with a dictionnary.</p>
<p>Attributes can be extracted with many functions in any namespace supported.</p>
</div>
<div class="section" id="quick-explanation">
<h4>Quick explanation<a class="headerlink" href="#quick-explanation" title="Permalink to this headline"></a></h4>
<p>The schema is defined in mapping.py and is made of definitions like this:</p>
<div class="highlight-python"><pre>"sn": {
"oid": "2.5.4.4",
"display_name": _("sn surname"),
"alias": ['surname'],
"profile_field_name": 'last_name',
"type": "http://www.w3.org/2001/XMLSchema#string",
"namespaces": {
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims": {
"identifiers":
[
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
],
"friendly_names":
[
"Last Name",
],
}
}
},</pre>
</div>
<p>The profile store all the data in a text field taht contains a cPickle list of
instances of the class AttributeData.</p>
<p>The profile is attached to a user and then can be created or loaded with:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">profile</span> <span class="o">=</span> <span class="n">load_or_create_user_profile</span><span class="p">(</span><span class="n">user</span><span class="o">=</span><span class="n">user</span><span class="p">)</span>
</pre></div>
</div>
<p>User may be None to create a temporary profile for an anonymous user. But
that need a DB cleaning function not implemented.</p>
</div>
<div class="section" id="the-model-userattributeprofile">
<h4>The model <em>UserAttributeProfile</em><a class="headerlink" href="#the-model-userattributeprofile" title="Permalink to this headline"></a></h4>
<p>The model &#8216;UserAttributeProfile&#8217; can be attached to a user and then persist
(as a Model).</p>
<p>When the profile is loaded, all data stored are removed expect if the
the data has an expiration date later.</p>
<p>The profile provide several methods to store and extract attributes.</p>
<p>All the methods to add attributes are based on a main one accepting a
dictionnary of attribute is parameters &#8216;load_by_dic()&#8217;. The other methods
(&#8216;load_listed_attributes()&#8217;, &#8216;load_greedy()&#8217;) send a signal with a list of
attributes (listed_attributes_call) or not (any_attributes_call) to grab a
dictionnary. The list is given with the definition name, oid or friendly name
of the attribute in the system namespace.</p>
<p>Into the dictionnary, attributes are given with their name, oid or friendly
name in the default namespace or with their name in a namepsace. An expiration
date can also be given (ISO8601 format), if none, attribute will be deleted at
next profile loading. The dictionnary format is as follows:</p>
<div class="highlight-python"><pre>attributes = dict()
data_from_source = list()
a1 = dict()
a1['oid'] = definition_name
Or
a1['definition'] = definition_name
definition may be the definition name like 'gn'
or an alias like 'givenName'
Or
a1['name'] = attribute_name_in_ns
a1['namespace'] = ns_name
a1['expiration_date'] = date
a1['values'] = list_of_values
data_from_source.append(a1)
...
data_from_source.append(a2)
attributes[source_name] = data_from_source</pre>
</div>
<p>Getters are defined to extract data from a profile. Only AttributeData
instances are extracted that assume that any attribute namespace can be used.</p>
<ul class="simple">
<li>get_data_of_definition(definition)</li>
</ul>
<p>Return a list of AttributeData instances corresponding to the definition
given.</p>
<ul class="simple">
<li>get_freshest_data_of_definition(definition)</li>
</ul>
<p>Return the freshest AttributeData instance. If multiple with no or same exp
date, random. Should use the creation date soon.</p>
<ul class="simple">
<li>get_data_of_source</li>
</ul>
<p>Return a list of AttributeData instances corresponding to the source given.</p>
<ul class="simple">
<li>get_data_of_source_by_name</li>
</ul>
<p>Idem but source name is given, not a Source instance.</p>
<ul class="simple">
<li>get_data_of_definition_and_source</li>
</ul>
<p>Return a list of AttributeData instances corresponding to the definition and
source given.</p>
<ul class="simple">
<li>get_data_of_definition_and_source_by_name</li>
</ul>
<p>Idem but source name is given, not a Source instance.</p>
</div>
</div>
<div class="section" id="saml2-attribute-representation-in-assertions">
<h3>SAML2 attribute representation in assertions<a class="headerlink" href="#saml2-attribute-representation-in-assertions" title="Permalink to this headline"></a></h3>
<p>SAML2 attribute profile (saml-profiles-2.0-os - Section 8) defines two kind of
attribute element syntax in the attribute statement of assertions, also
called <em>name format</em>:</p>
<ul>
<li><p class="first">BASIC:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">NameFormat</span><span class="o">=</span><span class="s">&quot;urn:oasis:names:tc:SAML:2.0:attrname-format:basic&quot;</span>
</pre></div>
</div>
</li>
<li><p class="first">URI:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">NameFormat</span><span class="o">=</span><span class="s">&quot;urn:oasis:names:tc:SAML:2.0:attrname-format:uri&quot;</span>
</pre></div>
</div>
</li>
</ul>
<p><em>URI should be used when attributes have &#8220;universally&#8221; known unique names
like OID.</em></p>
<p>Example:</p>
<div class="highlight-python"><pre>&lt;saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
Name="FirstName"&gt;
&lt;saml:AttributeValue xsi:type="xs:string"&gt;By-Tor&lt;/saml:AttributeValue&gt;
&lt;/saml:Attribute&gt;
&lt;saml:Attribute
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:2.5.4.42" FriendlyName="givenName"&gt;
&lt;saml:AttributeValue xsi:type="xs:string"
x500:Encoding="LDAP"&gt;Steven&lt;/saml:AttributeValue&gt;
&lt;/saml:Attribute&gt;</pre>
</div>
<div class="section" id="basic">
<h4>BASIC<a class="headerlink" href="#basic" title="Permalink to this headline"></a></h4>
<p>Two &lt;Attribute&gt; elements refer to the same SAML attribute if and only if the
values of their Name XML attributes are equal in the sense of Section 3.3.6 of
[Schema2].</p>
<p>No additional XML attributes are defined for use with the &lt;Attribute&gt; element.</p>
<p>The schema type of the contents of the &lt;AttributeValue&gt; element MUST be drawn
from one of the types defined in Section 3.3 of [Schema2]. The xsi:type
attribute MUST be present and be given the appropriate value.</p>
</div>
<div class="section" id="x-500-ldap-attribute-profile-uri">
<h4>X.500/LDAP Attribute Profile (URI)<a class="headerlink" href="#x-500-ldap-attribute-profile-uri" title="Permalink to this headline"></a></h4>
<p><strong>Extracted from the SAML2 core specifications</strong></p>
<p>Two &lt;Attribute&gt; elements refer to the same SAML attribute if and only if their
Name XML attribute values are equal in the sense of [RFC3061]. The
FriendlyName attribute plays no role in the comparison.</p>
<p>Directory attribute type definitions for use in native X.500 directories
specify the syntax of the attribute using ASN.1 [ASN.1]. For use in LDAP,
directory attribute definitions additionally include an LDAP syntax which
specifies how attribute or assertion values conforming to the syntax are to be
represented when transferred in the LDAP protocol (known as an LDAP-specific
encoding). The LDAP-specific encoding commonly produces Unicode characters in
UTF-8 form. This SAML attribute profile specifies the form of SAML attribute
values only for those directory attributes which have LDAP syntaxes. Future
extensions to this profile may define attribute value formats for directory
attributes whose syntaxes specify other encodings.</p>
<p>To represent the encoding rules in use for a particular attribute value, the
&lt;AttributeValue&gt; element MUST contain an XML attribute named Encoding defined
in the XML namespace <a class="reference external" href="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500">urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500</a>.</p>
<p>For any directory attribute with a syntax whose LDAP-specific encoding
exclusively produces UTF-8 character strings as values, the SAML attribute
value is encoded as simply the UTF-8 string itself, as the content of the
&lt;AttributeValue&gt; element, with no additional whitespace.
In such cases, the xsi:type XML attribute MUST be set to xs:string.
The profile-specific Encoding XML attribute is provided, with a value of LDAP.</p>
<p>The AttributeData instances have a field expiration_data. It the profile
exists, obsolete data are removed at loading.</p>
</div>
</div>
<div class="section" id="when-authentic-2-deals-with-attributes-and-needs-mapping">
<h3>When authentic 2 deals with attributes and needs mapping?<a class="headerlink" href="#when-authentic-2-deals-with-attributes-and-needs-mapping" title="Permalink to this headline"></a></h3>
<p>Authentic2 behaves as an attribute provider:
* At the SSO login
* When an attribute request is received</p>
<p>Authentic requests (e.g. by soap) are not yet supported.</p>
<div class="section" id="when-authentic2-behaves-as-an-attribute-provider-at-sso-login">
<h4>When Authentic2 behaves as an attribute provider at SSO login<a class="headerlink" href="#when-authentic2-behaves-as-an-attribute-provider-at-sso-login" title="Permalink to this headline"></a></h4>
<p>At a SSO request, just before responding to the service provider, the saml2
idp module sends the signal &#8216;add_attributes_to_response&#8217; giving the SP entity
ID.</p>
<p>The signal is connected to the function &#8216;provide_attributes_at_sso()&#8217; in
charge of providing the attributes at the SSO for this SP.</p>
<p><strong>Attributes sources are of two kinds. The first ones are the sources that can
be requested by the IdP with a syncrhonous binding without user intercations.
These sources are called pull sources. They are for now limited to LDAP
sources. The other ones are sources are asyncrhonous bindings, usually
requiring user interactions. These sources are called push sources. They are
now limited to the attributes provided at SSO requests when the IdP acts as a
SAML2 SP. There attributes are put/found in the Django session.</strong></p>
<p>Each source in the system is declared with an instance of the AttributeSource
model. We&#8217;ll see later that to forward attributes of push sources it is not
necessary that a source is declared in some circumstances.</p>
<p>To manage these sources an attribute policy is attached to services providers.
Then the service provider model must be extended with a attribute
attributes_at_sso_policy. The service provider must send the signal
&#8216;add_attributes_to_response&#8217;.</p>
<p>The implementation is actually done for SAML2 providers.</p>
<p><strong>In such a policy attributes from pull and push sources are treated
differently.</strong></p>
<p><strong>For pull sources, a list of attributes is indicated. Either an attribute is
searched in all the pull sources and whatever attribute value found is
returned. Or each attribute is indicated with a source. With each attribute is
indicated the output format and namespace.</strong></p>
<p><strong>The policy may also indicate that all the attributes in the Django session
must be forwarded. Then, no AttributeSource instance is required. All the
attributes are then forwarded without treating input namespace considerations.
When an AttributeSource instance is found, the input namespace of this source
is considered. An option can then be set to tell that the output format and
namespace must be taken. A list of attribute can also be given.
This list can be use to filter attributes to forward without or without taking
care of the source. The output namespace and format can also be trated per
attribute.</strong></p>
<p>If the namespace is default, the attribute names will be taken from the
system namespace. In BASIC the name will be the definition name. In URI, the
Name will be the OID in urn format and the friendly name will be the
definition name. If a namespace is given, the first identifier of this
attribute is taken as Name in BASIC. In URI, the same and the first friendly
name is taken.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">LibertyServiceProvider</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="o">...</span>
<span class="n">attribute_policy</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">AttributePolicy</span><span class="p">,</span>
<span class="n">verbose_name</span><span class="o">=</span><span class="n">_</span><span class="p">(</span><span class="s">&quot;Attribute policy&quot;</span><span class="p">),</span> <span class="n">null</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">AttributePolicy</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="c"># List of attributes to provide from pull sources at SSO Login.</span>
<span class="c"># If an attribute is indicate without a source, from any source.</span>
<span class="c"># The output format and namespace is given by each attribute.</span>
<span class="n">attribute_list_for_sso_from_pull_sources</span> <span class="o">=</span> \
<span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">LibertyAttributeMap</span><span class="p">,</span>
<span class="n">related_name</span> <span class="o">=</span> <span class="s">&quot;attributes of pull sources&quot;</span><span class="p">,</span>
<span class="n">blank</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="n">null</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="c"># Set to true for proxying attributes from pull sources at SSO Login.</span>
<span class="c"># Attributes are in session.</span>
<span class="c"># All attributes are forwarded as is except if the parameter</span>
<span class="c"># &#39;attribute_list_for_sso_from_push_sources&#39; is initialized</span>
<span class="n">forward_attributes_from_pull_sources</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="c"># Map attributes in session</span>
<span class="c"># forward_attributes_in_session must be true</span>
<span class="c"># At False, all attributes are forwarded as is</span>
<span class="c"># At true, look for the namespace of the source for input, If not found,</span>
<span class="c"># system namespace. Look for the options attribute_name_format and</span>
<span class="c"># output_namespace of the attribute policy for output.</span>
<span class="n">map_attributes_from_pull_sources</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="c"># ATTRIBUTE_VALUE_FORMATS[0] =&gt;</span>
<span class="c"># (lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC, &#39;SAMLv2 BASIC&#39;)</span>
<span class="n">output_name_format</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span>
<span class="n">choices</span> <span class="o">=</span> <span class="n">ATTRIBUTE_VALUE_FORMATS</span><span class="p">,</span>
<span class="n">default</span> <span class="o">=</span> <span class="n">ATTRIBUTE_VALUE_FORMATS</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="c">#ATTRIBUTES_NS[0] =&gt; (&#39;Default&#39;, &#39;Default&#39;)</span>
<span class="n">output_namespace</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span>
<span class="n">choices</span> <span class="o">=</span> <span class="n">ATTRIBUTES_NS</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">ATTRIBUTES_NS</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="c"># Filter attributes pushed from source.</span>
<span class="n">source_filter_for_sso_from_push_sources</span> <span class="o">=</span> \
<span class="n">models</span><span class="o">.</span><span class="n">ManyToManyField</span><span class="p">(</span><span class="n">AttributeSource</span><span class="p">,</span>
<span class="n">related_name</span> <span class="o">=</span> <span class="s">&quot;attributes of pull sources&quot;</span><span class="p">,</span>
<span class="n">blank</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="n">null</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="c"># List of attributes to filter from pull sources at SSO Login.</span>
<span class="n">attribute_filter_for_sso_from_push_sources</span> <span class="o">=</span> \
<span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">LibertyAttributeMap</span><span class="p">,</span>
<span class="n">related_name</span> <span class="o">=</span> <span class="s">&quot;attributes of pull sources&quot;</span><span class="p">,</span>
<span class="n">blank</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="n">null</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="c"># The sources of attributes of the previous list are considered.</span>
<span class="c"># May be used conjointly with &#39;source_filter_for_sso_from_push_sources&#39;</span>
<span class="n">filter_source_of_filtered_attributes</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="c"># To map the attributes of forwarded attributes with the defaut output</span>
<span class="c"># format and namespace, use &#39;map_attributes_from_pull_sources&#39;</span>
<span class="c"># Use the following option to use the output format and namespace</span>
<span class="c"># indicated for each attribute.</span>
<span class="n">map_attributes_of_filtered_attributes</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="c"># Set to true to take in account missing required attributes</span>
<span class="n">send_error_and_no_attrs_if_missing_required_attrs</span> <span class="o">=</span> \
<span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
<span class="n">verbose_name</span> <span class="o">=</span> <span class="n">_</span><span class="p">(</span><span class="s">&#39;attribute options policy&#39;</span><span class="p">)</span>
<span class="n">verbose_name_plural</span> <span class="o">=</span> <span class="n">_</span><span class="p">(</span><span class="s">&#39;attribute options policies&#39;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">AttributeList</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">40</span><span class="p">,</span> <span class="n">unique</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="n">attributes</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ManyToManyField</span><span class="p">(</span><span class="n">AttributeItem</span><span class="p">,</span>
<span class="n">related_name</span> <span class="o">=</span> <span class="s">&quot;attributes of the list&quot;</span><span class="p">,</span>
<span class="n">blank</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="n">null</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">AttributeItem</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">attribute_name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span> <span class="n">choices</span> <span class="o">=</span> <span class="n">ATTRIBUTES</span><span class="p">,</span>
<span class="n">default</span> <span class="o">=</span> <span class="n">ATTRIBUTES</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="c"># ATTRIBUTE_VALUE_FORMATS[0] =&gt;</span>
<span class="c"># (lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC, &#39;SAMLv2 BASIC&#39;)</span>
<span class="n">output_attribute_name_format</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span>
<span class="n">choices</span> <span class="o">=</span> <span class="n">ATTRIBUTE_VALUE_FORMATS</span><span class="p">,</span>
<span class="n">default</span> <span class="o">=</span> <span class="n">ATTRIBUTE_VALUE_FORMATS</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="c">#ATTRIBUTES_NS[0] =&gt; (&#39;Default&#39;, &#39;Default&#39;)</span>
<span class="n">output_namespace</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span> <span class="o">=</span> <span class="mi">100</span><span class="p">,</span>
<span class="n">choices</span> <span class="o">=</span> <span class="n">ATTRIBUTES_NS</span><span class="p">,</span> <span class="n">default</span> <span class="o">=</span> <span class="n">ATTRIBUTES_NS</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">required</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">source</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">AttributeSource</span><span class="p">,</span> <span class="n">blank</span> <span class="o">=</span> <span class="bp">True</span><span class="p">,</span> <span class="n">null</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>
</pre></div>
</div>
<p>A list of attributes can also be taken from the service provider metadata and
added to &#8216;attribute_list_for_sso_from_pull_sources&#8217;. The namespace may be
extracted from the metadata. This namespace is then used to look for the
corresponding definition and then to provide the attribute in the right
namespace. Read attributes from metadata is not yet supported.</p>
<p>For the attributes of pull sources, once the list of attributes is defined,
They are loaded in the user profile.</p>
<p>As explained before the attribute_aggregator loading function send signals to
grab dictionnary of attributes. Up to know, only the ldap loading function are
connected to these signals. The namespace of LDAP sources is assumed to be
the same as the system namespace. There is here then no mapping needed. Other
kind of sources than LDAP can be defined in attribute aggregator.</p>
<p>To grab attributes from a LDAP the user dn in the LDAP or at least a local
identifier in the LDAP is required. For this purpose, each user has alias
associated with LDAP source. These aliases must their DN in the LDAP. When
the authentication LDAP backend will be taken in account, the dn will be taken
direclty from the user Model instance.</p>
<p>Each LDAP sources are declared with the binding parameters. The LDAP namespace
is always &#8216;Default&#8217;.</p>
<p>If an attribute to load is not found and is required the answer should report
an error (Not yet implemented).</p>
<p>Attributes in response can also be provided with other means than from an LDAP
source. Attributes can be put in the user Django session and then loaded in
the profile. An option of the service provier indicate if attributes in the
session must be provided to the service provider.</p>
<p>To have the attribute loaded from the session, they must be provided in the
session as follows:
request.session[&#8216;attributes&#8217;][source_name] = list()</p>
<p>The source_name must be the name of an existing instance of an
&#8216;AttributeSource&#8217;. Such an instance contains a field namespace indicating the
namespace of attributes.</p>
<p>This is currently implemented only for the SAML2 service provider module of
authentic2. Authsaml2, the SP module, parse the assertion and put the
attributes in the session.</p>
<div class="highlight-python"><pre>if not 'multisource_attributes' in request.session:
request.session['attributes'] = dict{}
request.session['multisource_attributes'] \
[login.assertion.issuer.content] = attributes</pre>
</div>
<p>Then, Authentic2 can be used as a SAML2 proxy forwarding attributes in
assertion, eventually doing a namespace mapping. For this, the option
forward attributes in sesion must be set (by default False).</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Attribute Management in Authentic2</a><ul>
<li><a class="reference internal" href="#summary">Summary</a></li>
<li><a class="reference internal" href="#configuration">Configuration</a><ul>
<li><a class="reference internal" href="#configure-sources-of-attributes">Configure sources of attributes</a><ul>
<li><a class="reference internal" href="#declare-the-django-profile-source">Declare the Django profile source</a></li>
<li><a class="reference internal" href="#add-an-ldap-source">Add an LDAP Source</a></li>
<li><a class="reference internal" href="#manage-user-distinguished-names-in-ldap-directories">Manage user distinguished names in LDAP directories</a></li>
</ul>
</li>
<li><a class="reference internal" href="#configure-attributes-pushed-to-saml2-service-providers-in-sso-response">Configure attributes pushed to SAML2 service providers in SSO response</a><ul>
<li><a class="reference internal" href="#create-attribute-items">Create attribute items</a></li>
<li><a class="reference internal" href="#create-a-named-list-of-attribute-items">Create a named list of attribute items</a></li>
<li><a class="reference internal" href="#create-or-modify-an-attribute-policy">Create or modify an attribute policy</a></li>
<li><a class="reference internal" href="#associate-the-policy-to-a-service-provider">Associate the policy to a service provider</a></li>
</ul>
</li>
<li><a class="reference internal" href="#handle-attributes-provided-by-other-identity-providers-proxy-attributes">Handle attributes provided by other Identity providers, proxy attributes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#modifying-supported-namespaces-and-attribute-name-mappings">Modifying supported namespaces and attribute name mappings</a></li>
<li><a class="reference internal" href="#explanation-draft">Explanation (Draft)</a><ul>
<li><a class="reference internal" href="#attribute-aggegrator-module">Attribute aggegrator module</a><ul>
<li><a class="reference internal" href="#intro">Intro</a></li>
<li><a class="reference internal" href="#faq">FAQ</a></li>
<li><a class="reference internal" href="#quick-explanation">Quick explanation</a></li>
<li><a class="reference internal" href="#the-model-userattributeprofile">The model <em>UserAttributeProfile</em></a></li>
</ul>
</li>
<li><a class="reference internal" href="#saml2-attribute-representation-in-assertions">SAML2 attribute representation in assertions</a><ul>
<li><a class="reference internal" href="#basic">BASIC</a></li>
<li><a class="reference internal" href="#x-500-ldap-attribute-profile-uri">X.500/LDAP Attribute Profile (URI)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#when-authentic-2-deals-with-attributes-and-needs-mapping">When authentic 2 deals with attributes and needs mapping?</a><ul>
<li><a class="reference internal" href="#when-authentic2-behaves-as-an-attribute-provider-at-sso-login">When Authentic2 behaves as an attribute provider at SSO login</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="config_cas_idp.html"
title="previous chapter">Configure Authentic2 as a CAS client</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/attribute_management.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="config_cas_idp.html" title="Configure Authentic2 as a CAS client"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

178
doc/_build/html/auth_ldap.html vendored Normal file
View File

@ -0,0 +1,178 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Authentication with an existing LDAP directory &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="next" title="Authentication on Authentic2 with PAM" href="auth_pam.html" />
<link rel="prev" title="Installation" href="installation.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="auth_pam.html" title="Authentication on Authentic2 with PAM"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="installation.html" title="Installation"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="authentication-with-an-existing-ldap-directory">
<span id="auth-ldap"></span><h1>Authentication with an existing LDAP directory<a class="headerlink" href="#authentication-with-an-existing-ldap-directory" title="Permalink to this headline"></a></h1>
<p>Authentic use the module django_auth_ldap to synchronize the Django user tables
with an LDAP. For complex use case, we will refer you to the django_auth_ldap
documentation, see <a class="reference external" href="http://packages.python.org/django-auth-ldap/">http://packages.python.org/django-auth-ldap/</a>.</p>
<div class="section" id="how-to-authenticate-users-against-an-ldap-server-with-anonymous-binding">
<h2>How to authenticate users against an LDAP server with anonymous binding ?<a class="headerlink" href="#how-to-authenticate-users-against-an-ldap-server-with-anonymous-binding" title="Permalink to this headline"></a></h2>
<ol class="arabic">
<li><p class="first">Install the django_auth_ldap module for Django:</p>
<div class="highlight-python"><pre>pip install django_auth_ldap</pre>
</div>
</li>
<li><p class="first">Configure your local_settings.py file for authenticating against LDAP.</p>
</li>
</ol>
<p>The next lines must be added:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">AUTHENTICATION_BACKENDS</span> <span class="o">+=</span> <span class="p">(</span> <span class="s">&#39;django_auth_ldap.backend.LDAPBackend&#39;</span><span class="p">,</span> <span class="p">)</span>
<span class="kn">import</span> <span class="nn">ldap</span>
<span class="kn">from</span> <span class="nn">django_auth_ldap.config</span> <span class="kn">import</span> <span class="n">LDAPSearch</span>
<span class="c"># Here put the LDAP URL of your server</span>
<span class="n">AUTH_LDAP_SERVER_URI</span> <span class="o">=</span> <span class="s">&#39;ldap://ldap.example.com&#39;</span>
<span class="c"># Let the bind DN and bind password blank for anonymous binding</span>
<span class="n">AUTH_LDAP_BIND_DN</span> <span class="o">=</span> <span class="s">&quot;&quot;</span>
<span class="n">AUTH_LDAP_BIND_PASSWORD</span> <span class="o">=</span> <span class="s">&quot;&quot;</span>
<span class="c"># Lookup user under the branch o=base and by mathcing their uid against the</span>
<span class="c"># received login name</span>
<span class="n">AUTH_LDAP_USER_SEARCH</span> <span class="o">=</span> <span class="n">LDAPSearch</span><span class="p">(</span><span class="s">&quot;o=base&quot;</span><span class="p">,</span>
<span class="n">ldap</span><span class="o">.</span><span class="n">SCOPE_SUBTREE</span><span class="p">,</span> <span class="s">&quot;(uid=</span><span class="si">%(user)s</span><span class="s">)&quot;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="how-to-allow-members-of-an-ldap-group-to-manage-authentic">
<h2>How to allow members of an LDAP group to manage Authentic ?<a class="headerlink" href="#how-to-allow-members-of-an-ldap-group-to-manage-authentic" title="Permalink to this headline"></a></h2>
<ol class="arabic">
<li><p class="first">First you must know the objectClass of groups in your LDAP schema, this FAQ
will show you the configuration for two usual classes: groupOfNames and
groupOfUniqueNames.</p>
</li>
<li><p class="first">Find the relevant groupname. We will say it is: cn=admin,o=mycompany</p>
</li>
<li><p class="first">Add the following lines:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">django_auth_ldap.config</span> <span class="kn">import</span> <span class="n">GroupOfNamesType</span>
<span class="n">AUTH_LDAP_GROUP_TYPE</span> <span class="o">=</span> <span class="n">GroupOfNamesType</span><span class="p">()</span>
<span class="n">AUTH_LDAP_GROUP_SEARCH</span> <span class="o">=</span> <span class="n">LDAPSearch</span><span class="p">(</span><span class="s">&quot;o=mycompany&quot;</span><span class="p">,</span>
<span class="n">ldap</span><span class="o">.</span><span class="n">SCOPE_SUBTREE</span><span class="p">,</span> <span class="s">&quot;(objectClass=groupOfNames)&quot;</span><span class="p">)</span>
<span class="n">AUTH_LDAP_USER_FLAGS_BY_GROUP</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">&quot;is_staff&quot;</span><span class="p">:</span> <span class="s">&quot;cn=admin,o=mycompany&quot;</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
</ol>
<p>For an objectClass of groupOfUniqueNames you would change the string
GroupOfNamesType to GroupOfUniqueNamesType and grouOfNames to
groupOfUniqueNames. For more complex cases see the django_auth_ldap
documentation.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Authentication with an existing LDAP directory</a><ul>
<li><a class="reference internal" href="#how-to-authenticate-users-against-an-ldap-server-with-anonymous-binding">How to authenticate users against an LDAP server with anonymous binding ?</a></li>
<li><a class="reference internal" href="#how-to-allow-members-of-an-ldap-group-to-manage-authentic">How to allow members of an LDAP group to manage Authentic ?</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="installation.html"
title="previous chapter">Installation</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="auth_pam.html"
title="next chapter">Authentication on Authentic2 with PAM</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/auth_ldap.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="auth_pam.html" title="Authentication on Authentic2 with PAM"
>next</a> |</li>
<li class="right" >
<a href="installation.html" title="Installation"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

129
doc/_build/html/auth_pam.html vendored Normal file
View File

@ -0,0 +1,129 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Authentication on Authentic2 with PAM &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="next" title="Configure SAML 2.0 service providers" href="config_saml2_sp.html" />
<link rel="prev" title="Authentication with an existing LDAP directory" href="auth_ldap.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="config_saml2_sp.html" title="Configure SAML 2.0 service providers"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="auth_ldap.html" title="Authentication with an existing LDAP directory"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="authentication-on-authentic2-with-pam">
<span id="auth-pam"></span><h1>Authentication on Authentic2 with PAM<a class="headerlink" href="#authentication-on-authentic2-with-pam" title="Permalink to this headline"></a></h1>
<p>This module is copied from <a class="reference external" href="https://bitbucket.org/wnielson/django-pam/">https://bitbucket.org/wnielson/django-pam/</a> by Weston
Nielson and the pam ctype module by Chris Atlee <a class="reference external" href="http://atlee.ca/software/pam/">http://atlee.ca/software/pam/</a>.</p>
<p>Add &#8216;authentic2.vendor.dpam.backends.PAMBackend&#8217; to your
<tt class="docutils literal"><span class="pre">settings.py</span></tt>:</p>
<div class="highlight-python"><pre>AUTHENTICATION_BACKENDS = (
...
'authentic2.vendor.dpam.backends.PAMBackend',
...
)</pre>
</div>
<p>Now you can login via the system-login credentials. If the user is
successfully authenticated but has never logged-in before, a new <tt class="docutils literal"><span class="pre">User</span></tt>
object is created. By default this new <tt class="docutils literal"><span class="pre">User</span></tt> has both <tt class="docutils literal"><span class="pre">is_staff</span></tt> and
<tt class="docutils literal"><span class="pre">is_superuser</span></tt> set to <tt class="docutils literal"><span class="pre">False</span></tt>. You can change this behavior by adding
<tt class="docutils literal"><span class="pre">PAM_IS_STAFF=True</span></tt> and <tt class="docutils literal"><span class="pre">PAM_IS_SUPERUSER</span></tt> in your <tt class="docutils literal"><span class="pre">settings.py</span></tt> file.</p>
<p>The default PAM service used is <tt class="docutils literal"><span class="pre">login</span></tt> but you can change it by setting the
<tt class="docutils literal"><span class="pre">PAM_SERVICE</span></tt> variable in your <tt class="docutils literal"><span class="pre">settings.py</span></tt> file.</p>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h4>Previous topic</h4>
<p class="topless"><a href="auth_ldap.html"
title="previous chapter">Authentication with an existing LDAP directory</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="config_saml2_sp.html"
title="next chapter">Configure SAML 2.0 service providers</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/auth_pam.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="config_saml2_sp.html" title="Configure SAML 2.0 service providers"
>next</a> |</li>
<li class="right" >
<a href="auth_ldap.html" title="Authentication with an existing LDAP directory"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

112
doc/_build/html/config_cas_idp.html vendored Normal file
View File

@ -0,0 +1,112 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Configure Authentic2 as a CAS client &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="next" title="Attribute Management in Authentic2" href="attribute_management.html" />
<link rel="prev" title="Configure Authentic2 as a CAS server" href="config_cas_sp.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="attribute_management.html" title="Attribute Management in Authentic2"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="config_cas_sp.html" title="Configure Authentic2 as a CAS server"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="configure-authentic2-as-a-cas-client">
<span id="config-cas-idp"></span><h1>Configure Authentic2 as a CAS client<a class="headerlink" href="#configure-authentic2-as-a-cas-client" title="Permalink to this headline"></a></h1>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h4>Previous topic</h4>
<p class="topless"><a href="config_cas_sp.html"
title="previous chapter">Configure Authentic2 as a CAS server</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="attribute_management.html"
title="next chapter">Attribute Management in Authentic2</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/config_cas_idp.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="attribute_management.html" title="Attribute Management in Authentic2"
>next</a> |</li>
<li class="right" >
<a href="config_cas_sp.html" title="Configure Authentic2 as a CAS server"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

147
doc/_build/html/config_cas_sp.html vendored Normal file
View File

@ -0,0 +1,147 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Configure Authentic2 as a CAS server &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="next" title="Configure Authentic2 as a CAS client" href="config_cas_idp.html" />
<link rel="prev" title="Configure Authentic2 as a SAML2 service provider" href="config_saml2_idp.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="config_cas_idp.html" title="Configure Authentic2 as a CAS client"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="config_saml2_idp.html" title="Configure Authentic2 as a SAML2 service provider"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="configure-authentic2-as-a-cas-server">
<span id="config-cas-sp"></span><h1>Configure Authentic2 as a CAS server<a class="headerlink" href="#configure-authentic2-as-a-cas-server" title="Permalink to this headline"></a></h1>
<div class="section" id="how-to-use-authentic2-as-a-cas-1-0-or-cas-2-0-identity-provider">
<h2>How to use Authentic2 as a CAS 1.0 or CAS 2.0 identity provider ?<a class="headerlink" href="#how-to-use-authentic2-as-a-cas-1-0-or-cas-2-0-identity-provider" title="Permalink to this headline"></a></h2>
<ol class="arabic">
<li><p class="first">Activate CAS IdP support in settings.py:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">IDP_CAS</span> <span class="o">=</span> <span class="bp">True</span>
</pre></div>
</div>
</li>
<li><p class="first">Then create the database table to hold CAS service tickets:</p>
<div class="highlight-python"><pre>python authentic2/manage.py syncdb --migrate</pre>
</div>
</li>
<li><p class="first">Also configure authentic2 to authenticate against your LDAP directory (see
above) if your want your user attributes to be accessible from your service,
if it is not necessary you can use the normal relational database storage
for you users.</p>
</li>
<li><p class="first">Finally configure your service to point to the CAS endpoint at:</p>
<blockquote>
<div><p>http[s]://your.domain.com/idp/cas/</p>
</div></blockquote>
</li>
<li><p class="first">If needed configure your service to resolve authenticated user with your
LDAP directory (if user attributes are needed for your service)</p>
</li>
</ol>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Configure Authentic2 as a CAS server</a><ul>
<li><a class="reference internal" href="#how-to-use-authentic2-as-a-cas-1-0-or-cas-2-0-identity-provider">How to use Authentic2 as a CAS 1.0 or CAS 2.0 identity provider ?</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="config_saml2_idp.html"
title="previous chapter">Configure Authentic2 as a SAML2 service provider</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="config_cas_idp.html"
title="next chapter">Configure Authentic2 as a CAS client</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/config_cas_sp.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="config_cas_idp.html" title="Configure Authentic2 as a CAS client"
>next</a> |</li>
<li class="right" >
<a href="config_saml2_idp.html" title="Configure Authentic2 as a SAML2 service provider"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

117
doc/_build/html/config_saml2_idp.html vendored Normal file
View File

@ -0,0 +1,117 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Configure Authentic2 as a SAML2 service provider or a SAML2 proxy &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="next" title="Configure Authentic2 as a CAS server" href="config_cas_sp.html" />
<link rel="prev" title="Configure SAML 2.0 service providers" href="config_saml2_sp.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="config_cas_sp.html" title="Configure Authentic2 as a CAS server"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="config_saml2_sp.html" title="Configure SAML 2.0 service providers"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="configure-authentic2-as-a-saml2-service-provider-or-a-saml2-proxy">
<span id="config-saml2-idp"></span><h1>Configure Authentic2 as a SAML2 service provider or a SAML2 proxy<a class="headerlink" href="#configure-authentic2-as-a-saml2-service-provider-or-a-saml2-proxy" title="Permalink to this headline"></a></h1>
<ol class="arabic simple">
<li>Create instance of SP settings</li>
<li>Declare IdP</li>
<li>Get authsaml2 md</li>
</ol>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h4>Previous topic</h4>
<p class="topless"><a href="config_saml2_sp.html"
title="previous chapter">Configure SAML 2.0 service providers</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="config_cas_sp.html"
title="next chapter">Configure Authentic2 as a CAS server</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/config_saml2_idp.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="config_cas_sp.html" title="Configure Authentic2 as a CAS server"
>next</a> |</li>
<li class="right" >
<a href="config_saml2_sp.html" title="Configure SAML 2.0 service providers"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

140
doc/_build/html/config_saml2_sp.html vendored Normal file
View File

@ -0,0 +1,140 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Configure SAML 2.0 service providers &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="next" title="Configure Authentic2 as a SAML2 service provider" href="config_saml2_idp.html" />
<link rel="prev" title="Authentication on Authentic2 with PAM" href="auth_pam.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="config_saml2_idp.html" title="Configure Authentic2 as a SAML2 service provider"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="auth_pam.html" title="Authentication on Authentic2 with PAM"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="configure-saml-2-0-service-providers">
<span id="config-saml2-sp"></span><h1>Configure SAML 2.0 service providers<a class="headerlink" href="#configure-saml-2-0-service-providers" title="Permalink to this headline"></a></h1>
<div class="section" id="how-to-i-authenticate-against-authentic2-with-a-samlv2-service-provider">
<h2>How to I authenticate against Authentic2 with a SAMLv2 service provider ?<a class="headerlink" href="#how-to-i-authenticate-against-authentic2-with-a-samlv2-service-provider" title="Permalink to this headline"></a></h2>
<ol class="arabic">
<li><p class="first">Grab the SAML2 IdP metadata:</p>
<blockquote>
<div><p>http[s]://your.domain.com/idp/saml2/metadata</p>
</div></blockquote>
</li>
<li><p class="first">And configure your service provider with it.</p>
</li>
<li><p class="first">Go to the providers admin panel on:</p>
<blockquote>
<div><p>http[s]://your.domain.com/admin/saml/libertyprovider/add/</p>
</div></blockquote>
</li>
</ol>
<p>There create a new provider using the service provider metadata and enable it
as a service provider, you can customize some behaviours like the preferred
assertion consumer or encryption for the NameID or the Assertion element.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Configure SAML 2.0 service providers</a><ul>
<li><a class="reference internal" href="#how-to-i-authenticate-against-authentic2-with-a-samlv2-service-provider">How to I authenticate against Authentic2 with a SAMLv2 service provider ?</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="auth_pam.html"
title="previous chapter">Authentication on Authentic2 with PAM</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="config_saml2_idp.html"
title="next chapter">Configure Authentic2 as a SAML2 service provider</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/config_saml2_sp.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="config_saml2_idp.html" title="Configure Authentic2 as a SAML2 service provider"
>next</a> |</li>
<li class="right" >
<a href="auth_pam.html" title="Authentication on Authentic2 with PAM"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

117
doc/_build/html/download.html vendored Normal file
View File

@ -0,0 +1,117 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Download &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="next" title="Installation" href="installation.html" />
<link rel="prev" title="Features" href="features.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="installation.html" title="Installation"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="features.html" title="Features"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="download">
<span id="id1"></span><h1>Download<a class="headerlink" href="#download" title="Permalink to this headline"></a></h1>
<ol class="arabic simple">
<li>Pypi: <a class="reference external" href="http://pypi.python.org/pypi/authentic2/1.9.0">http://pypi.python.org/pypi/authentic2/1.9.0</a></li>
<li>Git repository: <a class="reference external" href="http://repos.entrouvert.org/authentic.git">http://repos.entrouvert.org/authentic.git</a></li>
<li><a class="reference external" href="http://dev.entrouvert.org/projects/authentic/repository">Browse source</a></li>
</ol>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h4>Previous topic</h4>
<p class="topless"><a href="features.html"
title="previous chapter">Features</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="installation.html"
title="next chapter">Installation</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/download.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="installation.html" title="Installation"
>next</a> |</li>
<li class="right" >
<a href="features.html" title="Features"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

128
doc/_build/html/features.html vendored Normal file
View File

@ -0,0 +1,128 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Features &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="next" title="Installation" href="installation.html" />
<link rel="prev" title="Authentic2s documentation" href="index.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="installation.html" title="Installation"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="index.html" title="Authentic2s documentation"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="features">
<span id="id1"></span><h1>Features<a class="headerlink" href="#features" title="Permalink to this headline"></a></h1>
<p>Authentic can authenticate users against:</p>
<ul class="simple">
<li>an LDAP directory,</li>
<li>a SAML 2.0 identity provider,</li>
<li>an OpenID identity provider,</li>
<li>with an X509 certificate.</li>
</ul>
<p>Authentic can provide authentication to web applications using the following
protocols:</p>
<ul class="simple">
<li>OpenID,</li>
<li>SAML 2.0,</li>
<li>CAS 1.0 &amp; CAS 2.0.</li>
</ul>
<p>Authentic can proxy authentication between any two different protocols it
support.</p>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h4>Previous topic</h4>
<p class="topless"><a href="index.html"
title="previous chapter">Authentic2&#8217;s documentation</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="installation.html"
title="next chapter">Installation</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/features.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="installation.html" title="Installation"
>next</a> |</li>
<li class="right" >
<a href="index.html" title="Authentic2s documentation"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

95
doc/_build/html/genindex.html vendored Normal file
View File

@ -0,0 +1,95 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Index &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="#" title="General Index"
accesskey="I">index</a></li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<h1 id="index">Index</h1>
<div class="genindex-jumpbox">
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="#" title="General Index"
>index</a></li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

176
doc/_build/html/index.html vendored Normal file
View File

@ -0,0 +1,176 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Authentic2s documentation &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="#" />
<link rel="next" title="Features" href="features.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="features.html" title="Features"
accesskey="N">next</a> |</li>
<li><a href="#">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="authentic2-s-documentation">
<h1>Authentic2&#8217;s documentation<a class="headerlink" href="#authentic2-s-documentation" title="Permalink to this headline"></a></h1>
<p>Authentic2 is a versatile identity provider addressing a broad
range of needs, from simple to advanced setups, around web authentication,
attribute sharing, namespace mapping and authorization management.</p>
<p>Authentic2 supports many protocols and standards, including SAML2, CAS, OpenID,
LDAP, X509, OATH, and can bridge between them.</p>
<p>Authentic2 is under the GNU AGPL version 3 licence.</p>
<p>It has support for SAMLv2 thanks to <a class="reference external" href="http://lasso.entrouvert.org">Lasso</a>,
a free (GNU GPL) implementation of the Liberty Alliance and OASIS
specifications of SAML2, ID-FF1.2 and ID-WSF2.</p>
<ul class="simple">
<li><a class="reference external" href="http://dev.entrouvert.org/projects/authentic">Authentic2 project site</a></li>
<li><a class="reference external" href="http://dev.entrouvert.org/projects/authentic/roadmap">Authentic2 roadmap</a></li>
</ul>
<div class="section" id="documentation-content">
<h2>Documentation content<a class="headerlink" href="#documentation-content" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="features.html">Features</a></li>
<li class="toctree-l1"><a class="reference internal" href="download.html">Download</a></li>
<li class="toctree-l1"><a class="reference internal" href="installation.html">Installation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="installation.html#dependencies">Dependencies</a></li>
<li class="toctree-l2"><a class="reference internal" href="installation.html#quick-start">Quick Start</a></li>
<li class="toctree-l2"><a class="reference internal" href="installation.html#specifying-a-different-database">Specifying a different database</a></li>
<li class="toctree-l2"><a class="reference internal" href="installation.html#how-to-upgrade-to-a-new-version-of-authentic">How to upgrade to a new version of authentic ?</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="auth_ldap.html">Authentication with an existing LDAP directory</a><ul>
<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html#how-to-authenticate-users-against-an-ldap-server-with-anonymous-binding">How to authenticate users against an LDAP server with anonymous binding ?</a></li>
<li class="toctree-l2"><a class="reference internal" href="auth_ldap.html#how-to-allow-members-of-an-ldap-group-to-manage-authentic">How to allow members of an LDAP group to manage Authentic ?</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="auth_pam.html">Authentication on Authentic2 with PAM</a></li>
<li class="toctree-l1"><a class="reference internal" href="config_saml2_sp.html">Configure SAML 2.0 service providers</a><ul>
<li class="toctree-l2"><a class="reference internal" href="config_saml2_sp.html#how-to-i-authenticate-against-authentic2-with-a-samlv2-service-provider">How to I authenticate against Authentic2 with a SAMLv2 service provider ?</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="config_saml2_idp.html">Configure Authentic2 as a SAML2 service provider or a SAML2 proxy</a></li>
<li class="toctree-l1"><a class="reference internal" href="config_cas_sp.html">Configure Authentic2 as a CAS server</a><ul>
<li class="toctree-l2"><a class="reference internal" href="config_cas_sp.html#how-to-use-authentic2-as-a-cas-1-0-or-cas-2-0-identity-provider">How to use Authentic2 as a CAS 1.0 or CAS 2.0 identity provider ?</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="config_cas_idp.html">Configure Authentic2 as a CAS client</a></li>
<li class="toctree-l1"><a class="reference internal" href="attribute_management.html">Attribute Management in Authentic2</a><ul>
<li class="toctree-l2"><a class="reference internal" href="attribute_management.html#summary">Summary</a></li>
<li class="toctree-l2"><a class="reference internal" href="attribute_management.html#configuration">Configuration</a></li>
<li class="toctree-l2"><a class="reference internal" href="attribute_management.html#modifying-supported-namespaces-and-attribute-name-mappings">Modifying supported namespaces and attribute name mappings</a></li>
<li class="toctree-l2"><a class="reference internal" href="attribute_management.html#explanation-draft">Explanation (Draft)</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="section" id="copyright">
<h2>Copyright<a class="headerlink" href="#copyright" title="Permalink to this headline"></a></h2>
<p>Authentic is copyrighted by Entr&#8217;ouvert and is licensed through the GNU General
Public Licence, version 2 or later. A copy of the whole license text is
available in the COPYING file.</p>
<p>The OpenID IdP originates in the project django_openid_provider by Roman
Barczy¿ski, which is under the Apache 2.0 licence. This imply that you must
distribute authentic2 under the AGPL3 licence when distributing this part of the
project which is the only AGPL licence version compatible with the Apache 2.0
licence.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="#">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Authentic2&#8217;s documentation</a><ul>
<li><a class="reference internal" href="#documentation-content">Documentation content</a><ul>
</ul>
</li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</li>
</ul>
<h4>Next topic</h4>
<p class="topless"><a href="features.html"
title="next chapter">Features</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/index.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="features.html" title="Features"
>next</a> |</li>
<li><a href="#">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

217
doc/_build/html/installation.html vendored Normal file
View File

@ -0,0 +1,217 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Installation &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<link rel="next" title="Attribute Management in Authentic2" href="attribute_management.html" />
<link rel="prev" title="Features" href="features.html" />
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="attribute_management.html" title="Attribute Management in Authentic2"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="features.html" title="Features"
accesskey="P">previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<div class="section" id="installation">
<span id="id1"></span><h1>Installation<a class="headerlink" href="#installation" title="Permalink to this headline"></a></h1>
<div class="section" id="dependencies">
<h2>Dependencies<a class="headerlink" href="#dependencies" title="Permalink to this headline"></a></h2>
<p>You must install the following packages to use Authentic</p>
<ul>
<li><p class="first">Python Lasso binding 2.3.5:</p>
<blockquote>
<div><p>From sources: <a class="reference external" href="http://lasso.entrouvert.org/download">http://lasso.entrouvert.org/download</a>
Debian based distribution: apt-get install python-lasso</p>
</div></blockquote>
</li>
<li><p class="first">Django 1.3:</p>
<blockquote>
<div><p>From sources: <a class="reference external" href="http://www.djangoproject.com/download/1.3/tarball/">http://www.djangoproject.com/download/1.3/tarball/</a></p>
</div></blockquote>
</li>
<li><p class="first">Django-registration 0.8-alpha-1:</p>
<blockquote>
<div><p>From sources: <a class="reference external" href="http://bitbucket.org/ubernostrum/django-registration/downloads">http://bitbucket.org/ubernostrum/django-registration/downloads</a>
Debian based distribution: apt-get install python-django-registration</p>
</div></blockquote>
</li>
<li><p class="first">Django-authopenid 0.9.6:</p>
<blockquote>
<div><p>From sources: <a class="reference external" href="http://bitbucket.org/benoitc/django-authopenid/downloads">http://bitbucket.org/benoitc/django-authopenid/downloads</a></p>
</div></blockquote>
</li>
<li><p class="first">Django-south 0.7.3:</p>
<blockquote>
<div><p>From sources:: <a class="reference external" href="http://south.aeracode.org/docs/installation.html">http://south.aeracode.org/docs/installation.html</a></p>
</div></blockquote>
</li>
<li><p class="first">Django-profiles 0.2:</p>
<blockquote>
<div><p>From sources:: <a class="reference external" href="http://pypi.python.org/pypi/django-profiles">http://pypi.python.org/pypi/django-profiles</a></p>
</div></blockquote>
</li>
</ul>
<p>You install all the django libraries quickly using pip:</p>
<div class="highlight-python"><pre>pip install django django-profiles django-registration \
django-debug-toolbar django-authopenid south</pre>
</div>
<p>or easy_install:</p>
<div class="highlight-python"><pre>easy_install django django-profiles django-registration \
django-debug-toolbar django-authopenid south</pre>
</div>
</div>
<div class="section" id="quick-start">
<h2>Quick Start<a class="headerlink" href="#quick-start" title="Permalink to this headline"></a></h2>
<p>Then launch the following commands:</p>
<div class="highlight-python"><pre>python manage.py syncdb --migrate
python manage.py runserver</pre>
</div>
<p>You should see the following output:</p>
<div class="highlight-python"><pre>Validating models...
0 errors found
Django version 1.2, using settings 'authentic.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
You can access the running application on http://127.0.0.1:8000/</pre>
</div>
</div>
<div class="section" id="specifying-a-different-database">
<h2>Specifying a different database<a class="headerlink" href="#specifying-a-different-database" title="Permalink to this headline"></a></h2>
<p>This is done by modifying the DATABASES dictionary in your local_settings.py file
(create it in Authentic project directory); for example:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">DATABASES</span><span class="p">[</span><span class="s">&#39;default&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">&#39;ENGINE&#39;</span><span class="p">:</span> <span class="s">&#39;django.db.backends.postgresql&#39;</span><span class="p">,</span>
<span class="s">&#39;NAME&#39;</span><span class="p">:</span> <span class="s">&#39;authentic&#39;</span><span class="p">,</span>
<span class="s">&#39;USER&#39;</span><span class="p">:</span> <span class="s">&#39;admindb&#39;</span><span class="p">,</span>
<span class="s">&#39;PASSWORD&#39;</span><span class="p">:</span> <span class="s">&#39;foobar&#39;</span><span class="p">,</span>
<span class="s">&#39;HOST&#39;</span><span class="p">:</span> <span class="s">&#39;db.example.com&#39;</span><span class="p">,</span>
<span class="s">&#39;PORT&#39;</span><span class="p">:</span> <span class="s">&#39;&#39;</span><span class="p">,</span> <span class="c"># empty string means default value</span>
<span class="p">}</span>
</pre></div>
</div>
<p>You should refer to the Django documentation on databases settings at
<a class="reference external" href="http://docs.djangoproject.com/en/dev/ref/settings/#databases">http://docs.djangoproject.com/en/dev/ref/settings/#databases</a> for all
the details.</p>
</div>
<div class="section" id="how-to-upgrade-to-a-new-version-of-authentic">
<h2>How to upgrade to a new version of authentic ?<a class="headerlink" href="#how-to-upgrade-to-a-new-version-of-authentic" title="Permalink to this headline"></a></h2>
<p>Authentic store all its data in a relational database as specified in its
settings.py or local_settings.py file. So in order to upgrade to a new version
of authentic you have to update your database schema using the
migration command — you will need to have installed the dependency django-south,
see the beginning of this README file.:</p>
<div class="highlight-python"><pre>python ./manage.py migrate</pre>
</div>
<p>Then you will need to create new tables if there are.:</p>
<div class="highlight-python"><pre>python ./manage.py syncdb</pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<h3><a href="index.html">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Installation</a><ul>
<li><a class="reference internal" href="#dependencies">Dependencies</a></li>
<li><a class="reference internal" href="#quick-start">Quick Start</a></li>
<li><a class="reference internal" href="#specifying-a-different-database">Specifying a different database</a></li>
<li><a class="reference internal" href="#how-to-upgrade-to-a-new-version-of-authentic">How to upgrade to a new version of authentic ?</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="features.html"
title="previous chapter">Features</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="attribute_management.html"
title="next chapter">Attribute Management in Authentic2</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="_sources/installation.txt"
rel="nofollow">Show Source</a></li>
</ul>
<div id="searchbox" style="display: none">
<h3>Quick search</h3>
<form class="search" action="search.html" method="get">
<input type="text" name="q" />
<input type="submit" value="Go" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
<p class="searchtip" style="font-size: 90%">
Enter search terms or a module, class or function name.
</p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="attribute_management.html" title="Attribute Management in Authentic2"
>next</a> |</li>
<li class="right" >
<a href="features.html" title="Features"
>previous</a> |</li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

BIN
doc/_build/html/objects.inv vendored Normal file

Binary file not shown.

99
doc/_build/html/search.html vendored Normal file
View File

@ -0,0 +1,99 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &mdash; Authentic2 1.9.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '',
VERSION: '1.9.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="top" title="Authentic2 1.9.2 documentation" href="index.html" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
</head>
<body>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
accesskey="I">index</a></li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body">
<h1 id="search-documentation">Search</h1>
<div id="fallback" class="admonition warning">
<script type="text/javascript">$('#fallback').hide();</script>
<p>
Please activate JavaScript to enable the search
functionality.
</p>
</div>
<p>
From here you can search these documents. Enter your search
words into the box below and click "search". Note that the search
function will automatically search for all of the words. Pages
containing fewer words won't appear in the result list.
</p>
<form action="" method="get">
<input type="text" name="q" value="" />
<input type="submit" value="search" />
<span id="search-progress" style="padding-left: 10px"></span>
</form>
<div id="search-results">
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li><a href="index.html">Authentic2 1.9.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">
&copy; Copyright 2011, Mikaël Ates.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.
</div>
</body>
</html>

1
doc/_build/html/searchindex.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,653 @@
.. _attribute_management:
==================================
Attribute Management in Authentic2
==================================
Summary
=======
Attribute management currently allows to configure attribute policies
associated with SAML2 service providers to define attributes that are
pushed in SAML2 successful authentication response delivered by Authentic2.
User attributes can be taken from LDAP directories, the user Django
profile or taken from the user Django session if Authentic2 is also configured
as a SAML2 service provider.
Indeed, when Authentic2 acts also as a SAML2 service provider,
attributes contained in the SAML2 assertion received from third IdP are put in
the user session.
Attributes can thus be proxyfied during SSO with Authentic2
configured as a SAML2 proxy.
The namespace of attributes received from another SAML2 IdP or pushed in the
assertion given in to service providers can be configured per attribute or per
service provider.
By default, the namespace and format of attributes in assertion is conformant
to the SAMLV2.0 X500/LDAP Attribute profile::
<saml:Attribute
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:2.5.4.42" FriendlyName="givenName">
<saml:AttributeValue xsi:type="xs:string"
x500:Encoding="LDAP">Mikaël</saml:AttributeValue>
</saml:Attribute>
But the http://schemas.xmlsoap.org/ws/2005/05/identity/claims from the ISI
profile can also be used, for instance::
<saml:Attribute
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
FriendlyName="First Name">
<saml:AttributeValue>Mikaël</saml:AttributeValue>
</saml:Attribute>
Configuration
=============
Configure sources of attributes
-------------------------------
The source of attributes for authentic2 are of two kinds. The LDAP sources and
the user django profile.
Declare the Django profile source
_________________________________
Add an attribute source named USER_PROFILE with namespace 'Default'.
Then, it is necessary that users create their profile.
Add an LDAP Source
__________________
For LDAP sources, objects of type 'LDAPSource' must be created.
**Even if the authentication is based on LDAP authentification, thus that a
server is configured in settings.py, it is
necessary to create a corresponding 'LDAPSource' to use it as a source of
attribute.**
1. Go to http[s]://your.domain.com/admin/attribute_aggregator/ldapsource/add/
2. Fill form fields
Only the field Name, Server, User, Password, Base and Port are used for now.
**The namespace of LDAP source must be kept to 'Default', since the system
namespace is based on LDAP.**
.. image:: pictures/ldapsource.png
:width: 800 px
3. Save
.. image:: pictures/ldapsource_saved.png
:width: 800 px
Manage user distinguished names in LDAP directories
___________________________________________________
To find the user in a LDAP directory, authentic2 must know its distinguished
name (DN). If this LDAP has been used when the user has authenticated,
Authentic2 learn the user DN. Nothing has to be done from this point of view.
However, if it is expected that user attributes be taken in a directory that
is not used by the user for authentication, it is necessary to manually
indicate to Authentic2 what is the user DN in the directory. For this, a
user alias in source is created for the user:
1. Go to http[s]://your.domain.com/admin/attribute_aggregator/useraliasinsource/add/
2. Fill form fields
.. image:: pictures/alias_in_source.png
:width: 800 px
3. Save
.. image:: pictures/alias_in_source_saved.png
:width: 800 px
Configure attributes pushed to SAML2 service providers in SSO response
----------------------------------------------------------------------
Reminder:
- The default name format in SAML2 assertions is URI
- The default namespace called 'Default' is LDAP
In summary:
1. Create attribute items indicating an attribute name, a source, the name format expected and the namespace expected for the attribute name and friendly name if any.
2. Create a named list of attribute items.
3. Create an attribute policy and associate the previous list or associate the previous list to a existing attribute policy.
4. Associate the policy to a service provider.
Create attribute items
______________________
1. Go to http[s]://your.domain.com/admin/idp/attributeitem/add/
2. Fill form fields
.. image:: pictures/attribute_item.png
:width: 800 px
3. Save
.. image:: pictures/attribute_item_saved.png
:width: 800 px
Create a named list of attribute items
______________________________________
1. Go to http[s]://your.domain.com/admin/idp/attributelist/add/
2. Name the list and add items to list
.. image:: pictures/attribute_list.png
:width: 800 px
3. Save
.. image:: pictures/attribute_list_saved.png
:width: 800 px
Create or modify an attribute policy
____________________________________
1. Go to http[s]://your.domain.com/admin/idp/attributepolicy/add/
2. Add list to the policy
.. image:: pictures/policy_pull.png
:width: 800 px
3. Save
.. image:: pictures/policy_pull_saved.png
:width: 800 px
Associate the policy to a service provider
__________________________________________
1. Go to http[s]://your.domain.com/admin/saml/libertyprovider/1/
2. Add policy to the service provider
.. image:: pictures/sp_policy_pull.png
:width: 800 px
3. Save
.. image:: pictures/sp_policy_pull_saved.png
:width: 800 px
4. The display name of the policy has changed
.. image:: pictures/policy_pull_renamed.png
:width: 800 px
Handle attributes provided by other Identity providers, proxy attributes
------------------------------------------------------------------------
Link to configure first Authentic as a sp to have attributes in session
Add a source if mapping set to true
Modifying supported namespaces and attribute name mappings
==========================================================
TBD
Explanation (Draft)
===================
Attribute aggegrator module
---------------------------
The core attribute management is based on the attribute aggregator module.
Intro
_____
Attribute aggregator provides a main Model class called UserAttributeProfile,
functions to load attributes and extract attributes.
The mapping between attribute namespaces is built-in and depends on a unique
file (mapping.py).
A main schema is defined and is based on LDAP/X500 for naming. The support
of http://schemas.xmlsoap.org/ws/2005/05/identity/claims is partly complete.
Source of attributes are connected with attribute loading functions using
signals.
FAQ
___
Why not use the Django User profile?
The django user profile needs to define attributes as class attributes and
then support form filling or mapping with LDAP.
That is useful and may be used, especially because the profile can be used as
a source of attribute to load in the attribute_aggregator profile.
The attribute_aggregator profile allow to load multivalued attributes from any
source supported (LDAP, Django profile and attributes in Django session for
now) from any namespace defined in mapping.py (LDAP/X500 and claims for now).
The profile can be loaded giving a source or a list of attribute, or can be
from any known source, or with a dictionnary.
Attributes can be extracted with many functions in any namespace supported.
Quick explanation
_________________
The schema is defined in mapping.py and is made of definitions like this::
"sn": {
"oid": "2.5.4.4",
"display_name": _("sn surname"),
"alias": ['surname'],
"profile_field_name": 'last_name',
"type": "http://www.w3.org/2001/XMLSchema#string",
"namespaces": {
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims": {
"identifiers":
[
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
],
"friendly_names":
[
"Last Name",
],
}
}
},
The profile store all the data in a text field taht contains a cPickle list of
instances of the class AttributeData.
The profile is attached to a user and then can be created or loaded with::
profile = load_or_create_user_profile(user=user)
User may be None to create a temporary profile for an anonymous user. But
that need a DB cleaning function not implemented.
The model *UserAttributeProfile*
________________________________
The model 'UserAttributeProfile' can be attached to a user and then persist
(as a Model).
When the profile is loaded, all data stored are removed expect if the
the data has an expiration date later.
The profile provide several methods to store and extract attributes.
All the methods to add attributes are based on a main one accepting a
dictionnary of attribute is parameters 'load_by_dic()'. The other methods
('load_listed_attributes()', 'load_greedy()') send a signal with a list of
attributes (listed_attributes_call) or not (any_attributes_call) to grab a
dictionnary. The list is given with the definition name, oid or friendly name
of the attribute in the system namespace.
Into the dictionnary, attributes are given with their name, oid or friendly
name in the default namespace or with their name in a namepsace. An expiration
date can also be given (ISO8601 format), if none, attribute will be deleted at
next profile loading. The dictionnary format is as follows::
attributes = dict()
data_from_source = list()
a1 = dict()
a1['oid'] = definition_name
Or
a1['definition'] = definition_name
definition may be the definition name like 'gn'
or an alias like 'givenName'
Or
a1['name'] = attribute_name_in_ns
a1['namespace'] = ns_name
a1['expiration_date'] = date
a1['values'] = list_of_values
data_from_source.append(a1)
...
data_from_source.append(a2)
attributes[source_name] = data_from_source
Getters are defined to extract data from a profile. Only AttributeData
instances are extracted that assume that any attribute namespace can be used.
* get_data_of_definition(definition)
Return a list of AttributeData instances corresponding to the definition
given.
* get_freshest_data_of_definition(definition)
Return the freshest AttributeData instance. If multiple with no or same exp
date, random. Should use the creation date soon.
* get_data_of_source
Return a list of AttributeData instances corresponding to the source given.
* get_data_of_source_by_name
Idem but source name is given, not a Source instance.
* get_data_of_definition_and_source
Return a list of AttributeData instances corresponding to the definition and
source given.
* get_data_of_definition_and_source_by_name
Idem but source name is given, not a Source instance.
SAML2 attribute representation in assertions
--------------------------------------------
SAML2 attribute profile (saml-profiles-2.0-os - Section 8) defines two kind of
attribute element syntax in the attribute statement of assertions, also
called *name format*:
- BASIC::
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
- URI::
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
*URI should be used when attributes have "universally" known unique names
like OID.*
Example::
<saml:Attribute NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
Name="FirstName">
<saml:AttributeValue xsi:type="xs:string">By-Tor</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute
xmlns:x500="urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500"
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
Name="urn:oid:2.5.4.42" FriendlyName="givenName">
<saml:AttributeValue xsi:type="xs:string"
x500:Encoding="LDAP">Steven</saml:AttributeValue>
</saml:Attribute>
BASIC
_____
Two <Attribute> elements refer to the same SAML attribute if and only if the
values of their Name XML attributes are equal in the sense of Section 3.3.6 of
[Schema2].
No additional XML attributes are defined for use with the <Attribute> element.
The schema type of the contents of the <AttributeValue> element MUST be drawn
from one of the types defined in Section 3.3 of [Schema2]. The xsi:type
attribute MUST be present and be given the appropriate value.
X.500/LDAP Attribute Profile (URI)
__________________________________
**Extracted from the SAML2 core specifications**
Two <Attribute> elements refer to the same SAML attribute if and only if their
Name XML attribute values are equal in the sense of [RFC3061]. The
FriendlyName attribute plays no role in the comparison.
Directory attribute type definitions for use in native X.500 directories
specify the syntax of the attribute using ASN.1 [ASN.1]. For use in LDAP,
directory attribute definitions additionally include an LDAP syntax which
specifies how attribute or assertion values conforming to the syntax are to be
represented when transferred in the LDAP protocol (known as an LDAP-specific
encoding). The LDAP-specific encoding commonly produces Unicode characters in
UTF-8 form. This SAML attribute profile specifies the form of SAML attribute
values only for those directory attributes which have LDAP syntaxes. Future
extensions to this profile may define attribute value formats for directory
attributes whose syntaxes specify other encodings.
To represent the encoding rules in use for a particular attribute value, the
<AttributeValue> element MUST contain an XML attribute named Encoding defined
in the XML namespace urn:oasis:names:tc:SAML:2.0:profiles:attribute:X500.
For any directory attribute with a syntax whose LDAP-specific encoding
exclusively produces UTF-8 character strings as values, the SAML attribute
value is encoded as simply the UTF-8 string itself, as the content of the
<AttributeValue> element, with no additional whitespace.
In such cases, the xsi:type XML attribute MUST be set to xs:string.
The profile-specific Encoding XML attribute is provided, with a value of LDAP.
The AttributeData instances have a field expiration_data. It the profile
exists, obsolete data are removed at loading.
When authentic 2 deals with attributes and needs mapping?
---------------------------------------------------------
Authentic2 behaves as an attribute provider:
* At the SSO login
* When an attribute request is received
Authentic requests (e.g. by soap) are not yet supported.
When Authentic2 behaves as an attribute provider at SSO login
_____________________________________________________________
At a SSO request, just before responding to the service provider, the saml2
idp module sends the signal 'add_attributes_to_response' giving the SP entity
ID.
The signal is connected to the function 'provide_attributes_at_sso()' in
charge of providing the attributes at the SSO for this SP.
**Attributes sources are of two kinds. The first ones are the sources that can
be requested by the IdP with a syncrhonous binding without user intercations.
These sources are called pull sources. They are for now limited to LDAP
sources. The other ones are sources are asyncrhonous bindings, usually
requiring user interactions. These sources are called push sources. They are
now limited to the attributes provided at SSO requests when the IdP acts as a
SAML2 SP. There attributes are put/found in the Django session.**
Each source in the system is declared with an instance of the AttributeSource
model. We'll see later that to forward attributes of push sources it is not
necessary that a source is declared in some circumstances.
To manage these sources an attribute policy is attached to services providers.
Then the service provider model must be extended with a attribute
attributes_at_sso_policy. The service provider must send the signal
'add_attributes_to_response'.
The implementation is actually done for SAML2 providers.
**In such a policy attributes from pull and push sources are treated
differently.**
**For pull sources, a list of attributes is indicated. Either an attribute is
searched in all the pull sources and whatever attribute value found is
returned. Or each attribute is indicated with a source. With each attribute is
indicated the output format and namespace.**
**The policy may also indicate that all the attributes in the Django session
must be forwarded. Then, no AttributeSource instance is required. All the
attributes are then forwarded without treating input namespace considerations.
When an AttributeSource instance is found, the input namespace of this source
is considered. An option can then be set to tell that the output format and
namespace must be taken. A list of attribute can also be given.
This list can be use to filter attributes to forward without or without taking
care of the source. The output namespace and format can also be trated per
attribute.**
If the namespace is default, the attribute names will be taken from the
system namespace. In BASIC the name will be the definition name. In URI, the
Name will be the OID in urn format and the friendly name will be the
definition name. If a namespace is given, the first identifier of this
attribute is taken as Name in BASIC. In URI, the same and the first friendly
name is taken.
::
class LibertyServiceProvider(models.Model):
...
attribute_policy = models.ForeignKey(AttributePolicy,
verbose_name=_("Attribute policy"), null=True, blank=True)
class AttributePolicy(models.Model):
# List of attributes to provide from pull sources at SSO Login.
# If an attribute is indicate without a source, from any source.
# The output format and namespace is given by each attribute.
attribute_list_for_sso_from_pull_sources = \
models.ForeignKey(LibertyAttributeMap,
related_name = "attributes of pull sources",
blank = True, null = True)
# Set to true for proxying attributes from pull sources at SSO Login.
# Attributes are in session.
# All attributes are forwarded as is except if the parameter
# 'attribute_list_for_sso_from_push_sources' is initialized
forward_attributes_from_pull_sources = models.BooleanField(default=False)
# Map attributes in session
# forward_attributes_in_session must be true
# At False, all attributes are forwarded as is
# At true, look for the namespace of the source for input, If not found,
# system namespace. Look for the options attribute_name_format and
# output_namespace of the attribute policy for output.
map_attributes_from_pull_sources = models.BooleanField(default=False)
# ATTRIBUTE_VALUE_FORMATS[0] =>
# (lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC, 'SAMLv2 BASIC')
output_name_format = models.CharField(max_length = 100,
choices = ATTRIBUTE_VALUE_FORMATS,
default = ATTRIBUTE_VALUE_FORMATS[0])
#ATTRIBUTES_NS[0] => ('Default', 'Default')
output_namespace = models.CharField(max_length = 100,
choices = ATTRIBUTES_NS, default = ATTRIBUTES_NS[0])
# Filter attributes pushed from source.
source_filter_for_sso_from_push_sources = \
models.ManyToManyField(AttributeSource,
related_name = "attributes of pull sources",
blank = True, null = True)
# List of attributes to filter from pull sources at SSO Login.
attribute_filter_for_sso_from_push_sources = \
models.ForeignKey(LibertyAttributeMap,
related_name = "attributes of pull sources",
blank = True, null = True)
# The sources of attributes of the previous list are considered.
# May be used conjointly with 'source_filter_for_sso_from_push_sources'
filter_source_of_filtered_attributes = models.BooleanField(default=False)
# To map the attributes of forwarded attributes with the defaut output
# format and namespace, use 'map_attributes_from_pull_sources'
# Use the following option to use the output format and namespace
# indicated for each attribute.
map_attributes_of_filtered_attributes = models.BooleanField(default=False)
# Set to true to take in account missing required attributes
send_error_and_no_attrs_if_missing_required_attrs = \
models.BooleanField(default=False)
class Meta:
verbose_name = _('attribute options policy')
verbose_name_plural = _('attribute options policies')
class AttributeList(models.Model):
name = models.CharField(max_length = 40, unique = True)
attributes = models.ManyToManyField(AttributeItem,
related_name = "attributes of the list",
blank = True, null = True)
class AttributeItem(models.Model):
attribute_name = models.CharField(max_length = 100, choices = ATTRIBUTES,
default = ATTRIBUTES[0])
# ATTRIBUTE_VALUE_FORMATS[0] =>
# (lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC, 'SAMLv2 BASIC')
output_attribute_name_format = models.CharField(max_length = 100,
choices = ATTRIBUTE_VALUE_FORMATS,
default = ATTRIBUTE_VALUE_FORMATS[0])
#ATTRIBUTES_NS[0] => ('Default', 'Default')
output_namespace = models.CharField(max_length = 100,
choices = ATTRIBUTES_NS, default = ATTRIBUTES_NS[0])
required = models.BooleanField(default=False)
source = models.ForeignKey(AttributeSource, blank = True, null = True)
A list of attributes can also be taken from the service provider metadata and
added to 'attribute_list_for_sso_from_pull_sources'. The namespace may be
extracted from the metadata. This namespace is then used to look for the
corresponding definition and then to provide the attribute in the right
namespace. Read attributes from metadata is not yet supported.
For the attributes of pull sources, once the list of attributes is defined,
They are loaded in the user profile.
As explained before the attribute_aggregator loading function send signals to
grab dictionnary of attributes. Up to know, only the ldap loading function are
connected to these signals. The namespace of LDAP sources is assumed to be
the same as the system namespace. There is here then no mapping needed. Other
kind of sources than LDAP can be defined in attribute aggregator.
To grab attributes from a LDAP the user dn in the LDAP or at least a local
identifier in the LDAP is required. For this purpose, each user has alias
associated with LDAP source. These aliases must their DN in the LDAP. When
the authentication LDAP backend will be taken in account, the dn will be taken
direclty from the user Model instance.
Each LDAP sources are declared with the binding parameters. The LDAP namespace
is always 'Default'.
If an attribute to load is not found and is required the answer should report
an error (Not yet implemented).
Attributes in response can also be provided with other means than from an LDAP
source. Attributes can be put in the user Django session and then loaded in
the profile. An option of the service provier indicate if attributes in the
session must be provided to the service provider.
To have the attribute loaded from the session, they must be provided in the
session as follows:
request.session['attributes'][source_name] = list()
The source_name must be the name of an existing instance of an
'AttributeSource'. Such an instance contains a field namespace indicating the
namespace of attributes.
This is currently implemented only for the SAML2 service provider module of
authentic2. Authsaml2, the SP module, parse the assertion and put the
attributes in the session.
::
if not 'multisource_attributes' in request.session:
request.session['attributes'] = dict{}
request.session['multisource_attributes'] \
[login.assertion.issuer.content] = attributes
Then, Authentic2 can be used as a SAML2 proxy forwarding attributes in
assertion, eventually doing a namespace mapping. For this, the option
forward attributes in sesion must be set (by default False).

61
doc/auth_ldap.rst Normal file
View File

@ -0,0 +1,61 @@
.. _auth_ldap:
==============================================
Authentication with an existing LDAP directory
==============================================
Authentic use the module django_auth_ldap to synchronize the Django user tables
with an LDAP. For complex use case, we will refer you to the django_auth_ldap
documentation, see http://packages.python.org/django-auth-ldap/.
How to authenticate users against an LDAP server with anonymous binding ?
-------------------------------------------------------------------------
1. Install the django_auth_ldap module for Django::
pip install django_auth_ldap
2. Configure your local_settings.py file for authenticating against LDAP.
The next lines must be added::
AUTHENTICATION_BACKENDS += ( 'django_auth_ldap.backend.LDAPBackend', )
import ldap
from django_auth_ldap.config import LDAPSearch
# Here put the LDAP URL of your server
AUTH_LDAP_SERVER_URI = 'ldap://ldap.example.com'
# Let the bind DN and bind password blank for anonymous binding
AUTH_LDAP_BIND_DN = ""
AUTH_LDAP_BIND_PASSWORD = ""
# Lookup user under the branch o=base and by mathcing their uid against the
# received login name
AUTH_LDAP_USER_SEARCH = LDAPSearch("o=base",
ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
How to allow members of an LDAP group to manage Authentic ?
-----------------------------------------------------------
1. First you must know the objectClass of groups in your LDAP schema, this FAQ
will show you the configuration for two usual classes: groupOfNames and
groupOfUniqueNames.
2. Find the relevant groupname. We will say it is: cn=admin,o=mycompany
3. Add the following lines::
from django_auth_ldap.config import GroupOfNamesType
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("o=mycompany",
ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)")
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
"is_staff": "cn=admin,o=mycompany"
}
For an objectClass of groupOfUniqueNames you would change the string
GroupOfNamesType to GroupOfUniqueNamesType and grouOfNames to
groupOfUniqueNames. For more complex cases see the django_auth_ldap
documentation.

26
doc/auth_pam.rst Normal file
View File

@ -0,0 +1,26 @@
.. _auth_pam:
=====================================
Authentication on Authentic2 with PAM
=====================================
This module is copied from https://bitbucket.org/wnielson/django-pam/ by Weston
Nielson and the pam ctype module by Chris Atlee http://atlee.ca/software/pam/.
Add 'authentic2.vendor.dpam.backends.PAMBackend' to your
``settings.py``::
AUTHENTICATION_BACKENDS = (
...
'authentic2.vendor.dpam.backends.PAMBackend',
...
)
Now you can login via the system-login credentials. If the user is
successfully authenticated but has never logged-in before, a new ``User``
object is created. By default this new ``User`` has both ``is_staff`` and
``is_superuser`` set to ``False``. You can change this behavior by adding
``PAM_IS_STAFF=True`` and ``PAM_IS_SUPERUSER`` in your ``settings.py`` file.
The default PAM service used is ``login`` but you can change it by setting the
``PAM_SERVICE`` variable in your ``settings.py`` file.

245
doc/conf.py Normal file
View File

@ -0,0 +1,245 @@
# -*- coding: utf-8 -*-
#
# Authentic2 documentation build configuration file, created by
# sphinx-quickstart on Thu Oct 13 14:38:32 2011.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Authentic2'
copyright = u'2011, Mikaël Ates'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1'
# The full version, including alpha/beta/rc tags.
release = '1.9.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'Authentic2doc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'Authentic2.tex', u'Authentic2 Documentation',
u'Mikaël Ates', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'authentic2', u'Authentic2 Documentation',
[u'Mikaël Ates'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'Authentic2', u'Authentic2 Documentation', u'Mikaël Ates',
'Authentic2', 'One line description of project.', 'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}

5
doc/config_cas_idp.rst Normal file
View File

@ -0,0 +1,5 @@
.. _config_cas_idp:
====================================
Configure Authentic2 as a CAS client
====================================

28
doc/config_cas_sp.rst Normal file
View File

@ -0,0 +1,28 @@
.. _config_cas_sp:
====================================
Configure Authentic2 as a CAS server
====================================
How to use Authentic2 as a CAS 1.0 or CAS 2.0 identity provider ?
-----------------------------------------------------------------
1. Activate CAS IdP support in settings.py::
IDP_CAS = True
2. Then create the database table to hold CAS service tickets::
python authentic2/manage.py syncdb --migrate
3. Also configure authentic2 to authenticate against your LDAP directory (see
above) if your want your user attributes to be accessible from your service,
if it is not necessary you can use the normal relational database storage
for you users.
4. Finally configure your service to point to the CAS endpoint at:
http[s]://your.domain.com/idp/cas/
5. If needed configure your service to resolve authenticated user with your
LDAP directory (if user attributes are needed for your service)

12
doc/config_saml2_idp.rst Normal file
View File

@ -0,0 +1,12 @@
.. _config_saml2_idp:
=================================================================
Configure Authentic2 as a SAML2 service provider or a SAML2 proxy
=================================================================
1. Create instance of SP settings
2. Declare IdP
3. Get authsaml2 md

23
doc/config_saml2_sp.rst Normal file
View File

@ -0,0 +1,23 @@
.. _config_saml2_sp:
====================================
Configure SAML 2.0 service providers
====================================
How to I authenticate against Authentic2 with a SAMLv2 service provider ?
-------------------------------------------------------------------------
1. Grab the SAML2 IdP metadata:
http[s]://your.domain.com/idp/saml2/metadata
2. And configure your service provider with it.
3. Go to the providers admin panel on:
http[s]://your.domain.com/admin/saml/libertyprovider/add/
There create a new provider using the service provider metadata and enable it
as a service provider, you can customize some behaviours like the preferred
assertion consumer or encryption for the NameID or the Assertion element.

13
doc/download.rst Normal file
View File

@ -0,0 +1,13 @@
.. _download:
========
Download
========
1. Pypi: http://pypi.python.org/pypi/authentic2/1.9.0
2. Git repository: http://repos.entrouvert.org/authentic.git
3. `Browse source <http://dev.entrouvert.org/projects/authentic/repository>`_

23
doc/features.rst Normal file
View File

@ -0,0 +1,23 @@
.. _features:
========
Features
========
Authentic can authenticate users against:
- an LDAP directory,
- a SAML 2.0 identity provider,
- an OpenID identity provider,
- with an X509 certificate.
Authentic can provide authentication to web applications using the following
protocols:
- OpenID,
- SAML 2.0,
- CAS 1.0 & CAS 2.0.
Authentic can proxy authentication between any two different protocols it
support.

71
doc/index.rst Normal file
View File

@ -0,0 +1,71 @@
.. Authentic2 documentation master file, created by
sphinx-quickstart on Thu Oct 13 09:53:03 2011.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
==========================
Authentic2's documentation
==========================
Authentic2 is a versatile identity provider addressing a broad
range of needs, from simple to advanced setups, around web authentication,
attribute sharing, namespace mapping and authorization management.
Authentic2 supports many protocols and standards, including SAML2, CAS, OpenID,
LDAP, X509, OATH, and can bridge between them.
Authentic2 is under the GNU AGPL version 3 licence.
It has support for SAMLv2 thanks to `Lasso <http://lasso.entrouvert.org>`_,
a free (GNU GPL) implementation of the Liberty Alliance and OASIS
specifications of SAML2, ID-FF1.2 and ID-WSF2.
- `Authentic2 project site <http://dev.entrouvert.org/projects/authentic>`_
- `Authentic2 roadmap <http://dev.entrouvert.org/projects/authentic/roadmap>`_
Documentation content
=====================
.. toctree::
:maxdepth: 2
features
download
installation
auth_ldap
auth_pam
config_saml2_sp
config_saml2_idp
config_cas_sp
config_cas_idp
attribute_management
Copyright
=========
Authentic is copyrighted by Entr'ouvert and is licensed through the GNU General
Public Licence, version 2 or later. A copy of the whole license text is
available in the COPYING file.
The OpenID IdP originates in the project django_openid_provider by Roman
Barczy¿ski, which is under the Apache 2.0 licence. This imply that you must
distribute authentic2 under the AGPL3 licence when distributing this part of the
project which is the only AGPL licence version compatible with the Apache 2.0
licence.
.. Indices and tables
.. ==================
.. * :ref:`genindex`
.. * :ref:`modindex`
.. * :ref:`search`

100
doc/installation.rst Normal file
View File

@ -0,0 +1,100 @@
.. _installation:
============
Installation
============
Dependencies
------------
You must install the following packages to use Authentic
- Python Lasso binding 2.3.5:
From sources: http://lasso.entrouvert.org/download
Debian based distribution: apt-get install python-lasso
- Django 1.3:
From sources: http://www.djangoproject.com/download/1.3/tarball/
- Django-registration 0.8-alpha-1:
From sources: http://bitbucket.org/ubernostrum/django-registration/downloads
Debian based distribution: apt-get install python-django-registration
- Django-authopenid 0.9.6:
From sources: http://bitbucket.org/benoitc/django-authopenid/downloads
- Django-south 0.7.3:
From sources:: http://south.aeracode.org/docs/installation.html
- Django-profiles 0.2:
From sources:: http://pypi.python.org/pypi/django-profiles
You install all the django libraries quickly using pip::
pip install django django-profiles django-registration \
django-debug-toolbar django-authopenid south
or easy_install::
easy_install django django-profiles django-registration \
django-debug-toolbar django-authopenid south
Quick Start
-----------
Then launch the following commands::
python manage.py syncdb --migrate
python manage.py runserver
You should see the following output::
Validating models...
0 errors found
Django version 1.2, using settings 'authentic.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
You can access the running application on http://127.0.0.1:8000/
Specifying a different database
-------------------------------
This is done by modifying the DATABASES dictionary in your local_settings.py file
(create it in Authentic project directory); for example::
DATABASES['default'] = {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'authentic',
'USER': 'admindb',
'PASSWORD': 'foobar',
'HOST': 'db.example.com',
'PORT': '', # empty string means default value
}
You should refer to the Django documentation on databases settings at
http://docs.djangoproject.com/en/dev/ref/settings/#databases for all
the details.
How to upgrade to a new version of authentic ?
----------------------------------------------
Authentic store all its data in a relational database as specified in its
settings.py or local_settings.py file. So in order to upgrade to a new version
of authentic you have to update your database schema using the
migration command — you will need to have installed the dependency django-south,
see the beginning of this README file.::
python ./manage.py migrate
Then you will need to create new tables if there are.::
python ./manage.py syncdb

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
doc/pictures/ldapsource.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Some files were not shown because too many files have changed in this diff Show More