Commit 8522ab91 authored by ale's avatar ale

initial import from old repo

parents
.deps
.libs
*.o
*.la
*.lo
*.a
*.pyc
*.gcda
*.gcno
build
Makefile
Makefile.in
coverage.info
coveragereport
config.guess
config.sub
config.log
config.status
configure
aclocal.m4
autom4te.cache
depcomp
install-sh
libtool
ltmain.sh
missing
.*-stamp
Copyright (c) 2008-2012 Autistici/Inventati <info@autistici.org>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
ai-sso - a Single Sign-On implementation
========================================
This documents should guide you through the installation of
ai-sso-server (sso_server) and setup a simple SSO-protected
Apache virtual host.
sso_server
----------
First of all, you will need to generate the public and private keys
used by the SSO server.
Simply run::
# cd /etc/sso
# ssotool --gen-keys
The file 'secret.key' should only be readable by the user which runs
the sso_server (in this example, and if you are using the Debian
packages, it is 'ai-sso')::
# chmod 400 /etc/sso/secret.key
# chown ai-sso /etc/sso/secret.key
After that, modify /etc/sso/config according to your needs. You will
want to set at least the 'SSO_DOMAIN' and 'SSO_SECRET_KEY' options::
SSO_AUTH_MODULE = 'sso_server.auth.auth_test'
SSO_DOMAIN = 'somedomain.org'
SSO_SECRET_KEY = 'something random'
Start the service::
# /etc/init.d/ai-sso-server start
Apache - mod_sso
----------------
Enable 'mod_sso' in Apache. On Debian systems, you can use the
a2enmod utility::
# a2enmod sso
Every VirtualHost that should be protected by SSO must be deployed
over SSL, so you'll have to rewrite the http:// url to point to
https://url. Then, configure SSO just like any normal Apache
authentication module::
<VirtualHost *:443>
ServerName example.somedomain.org
SSLEngine on
SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
SSOPublicKeyFile "/etc/sso/public.key"
SSODomain somedomain.org
SSOService example.somedomain.org/
<Location />
AuthType SSO
AuthName somename
require valid-user
</Location>
DocumentRoot /var/www
</VirtualHost>
Note that the SSOPublicKeyFile (the SSO public key file) must
be distributed to all servers that need to verify SSO tokens.
Using mod_sso with mod_proxy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you plan to use SSO on a server with mod_proxy enabled, you will
need to exclude the 'sso_login' and 'sso_logout' endpoints from being
served by the proxy module. Add these directives to your configuration::
ProxyPass /sso_login !
ProxyPass /sso_logout !
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = lib src
XML_TEST_OUTPUT = $(shell pwd)/test-output/
.PHONY: check-xml
check-xml:
-mkdir $(XML_TEST_OUTPUT)
env GTEST_OUTPUT="xml:$(XML_TEST_OUTPUT)" $(MAKE) check
-(echo -e '<?xml version="1.0"?>\n<unit_tests>' ; \
xsltproc gtest.xsl $(XML_TEST_OUTPUT)/* | fgrep '<test>' ; \
echo '</unit_tests>') > unittest.xml
coverage:
sh test_coverage.sh
clean-local:
-rm -fr coverage-*
# Note: this should match what's in lib/nacl-20110221/do.
short_hostname := $(shell hostname | sed 's/\..*//' | tr -cd '[a-z][A-Z][0-9]')
NACL_ABI := $(shell $(top_srcdir)/lib/nacl-20110221/printabi.debian)
NACL_DIR = $(top_builddir)/lib/nacl-20110221/build/$(short_hostname)
NACL_LIB_DIR = $(NACL_DIR)/lib/$(NACL_ABI)
AM_CPPFLAGS = \
-I$(top_srcdir)/src \
-I$(NACL_DIR)/include/$(NACL_ABI)
AM_LDFLAGS = \
-L$(top_builddir)/src \
-L$(NACL_LIB_DIR)
NACL_LIBS = $(NACL_LIB_DIR)/libnacl.a $(NACL_LIB_DIR)/librandombytes.a
SSO_LIBS = $(top_builddir)/src/sso/libsso.la $(NACL_LIBS)
LDADD = $(SSO_LIBS)
++++++++++++++++++++++++++++++++++++++++
ai-sso - a Single Sign-On implementation
++++++++++++++++++++++++++++++++++++++++
**EXPERIMENTAL - DO NOT USE IN PRODUCTION**
This is a Single Sign-On (SSO) implementation, comprehensive of a
login server and various client (middleware) modules that cover
application setups such as Apache and WSGI.
Overview
========
The service uses cryptographically signed *tickets*, short-term
authorization credentials generated by a central *login service*,
whose validity can be independently verified by the authentication
client.
The protocol works over HTTP, using cookies to store tickets. This
makes it work out-of-the-box for browsers, but programmatic access is
also possible (an example Python client is provided).
Note that, as with all cookie-based authentication systems, possession
of the cookie is sufficient for authentication purposes: this makes
them vulnerable to XSS and XSRF techniques. Users and application
developers are expected to take the necessary preventive measures.
The login service is fully stateless and can be easily replicated (for
large setups). Authentication is ultimately performed by pluggable
authentication modules (PAM and LDAP support are included in the
source distribution). You can write your own following the API in
``src/sso_server/sso_server/auth/base.py``.
Services
--------
A *service* is just an application that supports SSO. Since these are
usually served over HTTP, the service specification is modeled after
the URL syntax::
<HOST>[:<PORT>][/<PATH>]/
The `https` URL scheme is implied, thus forcing all client
interactions with the system to happen over SSL. Note that the service
name should always end with a slash.
Domains
-------
Currently, a *domain* is simply a high-level namespace for
authentication, and it is not really used except that it needs to
match between the clients and the login service. It can be set to any
domain name (which does not necessarily need to exist).
Implementation
==============
This section discusses briefly the implementation details.
Protocol
--------
Here is an example interaction between the browser, an SSO-enabled
application and the login server:
1) When a client connects to a SSO-enabled application, we search for
a local, service-specific, SSO cookie. If a valid cookie is found, the
request will be successfully handled by the application::
https://service1.some.com
2) The application redirects the client to the SSO login server,
asking it to generate a new ticket (we're skipping URL quoting for
readability)::
https://login.some.com/?s=service1.some.com/&d=https://service1.some.com
3) The SSO server checks for its own SSO cookie (using
`login.some.com/` as the service name). If the cookie is not valid,
show username/password prompt page, and check the credentials against
the authentication database
4) The SSO server redirects to the original application::
https://service1.some.com/sso_login?t=TICKET&d=https://service1.some.com/
5) The application sets the local, service-specific, SSO cookie to the
value provided in the *t* parameter, and redirects the client to the
original URL (*d*).
Each service supporting SSO must provide support for two special URLs:
``/sso_login``
Called with the *t* and *d* parameters, it should set the SSO
ticket to the (base64-decoded) value of *t*, and redirect the
client to the URL specified by *d* (eventually checking that
it lies within its own service namespace).
``/sso_logout``
Clear the SSO ticket for this service and any other application-specific
credentials. This handler should return an HTML page containing just
the text "OK".
The login server supports these two parameters:
*s* - Service name
Note that all service names should end with a slash. The
service name is used to generate the sso_login URL, in the
following way (abusing shell syntax for clarity)::
https://${SERVICE_NAME}sso_login
*d* - Redirect URL
When the login process is complete, redirect the user to this
URL.
*g* - Requested group membership
A comma-separated list of group names. When authenticating the user,
the login service will also check that it is a member of one or more
of the specified groups, or the authentication will fail.
Visiting ``https://login.some.com/logout`` will log the user out of all
the applications by calling their ``/sso_logout`` handlers (using
IFRAMEs).
SSO Ticket Format
-----------------
An SSO ticket is just a signed string consisting of fields separated
by the pipe (``|``) character. It includes the ticket format version,
username, service name, domain name, and group memberships.
The current format version number is 2.
Installation
============
To compile the software you'll need to install a few dependencies
first:
* SWIG
* libpam
* Apache2 development headers and libraries for your favorite
threading model
* Python development environment
* (the crypto library NaCl is currently included with the code, but
will soon become an external dependency).
Then it should be just a matter of running::
$ sh autogen.sh
$ ./configure --enable-mod-sso --enable-pam-sso
$ make install
To run the internal test suite::
$ make check
Deployment
==========
Configuring Apache with mod_sso
-------------------------------
You can add SSO support to Apache using *mod_sso*, which will be
installed if you pass ``--enable-mod-sso`` to ``configure``. It adds
the ``SSO`` authentication method, which can be used with the standard
``require`` directive as follows::
<Location />
AuthType SSO
SSOService this.host.name/
require valid-user
</Location>
Using ``require user`` and ``require group`` also works as expected.
Note that in some cases you might have to exclude the sso_login and
sso_logout URLs from being handled by another module, for instance if
you are using *mod_proxy* this should be added to your config::
ProxyPass !sso_login
ProxyPass !sso_logout
The following directives can be used to configure *mod_sso*:
SSOService
Service name for the local application. Can appear anywhere.
SSOLoginServer
URL of the login server. Must appear only once, in the top-level
configuration.
SSODomain
The shared authentication domain. Must appear only once, in the
top-level configuration.
SSOPublicKeyFile
Location of the file containing the login service public key.
Python / WSGI
-------------
The source distribution includes Python WSGI middleware to use for
your Python web applications. An example::
from sso.middleware import SSOMiddleware
app = SSOMiddleware(app,
service='test.example.com/',
domain='example.com')
PAM
---
An SSO-aware PAM module is available, for integration with other
services. It knows about the following parameters:
service
Service name.
domain
Shared authentication domain.
login_server
URL of the login server.
key
Location of the file containing the login service public key.
Login service
-------------
The login service is a WSGI application so you can adapt it to
whatever deployment strategy is required. It can also run standalone
from the command line, which is useful for debugging. In all cases, it
needs a configuration file (located using the ``APP_CONFIG``
environment variable if not specified on the command line), which
supports the following variables (and has Python syntax):
SSO_SECRET_KEY
Location of the file with the secret key (``/etc/sso/secret.key``).
SSO_PUBLIC_KEY
Location of the file with the public key (``/etc/sso/public.key``).
SSO_AUTH_MODULE
Module to use for authentication, specified as a Python import path
(the default of ``sso_server.auth.auth_test`` should definitely be
changed).
SSO_DOMAIN
Domain.
ALLOWED_SERVICES
A list of regular expression patterns defining the services
which are allowed. If left unset (the default), no checks will
be performed on the destination service upon authentication.
Production instances should not leave this unset.