Return-Path: X-Original-To: apmail-directory-commits-archive@www.apache.org Delivered-To: apmail-directory-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 4181AD389 for ; Tue, 2 Oct 2012 16:41:05 +0000 (UTC) Received: (qmail 72564 invoked by uid 500); 2 Oct 2012 16:41:05 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 72499 invoked by uid 500); 2 Oct 2012 16:41:05 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 72491 invoked by uid 99); 2 Oct 2012 16:41:05 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 02 Oct 2012 16:41:05 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 02 Oct 2012 16:41:02 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 4BBE4238899C for ; Tue, 2 Oct 2012 16:40:19 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r833770 - in /websites/staging/directory/trunk/content: ./ api/groovy-ldap-user-guide.html api/groovy-ldap.html Date: Tue, 02 Oct 2012 16:40:19 -0000 To: commits@directory.apache.org From: buildbot@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20121002164019.4BBE4238899C@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: buildbot Date: Tue Oct 2 16:40:18 2012 New Revision: 833770 Log: Staging update by buildbot for directory Added: websites/staging/directory/trunk/content/api/groovy-ldap-user-guide.html websites/staging/directory/trunk/content/api/groovy-ldap.html Modified: websites/staging/directory/trunk/content/ (props changed) Propchange: websites/staging/directory/trunk/content/ ------------------------------------------------------------------------------ --- cms:source-revision (original) +++ cms:source-revision Tue Oct 2 16:40:18 2012 @@ -1 +1 @@ -1392920 +1393024 Added: websites/staging/directory/trunk/content/api/groovy-ldap-user-guide.html ============================================================================== --- websites/staging/directory/trunk/content/api/groovy-ldap-user-guide.html (added) +++ websites/staging/directory/trunk/content/api/groovy-ldap-user-guide.html Tue Oct 2 16:40:18 2012 @@ -0,0 +1,350 @@ + + + + + Groovy LDAP User Guide — Apache Directory + + + + + + +
+ +
+
+ + + +
+
+ +

Groovy LDAP User Guide

+ +
+

Note: This guide is work in progress and is written at the same time as Groovy LDAP integration developes. The API may change. Feedback highly welcome.

+
+ +

Prerequisites

+
    +
  • Java SE 5 (JDK 1.5) or above
  • +
  • Groovy 1.0 or above
  • +
+

Installation

+

You only have to add the jar file groovy-ldap.jar with the Groovy LDAP classes to the class path. If you plan to write Groovy scripts whoich use the functionality, an easy option is to copy the library into the lib folder of your Groovy installation.

+

That's it.

+

Connection to an LDAP server

+

Main entry point is the class LDAP from the org.apache.directory.groovyldap package (contained in groovy-ldap.jar). You obtain an instance via a call to a static method newInstance, like this:

+
import org.apache.directory.groovyldap.LDAP
+
+ldap = LDAP.newInstance('ldap://zanzibar:10389/')
+...
+
+ + +

The argument used here is the LDAP URL of your directory server and contains hostname and port. This method as shown above is for anonymous binds. A variant of it expects the bind name of a user and his/her credentials:

+
...
+ldap = LDAP.newInstance('ldap://zanzibar:10389/', 'uid=admin,ou=system', '******')
+...
+
+ + +

Please note that Groovy LDAP uses JNDI and its configuration facilities. This means that if you provide a jndi.properties file in your class path, Groovy LDAP will take these parameters into account. This enables you to keep your user name and password outside of the script code, for instance.

+

Like with JNDI with its InitialContext, calling newInstance will not connect to the LDAP server immediately. This means that an authentication will likely occur later (with the first operation).

+

Basic LDAP operations

+

Groovy LDAP basically supports the operations provided by the native LDAP protocol, with some exceptions:

+
    +
  • It is not necessary to connect explicitly to the server or to bind/unbind. Groovy LDAP performs these operations automatically.
  • +
  • LDAP controls are not supported yet
  • +
  • No asynchronous calls are supported yet. Consequently, no abandon operation is available in the API
  • +
+

LDAP add operation

+

The add operation is used to create a new entry within the directory.

+

One option in Groovy LDAP is to define the attribute values of the new entry as a Map. One add operation takes the distinguished name (DN) of the new entry (as a String) and the attributes map as parameters. Here is an example:

+
import org.apache.directory.groovyldap.LDAP
+
+ldap = LDAP.newInstance('ldap://zanzibar:10389', 'uid=admin,ou=system' ,'******')
+
+assert ! ldap.exists('cn=Heather Nova,dc=example,dc=com')
+
+// define the attributes as a map
+attrs = [
+  objectclass: ['top', 'person'],              
+  sn: 'Nova',
+  cn: 'Heather Nova'
+]
+ldap.add('cn=Heather Nova,dc=example,dc=com', attrs)
+
+assert ldap.exists('cn=Heather Nova,dc=example,dc=com')
+
+ + +

In the assert expressions, the exists method of Groovy LDAP is used. It checks whether an entry with this DN already exists (see below).

+

If no error occurs, the script adds the following entry to the directory:

+
dn: cn=Heather Nova,dc=example,dc=com
+cn: Heather Nova
+sn: Nova
+objectClass: person
+objectClass: top
+
+ + +

LDAP delete operation

+

The delete operation is used to delete an existing entry within the directory. As in the original LDAP protocol, only the deletion of leaf entries is allowed. Deletion of a subtree of entries (for instance with the Tree Delete Control) is not supported yet.

+

Here is an example script which uses the delete method from Groovy LDAP.

+
import org.apache.directory.groovyldap.LDAP
+
+ldap = LDAP.newInstance('ldap://zanzibar:10389', 'uid=admin,ou=system' ,'******')
+
+assert ldap.exists('cn=Heather Nova,dc=example,dc=com')
+
+// delete the entry with the given DN
+ldap.delete('cn=Heather Nova,dc=example,dc=com')
+
+assert !ldap.exists('cn=Heather Nova,dc=example,dc=com')
+
+ + +

Note that if the given entry does not exist, calling delete throws a javax.naming.NameNotFoundException. This is different to JNDI, where no error will occur in this case. The behavior here imitates the original LDAP delete operation. In the example script, this will not occur due to the assert statements.

+

LDAP search operation

+
import org.apache.directory.groovyldap.*
+
+ldap = LDAP.newInstance('ldap://zanzibar:10389/')
+
+// search op
+results = ldap.search('(objectClass=*)', 'dc=example,dc=com', SearchScope.ONE )
+println "${results.size} entries found:"
+for (entry in results) {
+  println entry.dn
+}
+
+ + +

The output looks like:

+
3 entries found:
+cn=Tori Amos,dc=example,dc=com
+cn=Kate Bush,dc=example,dc=com
+cn=Heather Nova,dc=example,dc=com
+
+ + +

Learn more about options on how to search within a directory in the [Reference|5. Groovy LDAP Reference]

+

LDAP compare operation

+

The compare operation is used to check attribute value assertions.

+

The following script adds an entry and uses compare several times to demonstrate the different matching rules for attribute type cn (case insensitive) and userPassword (case sensitive).

+
import org.apache.directory.groovyldap.LDAP
+
+ldap = LDAP.newInstance('ldap://zanzibar:10389', 'uid=admin,ou=system' ,'******')
+
+assert ! ldap.exists('cn=Heather Nova,dc=example,dc=com')
+
+// define an entry for compare ops
+attrs = [
+  objectclass: ['top', 'person'],              
+  sn: 'Nova',
+  cn: 'Heather Nova',
+  userPassword: 'secret'
+]
+ldap.add('cn=Heather Nova,dc=example,dc=com', attrs)
+
+assert ldap.exists('cn=Heather Nova,dc=example,dc=com')
+
+assert ldap.compare('cn=Heather Nova,dc=example,dc=com', [cn: 'Heather Nova'] )
+assert ldap.compare('cn=Heather Nova,dc=example,dc=com', [cn: 'HEATHER NOVA'] )
+
+assert ldap.compare('cn=Heather Nova,dc=example,dc=com', [userPassword: 'secret'] )
+assert ! ldap.compare('cn=Heather Nova,dc=example,dc=com', [userPassword: 'SECRET'] )
+
+ldap.delete('cn=Heather Nova,dc=example,dc=com')
+
+ + +

LDAP modify operation

+

I am not perfectly happy with the syntax for modify yet. Here are two calls that perform modifications against the entry added above:

+
import org.apache.directory.groovyldap.*
+
+ldap = LDAP.newInstance('ldap://zanzibar:10389', 'uid=admin,ou=system' ,'secret')
+
+dn = 'cn=Heather Nova,dc=example,dc=com'
+
+// Adding a single attribute
+descr = [ description: 'a singer-songwriter' ]
+ldap.modify(dn, 'ADD', descr)
+
+// performing two operations atomically
+mods = [ 
+    [ 'REPLACE', [description: 'a singer-songwriter, born in Bermuda'] ],
+    [ 'ADD', [userPassword: 'secret'] ]
+]
+ldap.modify(dn, mods)
+
+ + +

The second call uses a list mods of modifications as an argument; each modification consists of a list of two elements (a pair): the modification type and a map with the attribute(s).

+

Afterwards, the entry looks like this in the directory

+
dn: cn=Heather Nova,dc=example,dc=com
+cn: Heather Nova
+sn: Nova
+objectClass: person
+objectClass: top
+userpassword: secret
+description: a singer-songwriter, born in Bermuda
+
+ + +

Additions to the original LDAP API

+

LDAP.exists(...): Checking whether an entry exist

+

implemented, but not documented yet

+

LDAP.read(...): Reading an entry by its distinguished name

+

I have included a read operation as in the Netscape API -- note that there is nothing like that in LDAP (you have to perform a search for it). Nevertheless, it is quite handy to have it. In this example I have use an anonymous LDAP connection. My LDAP server allows me to read entries without user and password (which is quite common).

+
import org.apache.directory.groovyldap.LDAP
+
+ldap = LDAP.newInstance("ldap://zanzibar:10389")
+
+// Simple entry lookup via dn
+heather = ldap.read('cn=Heather Nova,dc=example,dc=com')
+
+print """
+DN: ${heather.dn}
+Common name: ${heather.cn}
+Object classes: ${heather.objectclass}
+"""
+
+ + +

The output (if this entry exists) is:

+
DN: cn=Heather Nova,dc=example,dc=com
+Common name: Heather Nova
+Object classes: ["person", "top"]
+
+ + +

LDAP the Groovy way

+

Performing searches with closures

+

There is a search variant in the LDAP class comparable to eachRow in GSQL. It takes a closure as parameter. I have added the search base to the ldap URL. There is also a variant which takes the base and a scope (defaults to subtree).

+
import org.apache.directory.groovyldap.LDAP
+
+ldap = LDAP.newInstance('ldap://zanzibar:10389/dc=example,dc=com')
+
+ldap.eachEntry ('(objectClass=person)') { person ->  
+    println person.cn
+}
+
+ + +

The output looks like:

+
Tori Amos
+Kate Bush
+Heather Nova
+
+ +
+
+
+ +
+ + \ No newline at end of file Added: websites/staging/directory/trunk/content/api/groovy-ldap.html ============================================================================== --- websites/staging/directory/trunk/content/api/groovy-ldap.html (added) +++ websites/staging/directory/trunk/content/api/groovy-ldap.html Tue Oct 2 16:40:18 2012 @@ -0,0 +1,199 @@ + + + + + Five Minutes Tutorial — Apache Directory + + + + + + +
+ +
+
+ + + +
+
+ +

Groovy LDAP

+ +

Learn about an attempt to make LDAP available from Groovy scripts in a way, LDAP people would expect.

+ +

Feel free to provide feedback: dev@directory.apache.org

+
+

Note: Please note that this is not an official sub project of Apache Directory yet. There are no official releases. However if interest in this client library increases, it may become a sub project very soon.

+
+

Mission Statement

+

Create a way to access LDAP from Groovy scripts, which is suitable for people familiar to LDAP. Primary audience are people who plan to write simple scripts against their LDAP servers. This is not about LDAP abstraction. The API should be comparable to the native LDAP library for C, in order to provide an easy start for the primary target group. Nevertheless it should "smell" like other Groovy integration solutions (namely GSQL) do. Especially the use of closures is planned. In order to reduce the number of dependencies, nothing besides Java SE and Groovy itself should be used. JNDI will therefore be used under the hood to communicate with LDAP.

+
    +
  • Why this? Learn more about the origin of this attempt here.
  • +
+

How it looks like in Groovy

+

Here are two example scripts which use Groovy LDAP in order to give you a first impression. Learn more about how to use Groovy LDAP in the User Guide.

+

Adding an entry

+

The attribute values of an LDAP entry can be defined with the help of the expressive Map syntax of Groovy ([DIRxSBOX:...)). The following script uses the add operation to create a new entry in the directory:

+
import org.apache.directory.groovyldap.LDAP
+
+ldap = LDAP.newInstance('ldap://zanzibar:10389', 'uid=admin,ou=system', '******')
+
+heather = [
+  objectclass: ['top', 'person'],              
+  sn: 'Nova',
+  cn: 'Heather Nova'
+]
+
+ldap.add('cn=Heather Nova,dc=example,dc=com', heather)
+
+ + +

In LDIF format, the entry in the directory looks like this afterwards.

+
dn: cn=Heather Nova,dc=example,dc=com
+cn: Heather Nova
+sn: Nova
+objectClass: person
+objectClass: top
+
+ + +

Performing an LDAP search with a closure

+

Besides the operations found in the classic LDAP API, Groovy LDAP provides advanced functionality with the help of features specific to the Groovy language. Here is an example which performs a search operation, and executes the behavior given via a closure for each entry found:

+
import org.apache.directory.groovyldap.LDAP
+
+ldap = LDAP.newInstance('ldap://zanzibar:10389/dc=example,dc=com')
+
+ldap.eachEntry (filter: '(objectClass=person)') { entry ->  
+    println "${entry.cn} (${entry.dn})"
+}
+
+ + +

The example also shows how to access attributes and the distinguished name (DN) of an entry (Map syntax, as well). The output looks like this:

+
Tori Amos (cn=Tori Amos,dc=example,dc=com)
+Kate Bush (cn=Kate Bush,dc=example,dc=com)
+Heather Nova (cn=Heather Nova,dc=example,dc=com)
+...
+
+ + +

Current status

+

Creation of the solution has just been started. We do not know, whether it will become an official project with releases and so (no official release yet). Even the name is not final yet. The current version only supports five of the LDAP operations (search, add, delete, compare, modify) explicitly.

+

Get involved

+

Feel free to ask questions and provide feedback! Use the Apache Directory mailing lists for this purpose.

+

For issue tracking, Groovy LDAP has a project within the JIRA installation of the Apache Software Foundation.

+

Alternatives

+

There are other efforts to bring the Groovy and the LDAP World together. +An interesting alternative to Groovy LDAP is Gldapo (http://gldapo.codehaus.org/)

+

Where to go from here

+ + +
+
+
+ +
+ + \ No newline at end of file