views:

662

answers:

1

I would like to use an LDAP server (probably Apache directory) to manage logins and credentials for an application. From time to time the application needs to work offline (on a laptop) without a connection to the LDAP server.

What is the best way to replicate the credentials localy?

I have already thought about:

  • Using Mitosis to replicate the LDAP server on the laptop.

    But it would be a quite "heavy" and complicated solution. Moreover Mitosis seems not be be finished yet.

  • Exporting the credentials as LDIF file that could be stored on the laptop.

    But I would need a way to check that the LDIF file actually comes from the LDAP server (The file should include a kind of signature). Moreover I would like to reject LDIF files that haven't be updated for more than a week. It would be nice if I could avoid implementing signing and age check myself.

Any other ideas or tools that could help me?

Edited Edit: I had a look at Kerberos because the documentation of the Java-Kerberos-API seems to say that it is possible to use a cached ticket in a local cache and I thought this might be a solution for me. Moreover Kerberos can be added as plugin to Apache Directory. But the Kerberos cache stores decrypted tickets (aiming at sharing them with other applications). I would need the crypted version of the ticket to be able to check the user password during an offline session. Conclusion: Kerberos doesn't offer a simple solution to my problem.

3rd edit, solution used: I have not found another solution. I decided to use an LDIF export, add a timestamp as comment at the beginning of the file and then sign the file. To sign the file I calculate an hash value (SHA-1) of the file + a secret key. The signature is added as comment at the beginning of the file. To check the signature I remove the first line of the signed file and recalculate the hash value.

+2  A: 

Knowing that it will be probably ok if the user have to log on once online before being able to log on offline, consider the following algorithm:

  1. user provides your application with a (username + password)
  2. application attempts to contact LDAP for authentication
    • working online? (e.g. connection successful)
      1. application authenticates against LDAP using (username + password)
        • authentication succesful?
          1. application stores or updates hash(password) as (cached_credentials) for (username) into local secure storage
          2. application proceeds as authenticated [[STOP]]
        • authentication failed?
          1. application proceeds as non-authenticated (incorrect credentials) [[STOP]]
    • working offline? (e.g. network error)
      1. application attempts retrieve (cached_credentials) for (username) from local secure storage
        • (cached_credentials) exists AND more recent than (1 week)?
          1. application compares (cached_credentials) against hash(password)
            • match?
              1. application proceeds as authenticated [[STOP]]
            • no match?
              1. application proceeds as non-authenticated (incorrect credentials) [[STOP]]
        • (cached_credentials) does not exist OR less recent than (1 week)?
          1. application proceeds as non-authenticated (network error) [[STOP]]

This is (or was, IIRC), by the way, the same model employed by Windows NT+ for user authentication against domain controllers. Upon login an attempt is made to authenticate against the domain controller and create or update the local (cached) version of the user profile. If the domain controller is not available, the user is prompted to proceed with authentication against the credentials captured in the local (cached) profile (if one exists.)


EDIT

  • Yes, this is, in spirit, the same solution as copying an ldif file locally, except that you do not have to parse ldif when you're offline. :)
  • It is understood that you can store any additional attributes (permissions, etc.) in your cache
  • It is also understood that 'secure storage' is at least signed. :) You can do this easily enough with a SHA-1 hash and a secret, or you can use full-fledged cryptographic providers available on your platform (or in Java, if using Java.) You do not need to crypt it as long as no secret information is stored inside.

Cheers, Vlad.

vladr
Thanks for writing the detailled algorithm. But actually it is about the same solution as with an ldif file: Consider the ldif file as being the "local secure storage". I still have to manage this local secure storage myself (sign or crypt it to avoid forgery and add a time stamp to it).
Name
A precision: The credentials include more than username + password. They also include a list of the user rights. An hashed password isn't enough to avoid forgery, because a user could simply add new right to his own list if the "local secure storage" isn't signed.
Name
Yes, I know. :) See my update. It's really trivial to secure your entire storage with a sha-1 hash.
vladr
Thanks again. Actually there will be 2 applications using the authentication. One writted in Delphi, one in Java. That's why I would prefer to rely on standard libraries instead of implementing something myself. I keep the ldif solution for the case that I don't find something better.
Name