Sunday Apr 12, 2009

Webspace Server - Customizing the Default Landing Page

When a user is successfully authenticated against the Webspace server, user will be presented with a page which is known as "Default Landing Page". Which defaults to user's private page (can be configured to a default page for all users with If user is redirected to login page while attempting to access a page (webspace URL to be more specific) then user will be redirected to the original URL upon successful authentication.

In some cases, it is desirable to have a different "landing page" for different users. For example, a company would like to land all the customers to a page other than the employees. This requires more granular configuration for landing page. Though the configuration is not available out of the box, the webspace server provides with option to customize and configure the landing page of a user or can be determined dynamically.

This is possible by writing a custom java class for Post Login hook. I have put together a Wiki with sample code.

Sunday Mar 01, 2009

Verify AM/OpenSSO Attributes

When deployed OpenSSO or Access Manager to secure Web Applications often times it is desirable to “know” what attributes are being returned from OpenSSO to determine certain behavior of a particular application. The Webspace Server provides with an add-on to integrate with OpenSSO and implements Client SDK to accomplish the authentication with OpenSSO. This has been explained in detail at

In case, the authentication issues come up where a user successfully authenticates against OpenSSO but can't login into Web Space server it is very likely that the required attributes are not returned from the OpenSSO via client sdk. The Web Space server logs provide the information about the attributes returned and other related messages. This might require administration access to the log files on the file system.

To display what OpenSSO attributes are returned in the Web Browser I have written a web application “CheckAMAttrs” that would provide the information which looks like below picture. This will help debug any attributes related issues.


For more information and to download the application go the Wiki. Though the Wiki is written specific to the Webspace server, it should work with any other OpenSSO deployments.

Thursday Feb 12, 2009

Integrating WebSpace server with OpenSSO/Access Manager

The WebSpace Server is Sun's Portal Server offering ( Project Websynergy) with great feature set that rightly fit into an enterprise. The WebSpace server provides support for OpenSSO authentication out of the box using OpenSSO's RESTful web services. Having said that, this would not work with Access Manager. To provide support for both OpenSSO and Access Manager, we provide an “addon” which uses the client SDK to perform authentication and currently supports OpenSSO and Access Manager 7.1. In addition to providing authentication, the addon comes bundled with a portlet that would allow an administrator to map OpenSSO/AM role to WebSpace server's Community for content. What it means is that, when a user is added to a role on OpenSSO/AM, the user will be assigned with a memebership to the mapped Community on WebSpace server. However, the permissions are maintained and managed by WebSpace server only.

You can find more information on following Wiki

Tuesday Oct 14, 2008

Deploy and Configure OpenSSO on Glassfish from Command Line

Create a Glassfish domain “opensso “which runs on port 18080 and 18443 (SSL). Admin port running on 14848.

Assume that the Glassfish is installed under /opt/glassfish

$ cd /opt/glassfish/bin

$ ./asadmin create-domain --adminport 14848 --instanceport 18080 --savemasterpassword=true --user admin --savelogin=true --domainproperties http.ssl.port=18443 opensso

Configure the server policy on Glassfish for OpenSSO

As per the installation procedure of OpenSSO for Glassfish it is required to update the server.policy. I have created a file opensso_policy.txt with required contents.

$ cp /opt/glassfish/domains/opensso/config

$ cat opensso_policy.txt >> server.policy

Configure the JVM requirements for OpenSSO

Note: Here I have used GNU sed which allows in place replacement (-i switch). If you are not using GNU sed then you might need to make a copy of the file with change.

$ sed -i "s/<jvm-options>-client<\\/jvm-options>/<jvm-options>-server<\\/jvm-options>/" domain.xml

$ sed -i "s/<jvm-options>-Xmx512m<\\/jvm-options>/<jvm-options>-Xmx1024m<\\/jvm-options>/" domain.xml

Start OpenSSO

$ cd /opt/glassfish/bin

$ ./asadmin start-domain opensso

Deploy OpenSSO war file

Assuming the opensso.war is available under /opt/opensso/deployable-war

$./asadmin deploy --port 14848 --user admin /opt/opensso/deployable-war/opensso.war

Command deploy executed successfully.

Run the OpenSSO configurator

I have written a Java code ( download postOpenSSO.class) that performs a http POST to OpenSSO's configurator.jsp. It reads a configuration input file ( openssodeploy.,config) from the same directory from where it is invoked.

Assume that you have downloaded postConfig.class and openssodeploy.config into /opt/openssodeploy directory. If openssodeploy.config is the default, if not, you can pass the file name to postOpenSSO class.

$ cd /opt/openssodeploy

$ java postOpenSSO

Tuesday Sep 23, 2008

LDAP Password Policy and OpenDS

Password Policy has become an essential and integral part of user account management and many enterprises implement it regardless of the data sources. The most popular data repository for user authentication is LDAP. So, enterprises would obviously looking for a Password Policy on the accounts that are maintained in the LDAP server.

I have been to customers where a LDAP server provides a proprietary Password Policy implementation sometimes it makes it very difficult to accommodate new applications into the system, it makes it difficult to migrate to a new LDAP server for an enterprise. Most importantly, it becomes impossible for any application developer to write Password Policy code that would work with any LDAP server.

So, we have a defined LDAP Password Policy. Contributions provided by Ludovic who is the OpenDS community lead and an Architect in the Sun Directory engineering team, based in Grenoble, France.

Essentially, the LDAP Password Policy is an Internet Draft provides the details of Password Policy implementation for a LDAP server such as OpenDS. Here is the link to the Password Policy implementation of OpenDS.

While we are on the Password Policy topic, I would like to present a real time experience with few LDAP applications that I have come across that implement proprietary password policies. I have worked with some applications (rather products) that would maintain a bunch of attributes to track the password changes such as last login time of the user etc. This means that every time a user accesses an application, the user's LDAP entry is updated. Imagine the number of “Write” operations in a multi-million entry deployment of LDAP server.

To provide a better performance and compatibility with the Password Policy Internet Draft OpenDS generates these attributes are automatically for application developers' convenience.

Friday Sep 19, 2008


I usually get a task to review a LDIF file. I get a LDIF file and i have to "see" the data for whatever task I have to accomplish.

For example, I have to split a "sub tree" under a particular root suffix into a separate database for say replication reasons. I know that, I have to separate the entries of a branch, create a new database and import only those entries pertaining the branch.

Another example would be to just separate a particular branch for review purposes. Perhaps, I can run "ldapsearch" on the live server and obtain data. There are two issues that I usually come across, one is that I may not get access to the server in the first place, secondly, I may not get "all" the data. So, I generally request for a LDIF export of the root suffix so that I can work "offline" on the LDIF.

To address this most common challenge I wrote myself a tool called "ldifpart", written in perl. It would read the LDIF and provides with different levels in the hierarchy, then it can include/exclude to print only entries under a particular sub-tree. This will let me "split" the LDIF at any level of the tree.

$ ldifpart
This script reads a LDIF with entries and drills down the levels.
Prints the entries of a particular level if -l option is provided, else prints all the entries starting at Level 1.
Also available -b option to specify the base DN. Useful to print only a specific branch. To exclude a branch from printing, use -B option
Prints only dn of the entry if -d option is used
usage: ldifpart [-lbBd]
-b: Base DN to include
-B: Base DN to exclude
-d: Print dn lines only
-l: Level of the tree.

Let us look at an example. I wanted to just print the DNs of entries at different levels

$ ldifpart -d example_ldifpart.ldif
#Level: 1
dn: o=Corp
#Level: 2
dn: ou=Groups,o=Corp
dn: ou=People,o=Corp
#Level: 3
dn: cn=Lao Tzu,ou=People,o=Corp
dn: cn=Jon Ruiz,ou=People,o=Corp
dn: cn=Ben Dubin,ou=People,o=Corp
dn: cn=Don Knuth,ou=People,o=Corp
dn: cn=Niels Bohr,ou=People,o=Corp
dn: cn=Ted Geisel,ou=People,o=Corp
dn: cn=Uri Geller,ou=People,o=Corp
dn: cn=HR Managers,ou=groups,o=Corp
dn: cn=John Fowler,ou=People,o=Corp
dn: cn=QA Managers,ou=groups,o=Corp
dn: cn=Rod Serling,ou=People,o=Corp
dn: cn=Rosanna Lee,ou=People,o=Corp
dn: cn=Vinnie Ryan,ou=People,o=Corp
dn: cn=Ian Anderson,ou=People,o=Corp
dn: cn=Roger Waters,ou=People,o=Corp
dn: cn=Jonathan Wood,ou=People,o=Corp
dn: cn=Londo Mollari,ou=People,o=Corp
dn: cn=Maxine Erlund,ou=People,o=Corp
dn: cn=Samuel Clemens,ou=People,o=Corp
dn: cn=Scott Seligman,ou=People,o=Corp
dn: cn=Spuds Mackenzie,ou=People,o=Corp
dn: cn=Colleen Sullivan,ou=People,o=Corp
dn: cn=Accounting Managers,ou=groups,o=Corp
dn: cn=Engineering Managers,ou=groups,o=Corp
dn: cn=Directory Administrators,ou=Groups,o=Corp
#Level: 4
dn: cn=homedir,cn=Jon Ruiz,ou=people,o=Corp
dn: ou=Objects,cn=Rosanna Lee,ou=People,o=Corp
#Level: 5
dn: cn=Button,ou=Objects,cn=Rosanna Lee,ou=People,o=Corp
dn: cn=Choice,ou=Objects,cn=Rosanna Lee,ou=People,o=Corp
dn: cn=Integer,ou=Objects,cn=Rosanna Lee,ou=People,o=Corp
dn: cn=Hashtable,ou=objects,cn=Rosanna Lee,ou=People,o=Corp
dn: cn=CheckboxGroup,ou=Objects,cn=Rosanna Lee,ou=People,o=Corp

Now, suppose i want to branch out "ou=Groups" container to another database then i would need a LDIF that contains only entries under "ou=Groups" including.

$ ldifpart -b "ou=groups,o=corp" example_ldifpart.ldif
#Level: 1
dn: ou=Groups,o=Corp
ou: Groups
objectclass: top
objectclass: organizationalunit

#Level: 2
dn: cn=HR Managers,ou=groups,o=Corp
objectclass: top
objectclass: groupOfUniqueNames
cn: HR Managers
ou: groups
uniquemember: cn=Ted Geisel, ou=People, o=Corp
uniquemember: cn=Lao Tzu, ou=People, o=Corp
description: People who can manage HR entries

dn: cn=QA Managers,ou=groups,o=Corp
objectclass: top
objectclass: groupOfUniqueNames
cn: QA Managers
ou: groups
uniquemember: cn=Jonathan Wood, ou=People, o=Corp
description: People who can manage engineer entries

dn: cn=Accounting Managers,ou=groups,o=Corp
objectclass: top
objectclass: groupOfUniqueNames
cn: Accounting Managers
ou: groups
uniquemember: cn=Niels Bohr, ou=People, o=Corp
uniquemember: cn=Spuds Mackenzie, ou=People, o=Corp
description: People who can manage accounting entries

dn: cn=Engineering Managers,ou=groups,o=Corp
objectclass: top
objectclass: groupOfUniqueNames
cn: Engineering Managers
ou: groups
uniquemember: cn=John Fowler, ou=People, o=Corp
uniquemember: cn=Maxine Erlund, ou=People, o=Corp
description: People who can manage the unmanageable

dn: cn=Directory Administrators,ou=Groups,o=Corp
cn: Directory Administrators
objectclass: top
objectclass: groupofuniquenames
ou: Groups
uniquemember: cn=Rosanna Lee, ou=People, o=Corp
uniquemember: cn=Scott Seligman, ou=People, o=Corp
uniquemember: cn=Jon Ruiz, ou=People, o=Corp
uniquemember: cn=Vinnie Ryan, ou=People, o=Corp

Here is the script, and example LDIF.

Finally, the script normalizes the "DN" in the LDIF and unwraps the attributes that spawn across multiple lines. While this does not violate any LDIF standards some might perceive this as a "side effect". So, be warned. Enjoy.

Monday Sep 15, 2008

LDAP Paged Results - More

To demonstrate what VLV control provides what is missing in 
Simple Paged Results specification, let us examine the data that 
is loaded in OpenDS. 

I have loaded OpenDS with 10001 entries of sample data.
Loading sample data into OpenDS is very simple.
Assume that OpenDS is installed under "/opt/OpenDS" directory. 
cd /opt/OpenDS/bin
./import-ldif -n userRoot -A /opt/OpenDS/config/MakeLDIF/example.template
The tool that I am using here is the "ldapsearch" that is 
shipped with OpenDS which is capable of running LDAP 
searches with both Simple Paged Results control and VLV 

For demonstration purposes, let us add an administrator account.
$ ./ldapmodify -p 1389 -D "cn=directory manager" -w password -a 
dn: uid=admin,ou=people,dc=example,dc=com 
objectClass: top 
objectClass: person 
objectClass: organizationalPerson 
objectClass: inetOrgPerson 
sn: Administrator 
cn: Directory Administrator 
userPassword: password 
Add an ACI to grant full access to "admin" user 
$ ./ldapmodify -p 1389 -D "cn=directory manager" -w password
dn: dc=example,dc=com 
changetype: modify 
add: aci 
aci: (targetattr = "\*")(version 3.0; acl "Admin Access"; allow(all) 
userdn = "ldap:///uid=admin,ou=people,dc=example,dc=com";) 
Grant read permission on Simple Paged Results Control for 
user "admin". 

The OID for Simple Paged Results control is 
$ ./dsconfig -h localhost -p 1389 -D "cn=Directory Manager" -w password set-access-control-
handler-prop \\
--add global-aci:"(targetcontrol=\\"1.2.840.113556.1.4.319\\")(version 3.0; acl \\"Allow Simple Paged 
Results Access\\"; allow(read) userdn = \\"ldap:///uid=admin,ou=people,dc=example,dc=com\\";)" -n 
Let us run the ldapsearch with Simple Paged Results control
./ldapsearch -p 1389 -b "ou=people,dc=example,dc=com" -s one -D 
"uid=admin,ou=people,dc=example,dc=com" -w password --simplePageSize 1000 
SEARCH operation failed 
Result Code: 50 (Insufficient Access Rights) 
Additional Information: You do not have sufficient privileges to perform an unindexed search 
By default, the OpenDS does not allow search with more than 
4000 candidates unless you are using cn=directory manger
One way to fix this is to change the index entry limit to a desired 
value and another way of accomplishing the same is to create an 
administrative account and grant unindexed-search privilege.

I chose the former approach. Not because of any particular 
merit though.

So, let us change the default index limit of the index 
objectCalss to 20,000.
$ ./dsconfig -h localhost -p 1389 -D "cn=directory manager" -w password 
-n set-local-db-index-prop \\ --backend-name userRoot --index-name objectclass 
--set index-entry-limit:20000 
$ ./stop-ds 
$ ./rebuild-index -i objectclass -b dc=example,dc=com 
$ ./start-ds 
Also, grant unlimited lookthrough limit to "admin" user. Here is the 
more information on lookthrough limit.
$ ./ldapmodify -p 1389 -D "cn=directory manager" -w password 
dn: uid=admin,ou=people,dc=example,dc=com 
changetype: modify 
add: ds-rlim-lookthrough-limit 
ds-rlim-lookthrough-limit: -1 
Let us try the ldapsearch again.
./ldapsearch -p 1389 -b "ou=people,dc=example,dc=com" -s one -D 
"uid=admin,ou=people,dc=example,dc=com" -w password --simplePageSize 2000 
"objectclass=inetOrgPerson" dn 
dn: uid=user.0,ou=People,dc=example,dc=com 
dn: uid=user.1,ou=People,dc=example,dc=com 
dn: uid=user.2,ou=People,dc=example,dc=com 
dn: uid=user.3,ou=People,dc=example,dc=com 
SEARCH operation failed 
Result Code: 4 (Size Limit Exceeded) 
Additional Information: This search operation has sent the maximum of 1000 entries to the client 
The above command requests the OpenDS to return all entries in 
pages with 2000 entries per page. However, the client receives LDAP 
error code 4 (Size Limit Exceeded). Which means that the 
server can't send send 2000 entries back to the client as requested. 
The size limit is the constraint that the OpenDS server imposes with 
default value set to 1000. More information on size limit is here.
So, let us tune our ldapsearch and decrease the page size to 1000.
$ ./ldapsearch -p 1389 -b "ou=people,dc=example,dc=com" -s one -D 
"uid=admin,ou=people,dc=example,dc=com" -w password --simplePageSize 1000 
"objectclass=inetOrgPerson" dn 
dn: uid=user.0,ou=People,dc=example,dc=com
dn: uid=user.1,ou=People,dc=example,dc=com
dn: uid=user.2,ou=People,dc=example,dc=com
dn: uid=user.3,ou=People,dc=example,dc=com
dn: uid=user.4,ou=People,dc=example,dc=com
dn: uid=user.5,ou=People,dc=example,dc=com
dn: uid=user.6,ou=People,dc=example,dc=com
dn: uid=user.7,ou=People,dc=example,dc=com
We got our paged results. All of 10002 entries are returned with 
1000 entries at a time. I have noticed that some LDAP server 
administrators use Simple Paged Control to return all
the entries to generate reports, perform other operations on the data.
Now, let us examine VLV control and see how it can provide us 
with a better paged results where a client can request the server to
"sort" on an attribute for the results and where to "start" in the results set.

The VLV Control allows a client to request the server in a

manageable list of entries.

The Control provides following options to the client.

1. before:after:index:count 
before: Specify the number of entries before the target entry 
after: Specify the number of entries after the target entry 
index: Offset to the target entry. Number 1 means first entry 
count: Number of the size of result set for a search filter. 

2. before:after:index 
before: Specify the number of entries before the target entry 
after: Specify the number of entries after the target entry 
index: string within the result set (index=worrell) 

Again, the ldapsearch is the tool to use VLV control . In the following 
command the ldapsearch sends a VLV request to the server with 
following options (-G 0:1:1:0)

before: 0 - Zero entries before the target
after: 1 - One entry after the target
index: 1 - First Entry is the target.
Count: 0 - Unknown. Let the server determine the size.

The server returns two entries two entries one before the target and 
the target itself. Most importantly, the result set is sorted on 
"sn" attribute.
$ ./ldapsearch -p 1389 -b "ou=people,dc=example,dc=com" -s one -D 
"uid=admin,ou=people,dc=example,dc=com" -w password -G 0:1:1:0 --sortOrder sn 
dn: uid=user.4,ou=People,dc=example,dc=com 
objectClass: person 
objectClass: organizationalperson 
objectClass: inetorgperson 
objectClass: top 
postalAddress: Aartjan Aalders$60403 South Street$Salem, MS 22403 
postalCode: 22403 
uid: user.4 
description: This is the description for Aartjan Aalders. 
userPassword: {SSHA}HBLw+/8K4Tf1fjzCyDyyCuhEmAO4+lL2Cmz5rw== 
employeeNumber: 4 
initials: AVA 
givenName: Aartjan 
pager: +1 165 230 1073 
mobile: +1 096 889 4907 
cn: Aartjan Aalders 
telephoneNumber: +1 804 202 6921 
sn: Aalders 
street: 60403 South Street 
homePhone: +1 326 592 0306 
l: Salem 
st: MS 

dn: uid=user.5,ou=People,dc=example,dc=com 
objectClass: person 
objectClass: organizationalperson 
objectClass: inetorgperson 
objectClass: top 
postalAddress: Abagael Aasen$33591 Main Street$Lansing, NV 51577 
postalCode: 51577 
uid: user.5 
description: This is the description for Abagael Aasen. 
userPassword: {SSHA}3OoD2VVJOou9klYCX2i6ayO2LbY2tUF8x5Z3nw== 
employeeNumber: 5 
initials: AQA 
givenName: Abagael 
pager: +1 331 917 5915 
mobile: +1 258 717 0685 
cn: Abagael Aasen 
telephoneNumber: +1 039 625 4980 
sn: Aasen 
street: 33591 Main Street 
homePhone: +1 052 066 4526 
l: Lansing 
st: NV 
# VLV Target Offset: 1 
# VLV Content Count: 10002 
Let us look at another example. Request the server to return the target
entry that whose "sn" attribute begins with "jensen" and one 
followed by the target.
$ ./ldapsearch -p 1389 -b "ou=people,dc=example,dc=com" -s one -D 
"uid=admin,ou=people,dc=example,dc=com" -w password -G 0:1:jensen --sortOrder sn 
dn: uid=user.5814,ou=People,dc=example,dc=com
objectClass: person
objectClass: organizationalperson
objectClass: inetorgperson
objectClass: top
postalAddress: Mollie Jensen$10019 First Street$Hattiesburg, SD 58443
postalCode: 58443
uid: user.5814
description: This is the description for Mollie Jensen.
userPassword: {SSHA}yAKGDBMBn0qTPIksRITI+CxaGem+AH0BzkLYrQ==
employeeNumber: 5814
initials: MHJ
givenName: Mollie
pager: +1 891 013 7026
mobile: +1 139 787 4408
cn: Mollie Jensen
telephoneNumber: +1 880 751 8601
sn: Jensen
street: 10019 First Street
homePhone: +1 016 249 2054
l: Hattiesburg
st: SD

dn: uid=user.5815,ou=People,dc=example,dc=com
objectClass: person
objectClass: organizationalperson
objectClass: inetorgperson
objectClass: top
postalAddress: Molly Jensenworth$31942 Fifteenth Street$Portland, NM 00430
postalCode: 00430
uid: user.5815
description: This is the description for Molly Jensenworth.
userPassword: {SSHA}2Bi8fv6syMvpWYqtO+o7sbe67zdereieAaT/gQ==
employeeNumber: 5815
initials: MTJ
givenName: Molly
pager: +1 327 826 0387
mobile: +1 896 260 6042
cn: Molly Jensenworth
telephoneNumber: +1 004 038 6469
sn: Jensenworth
street: 31942 Fifteenth Street
homePhone: +1 044 105 6790
l: Portland
st: NM
# VLV Target Offset: 5816
# VLV Content Count: 10002
It is now clear that with VLV control the client can determine the 
result set, server side sort attribute and the page size. If you are writing 
a LDAP application with a large amount of data the VLV control is the
best option. 

For example, for an Address Book application you can efficiently
provide paged results based on what user inputs in the "Last Name" 
field instead of going through multiple pages with potentially unwanted 
data in it.

In order to get the above example to work, OpenDS needs some 

We need to tell the server how to handle VLV requests before start 
using VLV control in your application(s). First provide VLV control
access to "admin" user VLV Control OID: 2.16.840.1.113730.3.4.9 
./dsconfig -h localhost -p 1389 -D "cn=Directory Manager" -w password 
set-access-control-handler-prop --add global-aci:"(targetcontrol=\\"2.16.840.1.113730.3.4.9\\")(version 3.0; 
acl \\"Allow Simple Paged Results Access\\"; allow(read) 
userdn = \\"ldap:///uid=admin,ou=people,dc=example,dc=com\\";)" -n 
Create VLV control configuration for the search operation. Please note 
that the "Base DN", "Search Scope", "Search Filter" and the 
"Sort Attribute" should match the configuration in order to make 
VLV to work.

Following dsconfig command adds the following VLV configuration.
Search Base: ou=people,dc=example,dc=com
Search Scope: One Level
Search Filter: "objectclass=inetOrgPerson"
Sort Attribute: sn
$ ./dsconfig -h localhost -p 1389 -D "cn=Directory Manager" -w password 
create-local-db-vlv-index --backend-name userRoot --index-name People_Search 
--set sort-order:sn --set scope:single-level --set base-dn:ou=people,dc=example,dc=com 
--set filter:objectclass=inetOrgPerson -n 
After creating the VLV configuration, the index should be generated 
before using the VLV control.
$ ./stop-ds
$ ./rebuild-index -i vlv.People_Search -b dc=example,dc=com 
$ ./start-ds 
If you are reviewing the DSEE (Directory Server Enterprise
 Edition 6.3) and would like to get the above VLV configuration 
workingon the Sun Directory Server 6.3 perform the following 

Create the VLV configuration LDIF file "vlv.ldif" with following entry.
dn: cn=getsn,cn=example,cn=ldbm database,cn=plugins,cn=config
objectclass: top
objectclass: vlvSearch
cn: getsn
vlvBase: ou=People,dc=example,dc=com
vlvScope: 1
vlvfilter: (objectclass=inetorgperson))
aci: (target="ldap:///cn=getsn,cn=example,cn=ldbm database,cn=plugins,cn=config")(targetattr="\*")
 (version 3.0;acl "Config";allow(read,search,compare)(userdn="ldap:///anyone");)
dn: cn=sortsn,cn=getsn,cn=example,cn=ldbm database,cn=plugins,cn=config
objectclass: top
objectclass: vlvIndex
vlvsort: sn
cn: sortsn
Use ldapmodify to add the configuration to the Server.
$ ./ldapmodify -h localhost -p 1389 -D "cn=Directory Manager" -w password -a -f vlv.ldif
Now, generate the VLV index. Assuming that the Directory Server 
is installed under /opt/DSEE63 and the actual Directory Server instance 
is running under /opt/ds directory.
$ cd /opt/DSEE63/ds6/bin
$ ./dsadm stop /opt/ds
$ ./dsadm reindex -l -t sortsn /opt/ds dc=example,dc=com
$ ./dsadm start /opt/ds
All set. Now, you can run the ldapsearch (shipped with OpenDS 
and also that is shipped with DSEE). I am going to provide an 
example using the "ldapsearch" that is shipped with DSEE. You 
can find the "ldapsearch" under /opt/DSEE63/dsrk6/bin directory 
if you have installed using zip distribution.
$ ./ldapsearch -p 1389 -b "ou=people,dc=example,dc=com" -s one -D 
"uid=admin,ou=people,dc=example,dc=com" -w password -G 0:5:jensen -S sn -x 
"objectclass=inetOrgPerson" dn
version: 1
dn: uid=kjensen, ou=People, dc=example,dc=com
dn: uid=bjensen, ou=People, dc=example,dc=com
dn: uid=gjensen, ou=People, dc=example,dc=com
dn: uid=jjensen, ou=People, dc=example,dc=com
dn: uid=ajensen, ou=People, dc=example,dc=com
dn: uid=bjense2, ou=People, dc=example,dc=com
The Directory Editor which is part of DSEE an 
example of application that uses VLV control for searching 
the Directory Server.

One difference that I have noticed when using Simple Paged 
Results control with ldapsearch, all the entries (10002 in this 
case) are returned for the search filter "objectclass=inetorgperson" 
with 1000 entries per page. However, when the VLV control 
is used in the ldpasearch, I received only first page. I have noticed 
that for some administrators it could be desirable to fetch all the 
entries page wise just like ldpasearch has pulled all entries when 
used with Simple Paged Results. If you are a developer/administrator
 who likes to build tools around LDAP for administration 
purposes to accomplish certain tasks then you can use 
standard LDAP SDK for Java to write any LDAP applications 
in Java.

I have written a Java class using LDAP SDK for Java 
which is part of the DSEE (Directory Server Enterprise Edition), 
can be downloaded from here.

The LDAP SDK for Java can be downloaded separately here.

I have used NetBeans IDE 6.1 to build the jar file. - Performs a LDAP search using VLV Control 
and fetches all the entries page wise.

You will need LDAP SDK for Java to compile. Get it from here. 
If you have installed the DSEE then it will be part of DSRK.

VLVFetchAll.jar - Binary. Built using NetBeans IDE 6.1.
Usage: java VLVFetchAll [-h] [-p] [-b] [-D ] [-w ] [-S] [-s] [-P] [-f] 
-h - LDAP Server host. Default: localhost 
-p - LDAP Server port. Default: 389 
-b - Base DN for search. Default: rootDSE 
-D - Bind DN. Default: anonymous
-w - Bind Password. Defualt: blank
-s - Scope fo the search. Default: one
 Allowed values: base,one,sub
-S - Attribute(s) to sort. Default: sn
-f - Search filter. Mandatory option
-A - Space delimited list of attributes. Default: all attributes
-P - VLV pages size. Default: 2000
java -jar VLVFetchAll -h -b "ou=people,dc=example,dc=com" -D 
"uid=admin,ou=people,dc=example,dc=com" -w password -f 
"(objectclass=posixAccount)"-S "cn uid" -P 1000
In the above example all the entries are fetched that match the filter (objectClass=posixAccount)
Please note that the VLV configuration should already exist. If the Directory Server is configured 
for LDAP naming services for Unix then the above example would work without any issues
If you are a System Administrator with lots of Perl background, 
then you can use Net::LDAP to write a Perl script that exactly 
does the same as the Java class above.

Monday Aug 25, 2008

OpenSSO Training

The OpenSSO community has made training available on "how to deploy". This is free . Just sign up at training page. Create a MySun account and then "Join" when you access the training page. If you are a Sun employee then use your e-mail and LDAP password and then "Join" to access the training material. The direct link to the training is here .

For those who are wondering about what is OpenSSO, It is the Open Web Single Sign-On Project, referred to as OpenSSO, is an open development effort based on the source code for Sun Java System Access Manager and Sun Java System Federation Manager, two identity and federation products offered by Sun Microsystems, Inc. The goal of OpenSSO is to provide an extensible foundation for an identity services infrastructure in the public domain, facilitating single sign-on (SSO) for web applications hosted on web and application servers.

Friday Aug 22, 2008

Directory Server and LDAP Paged Results

Usually, the Directory Serer imposes constraints on a LDAP search as to “how many maximum entries” can be returned to the client for a search filter. This is called the “sizelimit”. Upon reaching this limit server will stop sending the results back with LDAP error code 4 (Size Limit Exceeded.).

In case an application which is a LDAP clients needs more than the configured number of entries, the client can “request” for paged results. Meaning, get results page wise where each page is equal to or less than the “Size Limit” number. One of the popular examples is address book application which contains a huge number of entries and an application that queries the Directory server that would receive large amount of entries.

In order to address such a scenario, the LDAP provides two controls.

One is Simple Pages Results defined in RFC 2696 ( As the name suggests it is a very simple paged results control which informs server to send results sequentially in pages. This is an informational RFC, meaning it is not part of the standard LDAPv3 specification.

Another LDAP control which is more advanced than the one defined in RFC 2696 is VLV Control. VLV stands for Virtual List Control. VLV provides more advanced paged search results than Simple Paged Results control and has been standardized at IETF which potentially become a standard for paged results. The VLV control is defined in the internet-draft “LDAP Extensions for Scrolling View Browsing of Search Results” (

Both, Directory Server 6.3 and OpenDS support VLV control while OpenDS supports both Simple Paged Results as well as VLV.


Srikanth Konjarla


« April 2014