Distributed Matter - Blog

To content | To menu | To search

Monday, June 9 2008

HTTP authentication mechanisms (and how they could work in Restlet)

Updated 08/08/08

I'm currently addressing how access control is done in the project I'm working on. We're using Restlet, so I've been looking into its authentication and authorisation mechanisms. There were a few issues with the current API for Guards, as I wanted to use mechanisms that are not currently supported. Thus, I started a discussion on the Restlet mailing list by making a few comments and suggestions about the Guard class. The Restlet community is really dynamic and changes tend to be integrated rapidly into the source code, which is really pleasant. However, we all seem to agree that this particular problem deserves more substantial consideration than just a few quick patches. Here are a few thoughts I've had on the subject...

Guarding access to a resource involves two steps:

  • authentication, which consists of ensuring the user is who he/she claims to be and that the credentials presented are authentic (for example, you can be authenticated because you can prove you know your password), and
  • authorisation, which consists of making a decision as to whether the authenticated user may or may not perform an action.

I'm focussing first on authentication, since this is really what influences the external interfaces of the system: what happens between the client and the server. In contrast, authorisation happens after the client has been authenticated and can be done by a third party. This being said, some authentication mechanism blur the line with authorisation, especially when some authorisations are granted or delegated by a third-party.

In the following, I'm trying to categorise the various pieces of information and mechanisms that can be used for authentication, in particular, authentication at transport level and authentication at HTTP-level. This is very HTTP-centric, even if Restlet can be used with other protocols. If you know of other mechanisms or spot something wrong, please let me know.


Authentication at transport-level

This category of authentication mechanism is not strictly related to HTTP, but HTTP sits on top of this layer and web applications can, in many cases, make use of information from the underlying transport mechanism.

SSL and TLS authentication

Secure Socket Layer (SSL) and Transport Layer Security (TLS) provide mechanisms for peer authentication at transport-level. In almost all cases, unless an anonymous cipher is used, the server authenticates itself to the client by presenting an X.509 certificate corresponding to the host name, which the client may choose to trust. (Anonymous cipher suites, which do not require the server to present a certificate, are prone to man-in-the-middle attacks.)

X.509 client-certificates

The client can present a certificate (or chain thereof) to the server. This procedure is initiated by the server, which may also be configured to accept the absence of a certificate even if it has been requested. In short, there are three ways to configure the server for client-side authentication (here, following the Tomcat configuration keywords):

  • none: no certificate request, so client-side authentication is disabled,
  • want: a certificate is requested, but the server will still establish the connection if the certificate response is empty, so this corresponds to setWantClientAuth in Java,
  • need: a certificate is requested and the server will require a valid, non-empty certificate response to establish the connection, so this corresponds to setNeedClientAuth in Java.

These options configure the SSL handshake, which takes place before any HTTP data is exchanged. In practice, if SSL client authentication is to be used as one of several possible authentication methods, or if only some resources on the server are protected by a mechanism that requires SSL client authentication, the preferred option should be to want a client-certificate. Indeed, if the server needs a certificate, failing to provide one implies that the connection will not even be established (which means that HTTP cannot be used to send an "access forbidden" error message of any sort): this is not very "polite".

Kerberos

Kerberos is a network authentication protocol which is secure. It allows two parties to authenticate each other by using a third party they both trust: the KDC (key distribution centre). It's totally independent of SSL. However, there are some Kerberos-based cipher suites, which are for example available in Java 6, so they could also provide Kerberos authentication at transport-level.

I have done a few quick tests in Java: SSLSession.getPeerPrincipal() does return a instance of KerberosPrincipal, the name of which is the Kerberos principal of the client, as expected. The client that I've tried was written in Java and using more or less the same JAAS settings as the server. The only other clients that I've tried were Firefox, Opera and Safari; unfortunately, they do not support these cipher suites, which makes it unrealistic for deploying a system that would be used from a browser. (This type of Kerberos-based authentication is not related to SPNEGO, which is better supported by most browsers and also works from Java clients.)

FOAF & SSL

A few weeks ago, Henry Story talked about his idea of secured FOAF on the Restlet mailing list. In short, Henry was interested in using a web-of-trust model using SSL and I've made a few suggestions so as to use OpenPGP keys in X.509 certificates. The implementation of this is available in the Sommer project and this particular feature uses jSSLutils. This is a very interesting project and I think FOAF&SSL based authentication could provide new authentication models, perhaps with various degrees of trusts that would depend on the way peers are related in the web of trust.

Client IP address and domain name

Although this does not strictly-speaking authenticate the client, but rather the machine from which the requests come, IP addresses and their reverse DNS names could be considered as authentication information which may then be used to make an authorisation decision. This is frequently used to authenticate someone as an intranet user.


Authentication at HTTP-level

The following authentication mechanisms make use of the HTTP protocol.

WWW-Authenticate and Authorization headers

HTTP provides a WWW-Authenticate response header which may be used to challenge the client to provide suitable authentication information, via the Authorization request header.

When access is not authorised, a 401 Unauthorized response status code is returned. There may be multiple WWW-Authenticate challenges in a single response; it is then up to the client to use one of them and provide its response in the Authorization header. This may be confusing, but most of the time, the Authorization header contains authentication (not authorisation) information.

Basic

HTTP Basic authentication is probably the simplest username/password authentication mechanism in HTTP. It relies on a realm, which is a name usually displayed by the browser when the user is prompted for his/her password. It is probably the simplest to implement, since the client then only has to provide the credentials as as string like username:password in clear, encoded in base 64. Since the server obtains the password in clear, this password can be relayed to a third-party authentication provider to be verified, such as an LDAP server. Other authentication providers include encrypted passwords in files (htpasswd in Apache) or in databases. Of course, this would also work with authentication providers that disclose password. HTTP Basic authentication can also be used pre-emptively, that is, when making the first request to the server, without being challenged with a "401" response.

Digest

HTTP Digest is an improvement over HTTP Basic because the password is not transmitted in clear between the client and the server. The downside of this mechanism is that it requires the server to be able to know the secret password. This is often impractical in environments where the password is really only known by the user (any mechanism that obfuscates the password) or where the authentication cannot reveal the password even if it has access to it. (It could be risky to let an LDAP server give out passwords.)

I personally tend to prefer Basic over SSL rather than Digest for two reasons:

  1. I use authentication providers that do not give access to the password in clear (LDAP or non plain-text htaccess).
  2. I find it hard as a user to feel safe entering my password in a Digest dialog box... which looks just the same as the box you get with Basic authentication; at least, with HTTPS, I'm warned when I switch to an un-enciphered page.

Negotiate (SPNEGO)

SPNEGO (Negotiate scheme) is an authentication mechanism that negotiates the use of an underlying GSS-API. When used in conjunction with HTTP, it uses the Negotiate scheme. It is mostly used to use NTLM or Kerberos (via GSS), but I think it could by used with other GSS mechanisms if required.

I've experimented with this for Restlet (on the server-side) and managed to get it to work from Firefox, Safari, Internet Explorer, and Konqueror against a Linux-hosted MIT Kerberos KDC. Active Directory can also use Kerberos.

Despite the security of Kerberos itself, it may be wiser to secure the exchange of GSS tokens in the HTTP headers, in particular using a GSS mechanism that supports integrity protection. (Admittedly, this is something I need to check.)

Kerberos

Kerberos can be used directly as an authentication scheme via the Apache Kerberos module (which may also support SPNEGO/Negotiate). I'm not sure if it's really maintained. The corresponding Mozilla plugin seems no longer maintained. Since Kerberos works fine via SPNEGO, I'm not sure why one would use it nowadays.

NTLM

There's an NTLM scheme too. Again, I suppose it should be deprecated nowadays, in favour of Negotiate.

OAuth

OAuth is a rather new HTTP authentication/authorisation scheme. Its purpose is to delegate authorisation. There already is an implementation of an OAuth Guard in Restlet.

Cookies and authentication sessions

Forms

Form-based authentication is probably the most used method of authentication on the web. It tends to make use of a cookie to maintain a session (or some session identifier in the URL). Its main advantage is that it looks prettier, especially when it matters to have a corporate visual identity. It has similar security problems as HTTP Basic, and it's thus better when used over SSL.

In terms of HTTP, form-based authentication usually challenges the client with two response codes:

  • 200 OK, you get the page, but there is an explicit message on the page which says you must log on and give you a link. It's a bit of a shame, since in principle, it could also return a 401 Unauthorized status code in the header and still produce the same explicit page which invites the user to log on.
  • 302 Moved, you get redirected to the login page. Again, a 401 Unauthorized status code could be better, especially for non-browser clients.

This being said, the HTTP specification clearly states that a WWW-Authenticate header must be present when returning a 401 response code. Perhaps there should just be a WWW-Authenticate: Form http://uri/of/the/logon/form scheme.

Shibboleth, Google Single-Sign On and OpenID

To some extent, mechanisms that delegate authentication to a third party such as Shibboleth, Google Single Sign-On Service and OpenID (Kerberos is not it this category because it's supported by SPNEGO headers directly) can be considered as variants of the form-based authentication, where a cookie is established to maintain the authenticated state with subsequent requests. Maintaining a session via a cookie isn't strictly necessary (especially for OpenID), but it seems that it's the way it's usually done, probably by lack of a corresponding WWW-Authenticate scheme.

These authentication mechanisms are mainly designed for browser-based access. In order to get the Shibboleth session cookie, the first HTTP request needs to be a GET, this wouldn't work with other actions. (I believe Shibboleth 2.0 tries to address this, but I haven't looked into it.)

Shibboleth is a mechanism that involves more interactions than a plain form and automatic redirections. There are also connections behind the scenes between servers, but here is what it looks like from the browser point of view:

  1. C->S - GET. The browsers attempts to get http://protected.site/page.
  2. S->C - The server returns a 302 redirection to a "Where are you from?" (WAYF) page, this URI includes the URI of the protected page in a parameter.
  3. C->S - GET http://where.are.you.from/ (automatic after redirection).
  4. S->C - The WAYF page offers a list of identity providers (IdP). The user clicks on an IdP link (usually, that of his/her institution) and is directed to that URI. Again, that URI comprises the URI of the protected page.
  5. C->S - GET http://identity.provider/. The page of the IdP authenticate the user via another means (HTTP Basic, X.509 certificates, ...): this is where the IdP authenticates the user.
  6. S->C - Upon successful authentication, the IdP gives the browser a web pages with a form that contains the SAMLResponse. This form is instantly submitted automatically via POST (because there's a <body onload="document.forms[0].submit()"> on that page).
  7. C->S - POST to http://protected.site/Shibboleth.processor the content of SAMLResponse.
  8. S->C - The server sets a Shibboleth session cookies and sends a 302 redirection to the original protected page.
  9. C->S - GET http://protected.site/page. The Shibboleth authentication has taken place. The Shibboleth-protecting module also inserts automatically a header for processing by the web application it hosts. That header is a set of SAML assertions for authentication and authorisation.
  10. S->C - You're in (depending on the SAML assertions).

This would really look better without the automatic POST (which relies on JavaScript). I hope that, when browser designers realise that these tricks are what causes the CSRF attacks to work, being able to have JavaScript to post a form upon loading the page (to a distinct website) will be more restricted. Unfortunately, this will certainly be a problem for Shibboleth. (Shibboleth could be deployed with a GET instead, the problem is that the SAMLResponse is about 8KB, which is a bit long as a URI parameter.)

This is in principle very similar to the Google Single Sign-On Service. The POST issue could in principle exist with Google SSO.

OpenID also falls in this category, except that the authentication assertion is only about the URI identifier, there's no extra SAML assertions (yet).


What this means in the context of Restlet

The current Guard class in Restlet is currently built using a ChallengeScheme. This is well suited for the use of WWW-Authenticate/Authorization headers. However, not all authentication mechanisms rely on these headers (in addition, not all challenge schemes use a realm, which is also currently mandatory to build a Guard, although it can be null). In fact, not all authentication information can be challenged.

There are 3 layers of information that may be used for authentication:

  1. Transport-level (IP address, SSL client-certificates...),
  2. Authentication-headers (although there can be multiple challenge schemes, only one has to be chosen by the client),
  3. Session-cookies.

These 3 layers can be used independently. Some may be used in conjunction with one another.

Although establishing a session via cookies for authentication may seem like it violates the stateless interactions principle of REST, I don't think it does. My interpretation is that the stateless interactions principle should be applied to the application layer, not necessarily the authentication layer. Of course, the use of forms blurs the line between authentication and application data, in particular because they can't really be used with a suitable 401 response. Since Restlet can be embedded in a Servlet, it can then use form/session based authentication.

In addition to this, the Restlet Guard could also make more use of Principal classes. This can be useful for simple cases, where there's a principal that models a user authenticated via a user-name and password, but this could also help model more complex models, for example by mapping the SAML assertions of Shibboleth to principals, thereby providing a basis for role-based authentication. There is a clear need for this with the JAX-RS extension, and principals would also help for making better use of the Java security framework. In terms of implementation design, these instances of Principal should probably be obtained from the authentication providers (that is, the component that actually verify the authentication information).

I'm sure we'll talk more about this on the Restlet mailing lists, but this should provide a sufficient basis for further work on the Guard model. Suggestions and comments welcome!

Update (08/08/08): If you were thinking that this entry wasn't long enough, here are a few additional references. I had forgotten about WSSE authentication, which falls in the "WWW-Authenticate and Authorization headers" category. In addition, here are a few links that may be of interest:

Thursday, May 22 2008

jSSLutils: Customisable configuration of SSL in Java

I recently released jSSLutils: a library to help configure SSL in Java.

Background

In my current project, I have been designing and implementing a system for managing data and allow these data to be shared between the relevant people. Securing access to this data is a strong requirement of this project. This system is implemented using Restlet (only the server-side at the moment), in Java.

In our domain, we tend to use SSL client-side authentication, whereby not only the server presents a certificate to the client (like most secure consumer-oriented websites do) but the client also sends its certificate to the server for being authenticated. Some of these certificates may also be proxy-certificates, often used as a single sign-on (SSO) mechanism in grids based on GSI. We also have a public-key infrastructure (PKI) set up with a certificate authority (CA) for our community.

I've experimented with more advanced configurations of SSL, mainly dealing with proxy-certificates and Certificate Revocation Lists (CRLs), which are not always supported by Java applications out of the box. I had managed to get Jetty to accept proxy-certificates; this is possible by modifying the SSL connectors. Later on, I tried to do the same thing with Restlet. Restlet can use several SSL connectors (based on Jetty, Grizzly, or others). What is common to all these SSL configurations is that they require the TrustManagers to be adapted when building the SSLContext used to create the SSLSockets. This was a good opportunity to package my code and make it usable from several projects.

jSSLutils

I have thus created this relatively small library: jSSLutils. The initial aims were:

  • to provide a consistent way to configure SSL-related parameters in Java applications,
  • to be able to customise the way keys and trust were managed (in particular grid proxy-certificates),
  • to be able to configure CRLs.

There is some initial documentation on the jSSLutils website. There are also examples in the form of jUnit tests in the source code. They even come with test keys, certificates and CRL so that you can try them out.

As of this week, version 0.3 is in the central Maven repository, which should make it easier to use.

FOAF & SSL

Coincidentally, Henry Story was also looking for customisation features in SSL at the same time on the Restlet mailing-list. I was able to help him a bit for his work on FOAF & SSL: a global decentralised authentication protocol. You can find his work in the Som(m)er Address Book project. This looks like a very interesting approach for authentication, but I haven't found the time to get more involved in this project.

Extras

I've also looked at using PKCS#11 tokens and the Apple Keychain (on Mac OS X) from Java, to store and to use the keys and certificates. While investigating this, I found out that some applications (most of those I've looked into) were unable to support these features, at least not easily. Fortunately, the projects I've looked into are open source: I was therefore able to add the features I wanted and contribute them back to their communities. For example, I submitted a patch for Tomcat and a patch for Jetty, to make it possible to use the Apple Keychain or a different Java security provider (useful for static configuration of PKCS#11).

The code for loading a KeyStore in many Java applications seems to assume that it's going to be loaded from a file, which isn't the case for PKCS#11 tokens or the KeychainStore. jSSLutils also provides a jsslutils.keystores.KeyStoreLoader, which should help handling these cases as normal cases.

Feedback

Comments and suggestions are welcome, please get in touch!