Building Liberty Services with Lasso

Author: Frederic Peters
Contact: fpeters@entrouvert.com
Date: 2005-01-22
Copyright: Copyright © 2004, 2005 Entr'ouvert

This work is licensed under the GNU General Public License. To view a copy of this license, visit http://www.gnu.org/copyleft/gpl.html.

1. Preface

In a digitalised world where both businesses and consumers want security in their transactions the notion of identity has become more and more crucial. Today one's identity on the network is fragmented across various identity providers, employers, business services and other communities. This fragmentation leads to partial and often unsatisfying customers-to-business relationships.

A Federated Network Identity allows new business opportunites and new economies of scale. In a world of federated commerce a user's identity, preferences, buying habits and history, are managed by the user himself and securely exchanged with the organisations of the user's choosing.

1.1. The Liberty Alliance Project

The Liberty Alliance Project was formed in September 2001 to develop open standards for federated network identity management and identity-based services. Its goals are to ensure interoperability, support privacy, and promote adoption of its specifications, guidelines and best practices. The Alliance is made up of more than 150 members, representing a worldwide cross-section of organizations ranging from educational institutions and government organizations, to service providers and financial institutions, to technology vendors and wireless providers.

1.2. The Lasso Project

In July 2003 Entr'ouvert started to develop the "Carte de Vie Quotidienne" project for the commune of Vandoeuvre-les-Nancy. This project quickly drove us to take interest in cross-site authentication problems. We identified Liberty Alliance specifications as the only ones potentially able to satisfy our need for a strong authentication, coupled with private life respect. Lasso is a library written in C which means it can be easily integrated within any kind of web service whenever a strong authentication is required. Lasso has been the first implementation of Liberty Alliance released under the GNU GPL license.

1.3. Acknowledgments

Figures use drawings from GNOME Gorilla theme by Jakub 'jimmac' Steiner.

2. The Liberty Architecture

Building on existing pieces, XML, SAML, SOAP, HTTP, SSL...

Points to specs; quick glossary; user = principal...

Maps use cases to profiles.

This chapter provides a quick overview of the different profiles; they will be detailed and implemented in the next chapters.

2.1. Single Sign-On and Federation

The Single Sign On process allows a user to log in once to an identity provider (IdP), and to be then transparently loged in to the required service providers (SP) belonging to the IP "circle of trust". Subordinating different identities of the same user within a circle of trust to a unique IP is called "Identity Federation". The liberty Alliance specifications allows, thanks to this federation, strong and unique authentication coupled with control by the user of his personal informations. The explicit user agreement is necessary before proceeding to Identity Federation.

The different SPs can't communicate directly together about users informations. They're only able to exchange informations about a user with the IP. This assure :

  • private life respect;
  • increased security (an unveiled identity for one of the SPs won't endanger the others).

To insure the integrity and the non-revocability of the exchange, a trusted third part releases a security token which identify only the session and not the user.

2.1.1. Artifact Profile

figures/single-sign-on.png

Single Sign-On and Federation interactions, Artifact profile

  1. the user clicks on a "login" button
  2. the service provider answers with a redirect to the identity provider
  3. the browser goes to the identity provider where the user logs in
  4. the identity provider answers with a redirect, back to the service provider
  5. the browser goes to the service provider telling it has been authenticated
  6. the service provider makes a SOAP request to the identity provider asking if it is true that the user has been authenticated
  7. the identity provider answers that yeah, everything is under control
  8. the service provider answers to the browser and send a welcome page

2.1.2. Browser POST Profile

Almost the Same thing.

2.2. Single Log-out

A few words about the five different profiles.

2.2.1. Initiated by the Service Provider, using SOAP requests

figures/single-logout.png

Single Log-out interactions; initiated at service provider, using SOAP

Should arrange the figure with the SP on the right; I think it would help read the figure.

2.3. Liberty URLs

How does the identity provider knows the "SOAP endpoint" of the service provider ? That is metadata for you.

3. The Lasso Architecture

Doesn't store, doesn't communicate.

Modeled on liberty profiles; one profile = one class

Objet oriented but in C. Talks about how this work (necessary to know for the lasso_profile functions)


Lasso provides the necessary functions to implement Liberty Alliance profiles, as defined in the Liberty ID-FF Bindings and Profiles Specification and explained in the previous chapter. Each profile maps to a Lasso class:

Single Sign-On and Federation LassoLogin
Name Registration LassoRegisterNameIdentifier
Federation Termination Notification LassoFederationTermination
Single Logout LassoLogout
Name Identifier Mapping LassoNameIdentifierMapping
Identity Provider Introduction not implemented
Name Identifier Encryption not implemented

There are also a few other classes to know about:

  • LassoServer holds the data about a provider, which other providers it knows, what certificates to use, etc.
  • LassoIdentity holds the data about a Liberty federated identity
  • LassoSession holds the data about an active Liberty session.
  • LassoProfile is the base class for profiles.

Talk more about respective usage of Identity and Session.

4. Getting Lasso

Lasso is licensed under the GNU General Public License. That means users are given several inalienable rights: the right to use the library, whatever the purpose is; the right to study how it works, getting access to source code; the right to distribute the library to others and the right to modify the library and publish those modifications.

Talks about library and how Lasso will force the use of the GPL.

4.1. Binary packages

4.1.1. Debian packages

The latest Lasso release should be available straight from any Debian mirror worldwide in the etch or sid distribution. Additionaly packages are provided for the sarge release on a dedicated APT repository. The following line needs to be added to /etc/apt/sources.list:

deb http://www.entrouvert.org ./debian/lasso/

It is then a matter of running:

apt-get install liblasso-dev

4.1.2. RPM packages

RPM Bad. A mess.

4.1.3. Microsoft Windows packages

Ah. Isn't that funky ? (need to ask Romain about cygwin, mingw32 and whatever is needed to get Lasso working on Windows)

4.2. Sources

The source code of the latest release is available at the following URL: http://labs.libre-entreprise.org/project/showfiles.php?group_id=31

Lasso uses the GNU automake and autoconf to handle system dependency checking. It is developed and built locally on GNU/Linux (Debian) both on x86 and PowerPC processors.

4.2.1. Compiling

./configure

The configure shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a Makefile in each directory of the package. It may also create one or more .h files containing system-dependent definitions. Finally, it creates a shell script config.status that can be run in the future to recreate the configuration, and a file config.log containing compiler output (useful mainly for debugging configure).

configure can take a lot of options, a complete list is available with the --help flag: ./configure --help

4.2.1.1. Installation Directories

By default, Lasso will be installed in /usr/local/lib. It is possible to specify an installation prefix other than /usr/local by giving the option --prefix=PATH; for example --prefix=/usr.

4.2.1.2. Optional Features

There are optional features that you may want not to build, things like unit tests, bindings for different languages, etc.

--disable-java Disable the Java binding
--disable-python Disable the Python binding
--disable-php Disable the PHP binding
--disable-csharp Disable the C# binding
--disable-tests Disable the unit tests

On the other hand there are features you may want to activate.

--enable-debugging Enable debugging messages
--enable-profiling Enable profiling compilation flags

Once ./configure has been executed it is time to compile the whole thing.

make

It should take a few minutes.

make install

Will then copy the library and header files to their final directories.

4.2.2. Bleeding Edge

CVS (Concurrent Versions System) is the version control system used by Lasso developers to keep track of files, how and by whom they were modified. It is accessible anonymously for people to use the latest developments.

export CVSROOT=:pserver:anonymous@cvs.labs.libre-entreprise.org:/cvsroot/lasso
cvs login     # press enter
cvs -z3 checkout lasso

Note

The CVS version requires more tools to build; notably automake, autoconf and libtool.

5. Common Lasso Knowledge

Starting with basics on using Lasso in a given program.

5.1. Lasso Projects Basics

Lasso functions are defined in several header files typically located in /usr/include/lasso/ or /usr/local/include/lasso/. It is possible to include individual files even if the main lasso.h is sufficient most often.

The first thing to do is then to call lasso_init(). Similarly the last thing will be to call lasso_shutdown(). The smallest and useless Lasso project will therefore be:

#include <lasso/lasso.h>

int main(int argc, char *argv[])
{
    lasso_init();
    printf("Hello world.\n");
    lasso_shutdown();
    return 0;
}

Lasso uses a tool called pkg-config to know the necessary flags for compilation and linking.

 $ pkg-config lasso --cflags
-DXMLSEC_CRYPTO=\"openssl\" -DXMLSEC_LIBXML_260=1 -D__XMLSEC_FUNCTION__=__FUNCTION__
-DXMLSEC_NO_XKMS=1 -DXMLSEC_NO_CRYPTO_DYNAMIC_LOADING=1 -DXMLSEC_CRYPTO_OPENSSL=1
-I/usr/include/lasso -I/usr/include/libxml2 -I/usr/include/xmlsec1 -I/usr/include/glib-2.0
-I/usr/lib/glib-2.0/include
 $ pkg-config lasso --libs
-llasso -lxmlsec1-openssl -lxmlsec1 -lssl -lcrypto -ldl -lgobject-2.0 -lxslt -lxml2
-lpthread -lz -lm -lglib-2.0

Creating an executable from the previous sample will then be a simple matter of calling gcc with the right flags

Creating an executable from the previous sample would then a simple matter of calling gcc with the right flags. But there is currently in bug in XMLSec, the library used by Lasso to provide XML Signature and XML Encryption support. It is possible to workaround the bug:

 $ gcc hello.c -o hello $(pkg-config lasso --cflags --libs)
<command line>:4:16: missing terminating " character
 $ gcc hello.c -o hello $(pkg-config xmlsec1 --cflags --libs | tr -d '\\')
 $ ./hello
Hello world.

5.2. Lasso Objects

The Lasso Architecture chapter described the different objects provided by Lasso. The profile objects will be detailed in the following chapters; common objects such as server, identity and session are explained here.

5.2.1. LassoServer

A LassoServer object may be created as follows:

LassoServer *server;
server = lasso_server_new("sp-metadata.xml",
              NULL, "sp-private-key.pem", "sp-crt.pem", lassoSignatureMethodRsaSha1);
lasso_server_add_provider(server, "idp-metadata.xml",
              "idp-public-key.pem", "ca-crt.pem");
  • sp-metadata.xml is the Liberty metadata file for the service provider
  • idp-metadata.xml is the Liberty metadata file for the identity provider
  • sp-private-key.pem is the service provider private key; used to sign documents
  • sp-crt.pem is the service provider certificate; sent within signed documents
  • idp-public-key.pem is the identity provider public key; used to verify signature in documents sent by the identity provider
  • ca-crt.pem is the certificate of the certification authority used by the identity provider.

It is of course possible to have several calls to lasso_server_add_provider if there are more than one identity provider.

5.2.2. LassoProfile

This is the virtual base class for profiles. It notably provides access to the identity and session parts of a profile. See below for examples.

5.2.3. LassoIdentity

/* profile is a pointer to a LassoProfile object */

LassoIdentity *identity;

if (lasso_profile_is_identity_dirty(profile)) {
    identity = lasso_profile_get_identity(profile);
    if (identity) {
        dump = lasso_identity_dump(identity);
    }
}

5.2.4. LassoSession

/* profile is a pointer to a LassoProfile object */

LassoSession *session;

if (lasso_profile_is_session_dirty(profile)) {
    session = lasso_profile_get_session(profile);
    if (session) {
        dump = lasso_session_dump(session);
    }
}

5.2.5. Serialization

LassoServer, LassoIdentity and LassoSession``objects can be serialized into XML files.  Example with a ``LassoServer:

gchar *dump;
FILE *fd;

dump = lasso_server_dump(server);
/* write dump into a file, a database, whatever */
g_free(dump);

Note

lasso_server_dump (and other Lasso dump functions) allocates memory through GLib. g_free is the function to use instead of free to release memory.

It is then really easy to have properly constructed objects returned:

LassoServer *server;
gchar *dump;

/* restore dump from file, database, whatever */
server = lasso_server_new_from_dump(dump);

Warning

The server dump only contains the filenames; not the actual file contents. Files should not be moved afterwards.

The functions are:

Object Dump Restore
LassoServer lasso_server_dump lasso_server_new_from_dump
LassoIdentity lasso_identity_dump lasso_identity_new_from_dump
LassoSession lasso_session_dump lasso_session_new_from_dump

6. Single Sign-On and Federation

6.1. Profile Overview

The service provider has four things to do:

  • creating an authentication request
  • sending it to the identity provider
  • receiving an authentication response or an artifact
  • (eventually) checking it against the identity provider

The first two steps are handled with an HTTP redirection or an HTML form; typically the user would click on a button, the service provider would then create the authentication request and send an HTTP Redirect to the browser. No URL is defined in the specifications for this first step.

The last two steps are handled in the AssertionConsumerServiceURL; the user will arrive there through an HTTP Redirect or an HTTP POST carrying a piece of information from the identity provider. In case of a redirect, this information, called artifact, won't be large and will be exchanged with the identity provider for a AuthnResponse. An HTTP POST will be able to carry much more information and will therefore be able to provide either the artifact or directly the AuthnResponse.

An appropriate metadata snippet would be:

<?xml version="1.0"?>
<EntityDescriptor providerID="service-provider" xmlns="urn:liberty:metadata:2003-08">
 <SPDescriptor>
  <AssertionConsumerServiceURL id="AssertionConsumerServiceURL1" isDefault="true">
   https://service-provider.example.com/liberty-alliance/assertionConsumer
  </AssertionConsumerServiceURL>
 </SPDescriptor>
</EntityDescriptor>

The identity provider has more things to do:

  • receiving an authentication request
  • authenticating the user if necessary
  • sending a response to the service provider
  • (eventually) answering a SOAP request with an other response

All but the last one is handled in the SingleSignOnServiceURL; the user has been redirected there from the service provider with an authentication request as URL parameter. This authentication request is used to decide several things (allowed authentication methods for example) and the authentication is done. This step is not part of the Liberty protocols, this can be as simple as straight HTTP authentication with a username and a password or as complex as a Java applet checking a certificate on the client.

Anyway, once the user has been authenticated, an answer must be sent to the service provider. It is actually not a direct communication, the answer bounces on the user agent with an HTTP Redirect or by an HTML form pointing to the service provider.

The answer may be an artifact (available in the query string in case of a redirect or in a LAREQ form field in case of a POST); the user is then simply redirected to this URL. The service provider will then make a SOAP request to the SoapEndpoint asking for the authentication response matching the artifact.

The answer may also be an authentication response; since it will be a large piece of data it must be passed in an HTML page; an HTML form embedding the authentication response. The user will then submit this form to the service provider AssertionConsumerURL.

Metadata would be:

<?xml version="1.0"?>
<EntityDescriptor providerID="identity-provider" xmlns="urn:liberty:metadata:2003-08">
 <IDPDescriptor>
  <SoapEndpoint>
   https://identity-provider.example.com/soapEndpoint
  </SoapEndpoint>
  <SingleSignOnServiceURL>
   https://identity-provider.example.com/singleSignOn
  </SingleSignOnServiceURL>
 </IDPDescriptor>
</EntityDescriptor> 

6.2. Implementing the service provider parts

Warning

The source code presented in the "implementing" section has for sole purpose to explain the different steps necessary to implement the profiles; they notably lack proper error checking. See XXX for details on error checking.

6.2.1. Sending the user to the identity provider

server is a LassoServer object as seen earlier (LassoServer) and idpProviderId is a string with the identity provider Id (the string must match a providerID defined in the metadata file).

LassoLogin *login;

/* create login object */
login = lasso_login_new(server);

Select profile to use, HTTP Redirect:

lasso_login_init_authn_request(login, idpProviderId, LASSO_HTTP_METHOD_REDIRECT);

or HTTP POST:

lasso_login_init_authn_request(login, idpProviderId, LASSO_HTTP_METHOD_POST);

Parametrize request:

/* will force authentication on the identity provider */
LASSO_LIB_AUTHN_REQUEST(LASSO_PROFILE(login)->request)->ForceAuthn = TRUE;

/* ask for identity federation */
LASSO_LIB_AUTHN_REQUEST(LASSO_PROFILE(login)->request)->NameIDPolicy =
    strdup(LASSO_LIB_NAME_ID_POLICY_TYPE_FEDERATED);

/* the user consents with the idea of identity federation */
LASSO_LIB_AUTHN_REQUEST(LASSO_PROFILE(login)->request)->consent =
    strdup(LASSO_LIB_CONSENT_OBTAINED);

(see API reference for other possible values)

Create the authentication request:

lasso_login_build_authn_request_msg(login);

An URL is then defined in LASSO_PROFILE(login)->msg_url; the user must be redirected to it; for example, in a CGI:

printf("Location: %s\n", LASSO_PROFILE(login)->msg_url);

6.2.2. Receiving an answer from the identity provider

This part is handled on the AssertionConsumerURL.

6.2.2.1. Receiving an assertion

The user has been directed to this URL. If it was a redirect the query string (the part of the URL after the question mark) will hold the artifact and may be used to initialize the LassoLogin object.

LassoLogin *login;

login = lasso_login_new(server);
lasso_login_init_request(login, query_string, LASSO_HTTP_METHOD_REDIRECT);
lasso_login_build_request_msg(login);

If it was a form post it will have a LAREQ field.

LassoLogin *login;

login = lasso_login_new(server);
lasso_login_init_request(login, lareq_field, LASSO_HTTP_METHOD_POST);
lasso_login_build_request_msg(login);

The service provider must then check this artifact using a SOAP request to the identity provider. The URL is LASSO_PROFILE(login)->msg_url while the request is LASSO_PROFILE(login)->msg_body. The request must succeed with an HTTP 200 status code. The SOAP answer body must then be passed to:

lasso_login_process_response_msg(login, answer);

6.2.2.2. Receiving an authentication response

A form with a LARES field has been posted; this element holds the authentication response.

LassoLogin *login;

login = lasso_login_new(server);
lasso_login_process_authn_response_msg(lares_field);

6.2.2.3. Federating identities

There is then a nameIdentifier (accessible through LASSO_PROFILE(login)->nameIdentifier) for the user identifying. If this name identifier is already known by the service provider the corresponding identity and session must be restored.

if (session_dump != NULL) {
    lasso_profile_set_session_from_dump(LASSO_PROFILE(login), session_dump);
}
if (identity_dump != NULL) {
    lasso_profile_set_identity_from_dump(LASSO_PROFILE(login), identity_dump);
}

Process the authentication request, this will update (or create) the identity and session.

::
lasso_login_accept_sso(login);

Identity and session must then be saved and finally the login object can be destroyed:

lasso_login_destroy(login);

And a success web page may then be displayed.

7. Integration with Existing Applications

That's the part where we talk about identity dumps to insert in existing user tables. And session dumps wherever sessions are stored.

8. Other Profiles

That would be like the single sign-on chapter but harder better faster stronger.

9. Lasso in other Languages

C is cool.

But.

Python. (CGI ?)

PHP. (with code putting the session dump in the PHP $_SESSION["lasso"])

Java. (and JSP ?)

C#. (and ASP.Net ?)

Whatever we have.