Showing posts with label LDAP. Show all posts
Showing posts with label LDAP. Show all posts

Tuesday, February 03, 2009

Spring LDAP caches user credentials

" Spring-LDAP caches environment properties by default "



I was facing this rather peculiar problem of User Credentials getting cached by Spring LDAP. I discovered this accidentally ( absent-minded, to be precise :) ) . I changed the password of a User in my ApacheDS but tried to login with the old password - and guess what ? it worked !

Well, I looked at the first place I would go to in these situations - the Spring-LDAP Community Forums.

I noticed that the problem has already been discussed in one of the threads.

The solution suggested in the thread is use the setCacheEnvironmentProperties() method in the AbstractContectSource class & set it to false. The Java doc for the API seems to explain this more :-

Set whether environment properties should be cached between requsts for anonymous environment. Default is true; setting this property to false causes the environment Hashmap to be rebuilt from the current property settings of this instance between each request for an anonymous environment.

Well, just one of those queer things in the fascinating Spring LDAP API.

Wednesday, January 21, 2009

Spring LDAP : My experiments

" Spring LDAP is a Java library for simplifying LDAP operations, based on the pattern of Spring's JdbcTemplate. The framework relieves the user of common chores, such as looking up and closing contexts, looping through results, encoding/decoding values and filters, and more. "

Spring LDAP

I took some time to explore the Spring LDAP library & I am impressed with it. The library aims to make a developer productive by eliminating a lot of plumbing code that one would encounter with plain-vanilla JNDI. I have worked on building an User Management application using JNDI & when I compare it with the facilities provided in Spring LDAP, I defenitely would think twice before coding in regular JNDI.

I created a sample application, by using the principles listed out in the Spring LDAP Reference Documentation & some of the samples I found using my favourite Google.

The steps to use Spring LDAP are quite the same for any Spring application :-

1. Get the Spring LDAP libraries.
2. Configure the applicationContext.xml
3. Write any utility classes you may need.
4. Write the Interface and Implementation class.
5. Write a test harness to see if all these gule together & work ( of course, it will ! :) ).

Let's take it one step at a time...

1. Get the Spring LDAP libraries.

You can get it from the Spring LDAP home page.

After downloading the library, you can unizp it & have a look at the README file. The file usually outlines the dependencies very clearly. In my case, I had to include all these libraries in my project :-
  • spring-ldap-core-tiger-x.x.jar
  • Commons Logging
  • Commons Lang
  • Commons Pool
  • spring-beans
  • spring-core
  • spring-context
  • spring-jdbc
  • spring-tx
  • ldapbp
2. Configure the applicationContext.xml

Here's my applicationContext.xml :-

< ?xml version="1.0" encoding="UTF-8"? >
< !DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
<>

< !-- The Spring LDAP Context Source Configuration. The information provided here is used to create an instance of InitialLdapContext -- >
< id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
< name="url" value="ldap://ecmser.idc.oracle.com:389">
< name="base" value="cn=Users,dc=idc,dc=oracle,dc=com">
< name="userDn" value="cn=orcladmin">
< name="password" value="allstate1">
< /bean >

< !-- The Spring LDAP Template executes tcore LDAP functionalities. It requires the Context Source for its operations. -- >
< id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate">
< ref="contextSource">
< /bean >

< !-- Our User Bean that makes uses of the pre-configured Spring LDAP Template-- >
< id="user" class="com.org.sandeep.dao.impl.UserDAOImpl">
< name="ldapTemplate" ref="ldapTemplate">
< /bean >

< /beans >

3. Write any utility classes you may need.

First, I an interface as a placeholder for some of the constants :-

package com.org.sandeep.util;

public interface UserConstants
{
String FIRST_NAME = "cn";
String LAST_NAME = "sn";
String BLANK = "";
String OBJECT_CLASS = "objectclass";
String PERSON = "person";
}


Next, I wrote my bean class :-

package com.org.sandeep.bean;

public class UserBean
{
private String firstName;
private String lastName;

public UserBean()
{
}

public UserBean(String firstName,String lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}

public void setFirstName(String firstName)
{
this.firstName = firstName;
}

public String getFirstName()
{
return firstName;
}

public void setLastName(String lastName)
{
this.lastName = lastName;
}

public String getLastName()
{
return lastName;
}


public String toString()
{
return firstName + " : "+lastName;
}
}

Finally, I wrote an AttributesMapper class the implements Spring's AttributeMapper interface. To quote from the Spring LDAP Reference Manual :-

An interface used by LdapTemplate for mapping LDAP Attributes to beans. Implementions of this interface perform the actual work of extracting results, but need not worry about exception handling. NamingExceptions will be caught and handled correctly by the LdapTemplate class.

Here's my AttributesMapper class :-

package com.org.sandeep.mapper;

import com.org.sandeep.bean.UserBean;
import com.org.sandeep.util.UserConstants;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;

import org.springframework.ldap.core.AttributesMapper;

public class UserMapper implements AttributesMapper
{
public Object mapFromAttributes(Attributes attributes)
{
UserBean userBean = null;

String firstName = null;
String lastName = null;

try
{
firstName = (String)attributes.get(UserConstants.FIRST_NAME).get();
lastName = (String)attributes.get(UserConstants.LAST_NAME ).get();
}
catch (NamingException objNamingException)
{
objNamingException.printStackTrace();
}

if ( firstName != null || lastName != null )
{
userBean = new UserBean(firstName,lastName);
}

return userBean;
}
}


4. Write the Interface and Implementation class.

First, we need an interface :-

package com.org.sandeep.dao;

import com.org.sandeep.bean.UserBean;

import java.util.List;

public interface UserDAO
{
public List get(UserBean user);
public void add(UserBean user);
public void modify(UserBean user);
public void remove(UserBean user);
}
Next, we need an implementation class that uses the interface :-

package com.org.sandeep.dao.impl;

import com.org.sandeep.bean.UserBean;
import com.org.sandeep.dao.UserDAO;
import com.org.sandeep.mapper.UserMapper;

import com.org.sandeep.util.UserConstants;

import java.util.List;

import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;

import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;


public class UserDAOImpl implements UserDAO
{
private LdapTemplate ldapTemplate;

public UserDAOImpl()
{
}

public void setLdapTemplate(LdapTemplate ldapTemplate)
{
this.ldapTemplate = ldapTemplate;
}

public List get(UserBean user)
{

String firstName = null;
String lastName = null;

AndFilter andFilter = null;

firstName = user.getFirstName();
lastName = user.getLastName();

andFilter = new AndFilter();
andFilter.and(new EqualsFilter(UserConstants.OBJECT_CLASS,UserConstants.PERSON));
andFilter.and(new EqualsFilter(UserConstants.FIRST_NAME,firstName));
andFilter.and(new EqualsFilter(UserConstants.LAST_NAME,lastName));

return ldapTemplate.search(UserConstants.BLANK, andFilter.encode(),new UserMapper());
}

public void add(UserBean user)
{
Attributes userAttributes = null;
BasicAttribute userBasicAttribute = null;
DistinguishedName userDN = null;


userAttributes = new BasicAttributes();
userBasicAttribute = new BasicAttribute(UserConstants.OBJECT_CLASS);

userBasicAttribute.add(UserConstants.PERSON);
userAttributes.put(userBasicAttribute);
userAttributes.put(UserConstants.FIRST_NAME, user.getFirstName());
userAttributes.put(UserConstants.LAST_NAME, user.getLastName());

userDN = new DistinguishedName(UserConstants.BLANK);
userDN.add(UserConstants.FIRST_NAME, user.getFirstName());

ldapTemplate.bind(userDN, null, userAttributes);
}

public void modify(UserBean user)
{
Attributes userAttributes = null;
BasicAttribute userBasicAttribute = null;
DistinguishedName userDN = null;


userAttributes = new BasicAttributes();
userBasicAttribute = new BasicAttribute(UserConstants.OBJECT_CLASS);

userBasicAttribute.add(UserConstants.PERSON);
userAttributes.put(userBasicAttribute);
userAttributes.put(UserConstants.FIRST_NAME, user.getFirstName());
userAttributes.put(UserConstants.LAST_NAME, user.getLastName());

userDN = new DistinguishedName(UserConstants.BLANK);
userDN.add(UserConstants.FIRST_NAME, user.getLastName());

ldapTemplate.rebind(userDN, null, userAttributes);
}

public void remove(UserBean user)
{
DistinguishedName userDN = new DistinguishedName(UserConstants.BLANK);
userDN.add(UserConstants.FIRST_NAME, user.getFirstName());
ldapTemplate.unbind(userDN);
}
}


5. Write a test harness to see if all these gule together & work

Well, we have reached the finish line ! The only remaining step is to see if all these gel together !

Here's my test client :-

package com.org.sandeep.client;

import com.org.sandeep.bean.UserBean;
import com.org.sandeep.dao.UserDAO;

import java.util.List;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessException;


public class UserClient
{

public static void main(String[] args)
{
try
{
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(resource);
UserDAO userDAO = (UserDAO)factory.getBean("user");

UserBean userBean = new UserBean("Sandeep","Seshan");

userDAO.add(userBean);

System.out.println("Done");

List userList = userDAO.get(userBean);

System.out.println("User "+userList);

userDAO.remove(userBean);

System.out.println("Done & Deleted");

}
catch (DataAccessException objDataAccessException )
{
objDataAccessException .printStackTrace();
}
}
}


That's it ! It's that simple !


Wednesday, July 09, 2008

LDAP Search : Search for a user in Oracle Internet Directory

The need to search for a user's entry in Oracle Internet directory (OID) crops up very often in various situations.

You can easily do this using JNDI. You need to usually take care of these things before we proceed with the code :-

1. You have access to Oracle Internet Directory.

2. You know the Distinguished Name ( DN ) of the entry that is the immediate parent of all the users.

3. You know the attribute used to search. E.g.: cn, mail, sn, etc.

4. You know that the attribute used to search has been "indexed" by Oracle Internet Directory.
You can then adapt this piece of code to suit your needs & look for users - the lines marked in red are important :-

String strSearchString = "sandeep";

String strLDAPUrl = "ldap://localhost:389";

String strUserRootDN = "cn=Users,dc=test,dc=com";
String strFilter = "cn="+strSearchString ;

Hashtable env = new Hashtable();

env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, strLDAPUrl);
env.put(Context.SECURITY_AUTHENTICATION, "simple");

// You know the credentials to search in OID
env.put(Context.SECURITY_PRINCIPAL, "cn=orcladmin");
env.put(Context.SECURITY_CREDENTIALS, "mySecretPassword");

try
{

DirContext ctx = new InitialDirContext(env);
Attributes attrs = ctx.getAttributes(strUserRootDN,strFilter,new String[]{"mail"});

Attribute attr = attrs.get("mail");
System.out.println(attr.get());

ctx.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
You can easily modify this piece of code to search for users in a group, etc.

Friday, July 04, 2008

Oracle AS SSO : How to get important user information from SSO and OID

The Oracle AS 10.1.2 Single Sign on places useful user information in the HTTP request Headers. The partner application can access these request headers & get this useful information.

We can use this information provided by the Oracle AS 10.1.2 Single Sign on and query the underlying Oracle Internet Directory ( OID ) directly to obtain useful user information.

The three critical assumptions that we need to make at this point are :-

1. We are able to get the OSSO-User-Dn value from the request header.

2. We are able to connect to the OID anonymously, to read the user information ( so that we need to unnecessarily authenticate again. ).

3. We have access to the underlying OID ( usually, the OID is protected by a DMZ layer & ports may need to be opened at the firewall ).


We can proceed to write a simple JNDI code ( simple garden variety code, obtained from the Sun JNDI Tutorial Trail ) to get important user information from OID :-

DirContext objRootContext = null;
Hashtable objHashtable = null;
Attributes objUserAttributes = null;
Attribute objEmail = null;
Attribute objPhone = null;
String strEmail = null;
String strPhone = null;

objHashtable = new Hashtable();

// Let's get the User DN from Single Sign On.
// CRITICAL ASSUMPTION : We get the User DN value from the SSO.
strUserDN = request.getHeader(“Osso-User-Dn”);

// Let's connect to the OID used by Oracle AS Single Sign on
// CRITICAL ASSUMPTION : We can access the OID objHashtable.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
objHashtable.put(Context.PROVIDER_URL,"ldap://localhost:389/");
objHashtable.put(Context.SECURITY_PRINCIPAL,strUserDN);
// CRITICAL ASSUMPTION : The OID should provide anonymous access.
objHashtable.put(Context.SECURITY_CREDENTIALS,"");

// Let's lookup the user from the root node.
objRootContext = new InitialDirContext(objHashtable);
objRootContext = (DirContext) objRootContext.lookup(strUserDN);

// Let's get all the attributes
objUserAttributes = objRootContext.getAttributes("");

// Let's pull out only the attributes we are interested in.
objEmail = objUserAttributes.get("mail");
objPhone = objUserAttributes.get("phone");

if(objEmail!=null)
{
strEmail = (String) objEmail.get();
}

if(objPhone!=null)
{
strPhone = (String) objPhone.get();
}
We can now comfortably get the user information & use it further downstream in our applications.

Oracle AS SSO : How to get the User DN in a Java Application?

The Oracle AS 10.1.2 Single Sign on places useful user information in the HTTP request Headers. The partner application can access these request headers & get this useful information.

The authenticated user's distinguished name ( DN ) is a very important attribute. The DN can be used to pull out more information about the user from Oracle Internet Directory - e.g : the email address, the phone number, etc.

You can easily get the user dn of the authenticated user from the request , by using this code snippet :-

String strUserDN = request.getHeader(“Osso-User-Dn”);
The DN can then be coupled with a simple JNDI Code to retrieve other attributes.

Tuesday, July 01, 2008

Oracle 10.1.3.x JavaSSO : LDAP Configuration Checklist

" In AS 10.1.3.x Oracle came up with the JavaSSO. Seems to be (from a high level perspective) a poor man's version of the SSO from the AS 10.1.2.x. "

Andreas

I have to agree with Andreas. The JavaSSO solution bundled with the Oracle Application Server 10.1.3.x is definitely a poor man's SSO, with a few basic options & very little available documentation.

I am with Oracle Application Server 10.1.3.x JavaSSO & was trying to configure it with an Oracle Internet Directory. I hit a lot of "gotchas" & had to spend a lot of time wading through the documentation to get it working.

I guess I need a small "checklist" to summarize the steps I took to get it to work :-

1. Configure the OID as a Security Provider in the OC4J.
2. Start the JavaSSO application ( it is switched off by default ).
3. Configure JavaSSO to use the OID Security Provider.
4. Configure your application's web.xml & list the security settings.
4. Deploy the Application - ensure that the "Enable JavaSSO" option is checked at deploy time. You can do it later too from the administration console.
5. Ensure that the deployed uses the OID Security Provider.
6. Configure the deployed application as a Partner Application in JavaSSO.


I'll provide more information on some of these steps in future posts.



Monday, June 23, 2008

Apache Directory Server : Default Settings

" We strive to increase LDAP awareness, comfort and adoption to bring forth what we call the Modern LDAP Renaissance. "



I just downloaded and installed the Apache Directory Server. It took less than 5 minutes to install the server & start it.

The Apache Directory Server is one of the best LDAP Servers that I have used, during prototyping stages. It's very easy to install & very fast in operation.

However, I did observe in a couple of customer engagements that I had to look a bit through the documentation to get a list of the default configuration. I just want to list the default configuration that I use frequently here, to save a bit of time :-

Defalut Host : localhost
Default Port : 10389
Admin user : uid=admin, ou=system
Admin pass : secret
Base DN : ou=system
Initial context Factory : com.sun.jndi.ldap.LdapCtxFactory


Overall, the Apache Directory Project is simply too good !