Crowd as an LDAP Server

Name Crowd as an LDAP Server
Version 1.0
Product Versions Crowd v1.0.6
Author(s) Robert Castaneda [CODEGEIST:CustomWare] , Daren Klamer [CODEGEIST:CustomWare]
Homepage http://www.customware.net
Price FREE! Priceless!
License N/A
JavaDocs  
IssueTracking  
Download JAR  
Download Source Code, what code? This one is about re-use!

Description/Features

A layer to turn Crowd into an LDAP server

Motivation - a non-Atlassian product to integrate into our environment. The product supports LDAP authentication, we want to use our Crowd deployment as the central repository of users, rather than setting up an LDAP repository just for this application.

A picture is a thousand words - here is the end result in JXplorer of users listed from Crowd via LDAP:

The requirement is to have no Java/J2EE/Atlassian based products use crowd as the central authentication mechanism via LDAP. To achieve this, we have used Penrose - http://penrose.safehaus.org/ and have configured it to read user/password information from the Crowd database as well as implement a password decrypt/decode function in Penrose so that it can authenticate using the same passwords that are stored in Crowd without duplicating user information. A user in Crowd, is a user in LDAP. The diagram shows the setup below:

Full Size

Whilst not a plugin that runs within an Atlassian product, it's another solution that can bring outside technologies into the Atlassian world.

How an external application authenticates over LDAP can be different from one application to another. This example has been tested using Crowd itself, that is , using the Penrose LDAP server as a Crowd Directory service and a Crowd external Application setup to test against this directory.

At any time, Crowd can update their algorithm for storing passwords. The mechanism described here makes us of the fact that having access to the right data, a password can be reverse engineered/constructed from the Crowd database. If this ability changes in future, then this will need to be updated, probably to use the

Unknown macro: {SHA-512}
<pwd> type syntax.

As always, an application/infrastructure such as Crowd is only as secure as the infrastructure -database/os - that it runs on.

Steps to setup

  • We then create a Source. In Crowd, we created a View rather than accessing the tables directly. The main table that you need access to is REMOTEPRINCIPALCREDENTIALS

  • We then and add a New Dynamic Entry, not a "Dynamic Entry from Source". Within that entry definition, we define the source within the dynamic entry.

Code

The following code decrypts passwords stored in Crowd, note that you need to retrieve the RETRIEVE_ME_FROM_YOUR_CROWD_DATABASE parameter from your DB. To retrieve this parameter, execute the following SQL from the Crowd database:

select * from "SERVERPROPERTY" where "NAME" = 16

The code is below.

import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;

            // Buffer used to transport the bytes from one stream to another
        byte[] buf = new byte[CODEGEIST:1024];

        try {
            byte[] hash = new BASE64Decoder().decodeBuffer( RETRIEVE_ME_FROM_YOUR_CROWD_DATABASE );
            SecretKey key = new SecretKeySpec( hash, "DES" );

            DESKeySpec paramSpec = new DESKeySpec( hash );

            Cipher dcipher = Cipher.getInstance( "DES" );
            dcipher.init( Cipher.DECRYPT_MODE, key );

            ByteArrayInputStream bis = new ByteArrayInputStream( new BASE64Decoder().decodeBuffer( thepwd ) );

            InputStream in = new CipherInputStream( bis, dcipher );

            // Read in the decrypted bytes and write the cleartext to out
            int numRead = 0;

            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            while( ( numRead = in.read( buf ) ) >= 0 ) {
                bos.write( buf, 0, numRead );
            }
            return new String( bos.toByteArray() ) ;
        } catch( Exception e ) {
            e.printStackTrace();
        }

Screenshots

Labels

codegeist_2007_crowd codegeist_2007_crowd Delete
plugin plugin Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. May 14, 2007

    Collin Summers says:

    What timing... I was just getting ready to use Penrose for an app that does not ...

    What timing... I was just getting ready to use Penrose for an app that does not have a crowd adapter...

    Now I can use Crowd    which will make my life much easier...

    I have followed the directions ... as minimal as they are   ...  And I can not get any users to return I get "Search "cn=users,ou=Users,dc=example,dc=com" with scope base and filter "(objectClass=*)
    [05/14/2007 14:43:23] Search operation succeded.
    [05/14/2007 14:43:23] Search operation returned 0 entries.
    " every time I try to look at the users via JXplorer...

    Should the userPassword code be entered as text or as an expression?  Any suggestions for further debugging?

    Thanks,

    Collin

    1. May 15, 2007

      Robert Castaneda[CustomWare] says:

      Hi Colin, Thanks for trying this out. The password piece is only required if yo...

      Hi Colin,

      Thanks for trying this out. The password piece is only required if you want to authenticate against LDAP, not browse it. When you craete your source in Penrose Studio, are you able to see the list of results within Penrose Studio itself? this is the first step that needs to be verified before trying to access it externally.

  2. May 22, 2007

    Robert Castaneda[CustomWare] says:

    The SQL for the view is... CREATE OR REPLACE VIEW public.crowdview AS SELECT ...

    The SQL for the view is...

    CREATE OR REPLACE VIEW public.crowd_view AS
     SELECT a."REMOTEPRINCIPALNAME" AS principal_name
    , a."CREDENTIAL" AS the_credential
    , to_char(b."CONCEPTION", 'YYYYMMDDHH24MISSMS'::character varying) AS the_uid FROM 
    "REMOTEPRINCIPALCREDENTIALS" a, "REMOTEPRINCIPAL" b WHERE ((a."REMOTEPRINCIPALNAME")::text = (b."NAME")::text);
  3. Jun 01

    Devon Hillard says:

    Is there any way to get crowd groups linked to the users exposed through ldap? W...

    Is there any way to get crowd groups linked to the users exposed through ldap? We want to tie into LDAP and auth based on what group a user is in. Etc...

    I'm sure it's possible, but the penrose docs are pretty lacking imho.

    Thanks for any help!