LDAP schema for Secure Remote Password authentication

Here is a simple LDAP schema for storing Secure Remote Password (SRP-6a) authentication credentials. It defines an object class srp6Account which can be attached to any directory entry to enable SRP-6a authentication for it. The SRP salt and verifier are stored in a text attribute called srp6Verifier.

dn: cn=schema
objectClass: top
objectClass: ldapSubentry
objectClass: subschema
cn: schema
attributeTypes: ( 1.3.6.1.4.1.31487.3.1 
 NAME 'srp6Verifier' 
 DESC 'Stores SRP6 salt and verifier, in hex and delimited by semicolon' 
 EQUALITY caseIgnoreMatch 
 ORDERING caseIgnoreOrderingMatch 
 SUBSTR caseIgnoreSubstringsMatch 
 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 
 SINGLE-VALUE 
 USAGE userApplications )
objectClasses: ( 1.3.6.1.4.1.31487.3.2 
 NAME 'srp6account' 
 DESC 'Account with SRP-6a authentication support' 
 SUP top 
 AUXILIARY 
 MAY srp6Verifier )

The following format is suitable for storing the Secure Remote Password credentials:

srp6Verifier: [hex-string-salt];[hex-string-verifier]

The salt and the verifier are hex encoded (to save space and avoid ambiguity) , separated by a semicolon.

Example:

srp6Verifier: b24c9bc199aafd143a94;10b3a3986ec57075d1a8f83bafc3350f582f6bd08064d3a09b9f5b4cdcf21c6ee

Check out Nimbus SRP if you’re looking for a solid and well documented Secure Remote Password library.

New prices

This week the [d]zhuvinov [s]oftware website was redesigned and received new prices too!

As of today the prices for JsWorld, the JSON-RPC Shell and new Nimbus SRP library are listed in three major currencies: Euros, British pounds and US dollars. With that more people should be able to shop in their own currency.

In the next few days we’ll add more docs to the Nimbus SRP library. It came about as a side-product of the most recent Json2Ldap feature – support for Secure Remote Password (SRP-6a) authentication for LDAP directory users. After having reviewed so many implementations of the protocol, and having found nothing that truly suit us, we sat down and coded Nimbus SRP. From scratch and with the lessons from the other works in the field. Today Web SRP 1.1 is probably the most complete and versatile toolkit you can get. Stay tuned!

LDAP directories, explained in 1 minute

An LDAP directory is a type of hierarchical NoSQL storage. A quick way to explain the essence of LDAP is by drawing a comparison to a computer file system which people are familiar with.

LDAP directories share many similarities with a file system

Overall organisation

  • A file system consists of files in a tree-like structure.
  • An LDAP directory consists of entries in a tree-like structure.

Data types

  • A file in a file system is an arbitrary blob of text or binary data.
  • A directory entry is a collection of attributes, or name / value pairs. Attributes may be text or binary. They may be mandatory or optional, single or multi-valued.

Naming

  • A file in a file system has a name, e.g. “tax-report-2010.xml”. The file name must be unique within the containing folder.
  • An entry in a directory branch has a relative distinguished name (RDN), e.g. “cn=Alice Wonderland”. The RDN comes from an existing name/value pair in the entry that was chosen to become the entry’s name (or title). RDNs must also be unique within the containing directory branch.

Global naming

  • A file in a file system is uniquely identified by its path, e.g. “/home/vladimir/taxes/tax-report-2010.xml”.
  • An entry in a directory is identified by its distinguished name (DN), which is formed by the chain of RDNs leading all the way to the directory root, e.g. “cn=Alice Wonderland, ou=people, dc=wonderland, dc=net”.

Here is a truncated example directory entry of a user, in LDIF (LDIF stands for LDAP data interchange format).

The distinguished name (DN) is in bold, the name/value pair serving as RDN is slanted.

dn: uid=alice,ou=people,dc=wonderland,dc=net
uid: alice
objectClass: inetorgperson
objectClass: organizationalperson
objectClass: person
objectClass: top
cn: Alice Wonderland
sn: Wonderland
employeeNumber: 18001
givenName: Alice
initials: AA
mail: alice@wonderland.net
mobile: +1 010 154 3228
userPassword:: c2VjcmV0

If you like this analogy explanation of LDAP you’re welcome to use it in your own presentations 🙂

Secure Remote Password (SRP-6a) compatibility issues

Secure Remote Password (SRP) is a clever protocol for secure username + password based authentication where the client doesn’t reveal the actual password to the server, at any time. The password remains entirely private to the user. What the server stores and deals with during authentication are cryptographically secure one-way values that the client derived from the password. So if communication between client and server or the underlying server database is compromised, there is no technical risk of the intruder finding out the user password. The merits of SRP are discussed at greater detail on Tom Wu’s website who is the protocol designer.

Despite its virtues SRP is not particularly well known and widely used. I personally found about it when a customer requested SRP-6a authentication to be added to the Json2Ldap directory web service. My guess is that most developers find transmission of passwords over TLS/SSL and storing them in some hashed form (e.g. SHA1) good enough for most purposes. If you however run a low-budget web service and don’t want to purchase an SSL certificate SRP is the best alternative for secure authentication over plain HTTP.

There are a number of libraries implementing the latest version of Secure Remote Password, namely SRP-6a. I was particularly interested in Java and JavaScript support as these are the languages I use most. For example, a good general purpose Java crypto library that covers SRP-6a is the one produced by Bouncy Castle.

Mixing libraries, however, is very likely to lead to compatibility issues. This may occur if you want to use one library on the server side (e.g. Java) and another on the client (e.g. JavaScript).

Here is a list of the four likely compatibility issues with SRP:

Compatibility factor #1: Choice of initial crypto constants – N and g

SRP must be preset with two initial (public) parameters – a safe prime number (N) and a generator (g). These must be agreed in advance between client and server. The practical approach is to have the server manage these and make them available to clients on request. This way, the client does not need to anticipate or otherwise keep track of which parameters are used for which users or servers; it only needs to verify their validity, which can be done mathematically or by simple table lookup.

Unfortunately, many client libraries employ hard-wired values for N and g.

For servers, look for implementations which have configurable N and g, to allow a choice of optimal bitsize lengths for N, e.g. 256 bit, 512 bit and 1024 bit. Shorter primes speed up the crypto computations while longer ones provide better protection.

For clients, look for generic implementations which allow N and g to be set through the client API, typically from values passed by the server.

Compatibility factor #2: Hash function

Similar to the N and g parameters, client and server must also employ the same hash function throughout the crypto computations. Otherwise the protocol will not work. Commonly used hash functions are SHA-1, SHA-256 and SHA-512. Here again it is advisable to have the server set the preferred hash function.

For servers, look for implementations which allow selection of a digest algorithm, so you can choose the optimal one for your application case. While SHA-1 may be good enough for many situations, SHA-512 provides increased security.

For clients, look for implementations which allow the hash algorithm to be set externally, to fit the server’s choice.

Compatibility factor #3: Verifier computation

The verifier (v) is a special value derived cryptographically from the user password. The client stores it on the server when a new password is set; the server uses it then during authentication. The authenticating clients must use the same method for verifier computation as the client that uploaded the original verifier to the server, else authentication will fail.

The verifier (v) is computed from

v = g^x (mod N)

where x is a hash of the password and the password salt (s), and sometimes the username too.

Some clients base the hash on the simple concatenation of the salt (s) and password:

x = H(s || password)

while others make use of additional hashing that includes the username as well:

x = H(s || H(username) || H(password))

or something more complicated as (from SRP/TLS – see RFC 5054).

x = SHA1( s || SHA1( username || ":" || password))

When devising a web application or service, you have to make sure all clients employ the same method for x computation. This can be done by providing a default client and/or by communicating to developers the expected formula for the x hash creation.

When not to include username in the x hash?

Do not make username part of the x hash if users can have more than one login (e.g. username and email) or if the username is expected to change without an update to the password.

Compatibility factor #4: Validation messages

At the end of the authentication session client and server exchange validation messages.

M1 – а message from client to server. It completes the user authentication.

M2 – оptional message from server to client. It proves that the server has a valid verifier (v) for the user’s password.

Together M1 and M2 can be used for mutual authentication.

The problem is that SRP implementations may have different methods for computing the validation messages, for example:

M1 = H(A || B || S)
M1 = H(A || B || H(S))
M1 = H(H(N) xor H(g) || H(username) || s || A || B || H(S))

M2 = H(A || M1 || S)
M2 = H(A || M1 || H(S))

If the M computation methods differ authentication will fail. Make sure that both server and client use the same method for computing M1 and M2.

How do some of Java libraries fare in terms of the above compatibility factors?

  • Bouncy Castle: Allows for arbitrary choice of N, g and hash function. The implementation is however geared towards use of SRP for TLS (RFC 5054) and doesn’t provide methods for validating M1 and M2. Also x = SHA1( s || SHA1( username || “:” || password)). The verifier (v) generator should have been an interface, not a hard-wired class.
  • Jordan Zimmermann’s SRPforJava: Hard wired parameters and hash function, the verifier is based on non-conventional concatenation of password and salt (s) so client and server implementations must use the same library.

With JavaScript (client) implementations the situations is more or less the same – hard-wired constants and hash function.

So what to do if you encounter a compatibility issue between the server and client libraries you’re using? There’s not much choice but modify the existing code. Fortunately, SRP code is relatively simple and the required touches to match the parameters, the hash function or the V, M1 or M2 methods small. If you need a good and flexible base Java server implementation, Bouncy Castle’s is probably the best point to start.

Update 18 November 2011

Following our unsatisfactory experience with the listed Java SRP libraries we put ourselves to work and produced the ultimate Java library for Secure Remote Password authentication. It addresses all of the above issues: it is fully configurable in terms of crypto parameters ‘N’ and ‘g’ as well as hash algorithm ‘H’; it provides interfaces for custom password key ‘x’ as well as client and server evidence message ‘M1’ + ‘M2’ routines. The library was extensively tested in the context of our Json2Ldap service and incorporates a number of lessons to make it easier to integrate into a complex server environment (session management, timeouts, arbitrary attributes).

Check it out for yourself: Nimbus SRP

Plain SASL authentication

Json2Ldap iconYesterday’s 2.0 release of Json2Ldap brings a lot of new good things. Some of them are hidden, representing various little stubs under the hood that will enable cool new features to be added in future (patience, you’ll find out in due time!). On the outside, the most noticeable addition is the arrival of plain SASL authentication support. This LDAP authentication method offers two key advantages over the traditional simple bind. Here I’ll explain what these are and how you could apply them.

Simpler authentication with username instead of DN

The traditional ldap.simpleBind method authenticates users with their distinguished name (DN) and password. Using DNs for web app login, however, is a bit cumbersome. Why? Because you first have to establish a search connection (bound as some service user) in order to resolve the user’s DN from the entered username or email address, typically with a filter like "|(uid=%u)(mail=%u)", and only then you can make the actual ldap.simpleBind request.

ldap.plainBind spares us these preliminary steps by taking care of the underlying user DN resolution. With it you can just pass the user’s name / email + password and be authenticated. The only snag is that the LDAP directory may require some configuration before that, to allow plain SASL binds and to know which user record attributes will serve as “username”.

Here is an example plain SASL auth included in the ldap.connect request:

{ "method"  : "ldap.connect",
  "params"  : { "host"      : "ds.wonderland.net",
                "port"      : 389,
	        "security"  : "StartTLS",
		"plainBind" : { "username" : "alice",
		                "password" : "secret" },
  "id"      : 1,
  "jsonrpc" : "2.0" }

Proxied authorisation / switching the current user

Proxied authorisation is similar to the sudo command on Unix systems. It allows you to authenticate to the directory with the credentials of one user and then perform all subsequent operations as another user. This is the other significant feature of plain SASL bind.

{ "method"  : "ldap.connect",
  "params"  : { "host"      : "ds.wonderland.net",
                "port"      : 389,
	        "security"  : "StartTLS",
		"plainBind" : { "username"       : "myWebApp",
		                "targetUsername" : "alice",
		                "password"       : "secret" },
  "id"      : 1,
  "jsonrpc" : "2.0" }

Where could proxied authorisation come to use?

In situations when a web app has to modify user data on behalf of another user. In the above example the JSON call authenticates as “myWebApp” but then requests the resulting connection to receive the identity (and privileges) of user “alice”.

Proxied authorisation can also be used to create custom external login procedures, for example based on OAuth 2.0 tokens. Here a helper app upon establishing the identity of the user through some other external mean authenticates to the directory as itself but then through the targetDN / targetUsername parameter requests the connection to take on the identity of the target user.

Note that enabling proxied authorisation for a particular service account requires the underlying LDAP directory to be explicitly configured for that. Check out the docs of your particular directory server for detailed instructions.

Which directory servers support PLAIN SASL bind (RFC 4616)?

  • OpenDJ / OpenDS
  • OpenLDAP
  • Apache DS
  • 389 Directory Server
  • UnboundID in-memory DS
  • Novell eDirectory
  • IBM Tivoli Directory Server

Directory servers without PLAIN SASL bind support:

  • MS Active Directory

JsWorld 2.4.1 with automatic currency rounding

JsWorld iconToday saw the release of JsWorld 2.4.1, which remains the most comprehensive JavaScript library for localised formatting and parsing of numeric, monetary and date/time values in web applications. This is a minor update which introduces automatic rounding of formatted currency amounts.

Up to now the default behaviour was to leave the fraction part of the original input amount unchanged.

var lc = new jsworld.Locale(POSIX_LC.en_US);
var mf = new jsworld.MonetaryFormatter(lc);
alert(mf.format(1500.005));

Result:

$1,500.005

To enforce rounding and display to a certain precision the optional ".n" argument can be used, where n is the number of desired fraction digits.

alert(mf.format(1500.005, ".2"));

Result:

$1,500.01

Yesterday I received an email from a customer in the US from which it became apparent that the default non-rounding behaviour was not intuitive to developers. After some consideration I decided to patch the library code to round per default, based on the number of fraction digits for the selected currency. The optional “.n” facility remains the same.

So the above

alert(mf.format(1500.005));

will now instead result in

$1,500.01

The patched version is now available as JsWorld 2.4.1.

JSON-RPC and cookies

JSON-RPC ShellToday’s releases of the JSON-RPC 2.0 Client (version 1.6) and JSON-RPC 2.0 Shell (version 1.10) include support for handling HTTP cookies, just like browsers do. These latest updates came about after a developer in Norway wrote that the JSON-RPC software was not working as expected against the web API of a particular service provider. A quick look at the API docs revealed that the service was pushing session tokens outside the regular JSON-RPC message flow, using HTTP cookies. The inclusion of cookie support took about a day to code and test out and is now publicly available.

I know, to purists using out-of-channel means to pass the session tokens of a JSON-RPC service is not a clean thing to do. I also value the simplicity of having all message data passed in-channel and our JSON-RPC based services – from Json2Ldap to JsonSSO use the regular JSON-RPC parameters and result fields to communicate session tokens. But at the same time, if you’re programming a servlet-based web service, using the built-in session mechanisms can be too convenient (and routinely done) to ignore.

There is another pitfall with passing cookies from a JSON-RPC service: if you want to allow cross-domain XHR access from browsers to your service, IE will certainly block any cookies for security reasons.

So my advice is to stay away from cookies in JSON-RPC, despite their relative convenience.

JSON-RPC for Android apps

JSON-RPC 2.0 Thanks to user feedback I recently discovered that the JSON-RPC 2.0 Base and related libraries and JSON-RPC shell are finding increasing use in Android applications, mostly to hook to remote JSON-RPC services.

While I’m not really into mobile gadgets and don’t own a smart phone, I do sense there is usefulness in mobile apps to people. I’m now considering a mobile version of the Json2Ldap demo. The upcoming Transaction Company software will also certainly a boast a few mobile apps, to allow users to check their balance and pay co-workers while on the go. Application Craft‘s offering may be just the right mean to do that, as it provides both a development and hosting environment in one.

CORS requests and cookies

CORS FilterToday I received a question regarding the Java CORS Filter and browser cookies:

Does your filter take care about the sessions? For each CORS request I get a different JSESSIONID.

My response was that in order for the Java web application or service to get at a cookie, both the CORS Filter in front of it as well as the requesting JavaScript must explicitly allow this form of credential:

First, the JavaScript initiating the XHR call must set its “withCredentials” flag to true. Otherwise the browser will not allow any cookies to be passed during the cross-domain call.

var xhr = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';

xhr.open('GET', url, true);
xhr.withCredentials = true;
xhr.onreadystatechange = handler;
xhr.send();

Second, the CORS Filter must also expressly state to the browser that cookies are permitted. This is advertised during the so called “pre-flight” request that the browser makes before an actual request that may involve credentials, such as cookies. The CORS Filter ships with a default configuration where credentials, such as cookies, are flagged as allowed when responding to preflight requests. To restrict this edit the cors.supportsCredentials configuration parameter.

The Java CORS filter itself doesn’t access the cookie headers in any way, nor does it interface to the JSESSIONID.

So, to sum up, both the calling script on the browser side as well as the CORS Filter on the server side must expressly have the credentials flag enabled for cookies to pass through.

There is a snag however and it has to do with Internet Explorer. Its XDomainRequest implementation of CORS doesn’t allow cookies to be passed at all, for security reasons says Microsoft. Which is probably a good thing. So if you wish to achieve wider browser support for your cross-domain application or service you will have to use an alternative mean to cookies for storing session IDs, such as passing the token as an URL parameter.

Using data URIs with Json2Ldap

Json2Ldap iconPerson entries in a LDAP directory may contain photos. These are typically stored in a jpegPhoto attribute, defined in the standard inetOrgPerson schema. In this article I’ll show you how to display such JPEG images in the browser using Json2Ldap and a cool new HTML feature called data URIs.

Json2Ldap is a neat LDAP gateway software for web applications. It’s web API presents a set of JSON calls that JavaScript code running in a browser can address to access remote directory servers to perform tasks such as authenticating users, browsing their directory records, reading and updating attributes.

When Json2Ldap returns a directory entry it inspects the value of each attribute. If it is text, it passes it unmodified (save for escaping the special JSON chars). If the content is binary data, it encodes it into a Base64 string.

{ "DN" : "uid=alice,ou=people,dc=wonderland,dc=com",
  "cn"        : [ "Alice Wonderland" ],
  "mail"      : [ "alice@wonderland.net" ],
  "mobile"    : [ "+1 382 077 4180" ],
  "jpegPhoto" : [ "yugEMFjdQyRoxCP2KaZ041BUSctnUgY5TS7PBg==" ]
}

Your client JavaScript application will have no problems displaying the text attributes inside a web page. But how to render the JPEG image which was received as a Base64 string? What to do with it?

In the pre HTML 5 days you would have had to produce a physical JPEG URL from the received Base64 string, for example as by uploading it to a web server and then linking to it.

Fortunately, work-arounds such as this are no longer necessary. The solution is called Data URIs, a feature which was originally specified in 1998 and is now finally implemented by the latest crop of HTML 5 browsers.

How do data URIs work?

They provide an option for image data to be “in-lined” within the HTML page, instead only being able to link to it.

Here is a standard img element where the src attribute is a typical URL pointing to a file on the web server:

<img src="http://myapp.com/users/alice.jpg"/>

And here is an img with a data URI, where the image content is pasted directly into the src attribute. So when a data URI aware browser reads it, it will fetch the JPEG data from the in-lined Base64 string:

<img src="data:image/jpeg;base64,yugEMFjdQyRoxCP2KaZ041BUSctnUgY5TS7PBg=="/>

I don’t know why it took over 10 years to implement support for data URIs in browsers, but this is now a powerful technique for Ajax apps to render images on the web page which content was received through a XHR call.

Data URIs can naturally be applied to Ajax apps that interface to an LDAP directory through Json2Ldap. Rendering jpegPhoto attributes is then as simple as setting the src attribute of the desired image element to a data URI and then appending the Base64 content to it:

// We're using jQuery and the user directory entry 
// resides in the 'user' variable
$("#user-photo").attr("src", "data:image/jpeg;base64," + user.jpegPhoto[0]);

The online Json2Ldap demo makes use of inline images too. You can check it out at http://nimbusds.com/json2ldap-demo.html

The online Json2Ldap featuring data URIs for JPEG image rendering

Things to bear in mind:

While data URIs are supported by all major browsers today, some may impose a limit on the content size. IE 8 for example has a limit of 32 KB. So this technique may not work well for large images. For avatars and photos in user profiles, where 10 to 20KB are sufficient, it is going to be just fine.