Adobe ColdFusion 8

Advanced topics

Some more advanced techniques enable you to use LDAP directories more effectively.

Specifying an attribute that includes a comma or semicolon

LDAP attribute values can contain commas. The cfldap tag normally uses commas to separate attribute values in a value list. Similarly, an attribute can contain a semicolon, which cfldap normally uses to delimit (separate) attributes in an attribute list. To override the default separator and delimiter characters, you use the cfldap tag separator and delimiter attributes.

For example, assume you want to add the following attributes to an LDAP entry:

cn=Proctor, Goodman, and Jones
description=Friends of the company; Rationalists

Use the cfldap tag in the following way:

<cfldap action="modify"
    modifyType="add"
    attributes="cn=Proctor, Goodman, and Jones: description=Friends of the company;
        Rationalists"
    dn="uid=goodco, ou=People, o=Airius.com"
    separator="&"
    delimiter=":"
    server=#myServer#
    username=#myUserName#
    password=#myPassword#>

Using cfldap output

You can create a searchable Verity collection from LDAP data. For an example of building a Verity collection using an LDAP directory, see Indexing query results obtained from an LDAP directory.

The ability to generate queries from other queries is very useful when cfldap queries return complex data. For more information on querying queries, see Using Query of Queries.

Viewing a directory schema

LDAP v3 exposes a directory's schema information in a special entry in the root DN. You use the directory root subschemaSubentry attribute to access this information.

The following ColdFusion query shows how to get and display the directory schema. It displays information from the schema's object class and attribute type definitions. For object classes, it displays the class name, superior class, required attribute types, and optional attribute types. For attribute types, it displays the type name, type description, and whether the type is single- or multivalued.

The example does not display all the information in the schema. For example, it does not display the matching rules. It also does not display the object class IDs, attribute type IDs, attribute type syntax IDs, or the object class descriptions. (The object class description values are all "Standard Object Class.")

Note: To be able to view the schema for an LDAP server, the server must support LDAP v3

This example does not work on iPlanet Directory Server 5.0. It does work on a 4.x server.

View the schema for an LDAP directory

  1. Create a file that looks like the following:
    <html>
    <head>
        <title>LDAP Schema</title>
    </head>
    
    <body>
    <!--- Start at Root DSE to get the subschemaSubentry attribute. --->
    <cfldap 
        name="EntryList"
        server="ldap.mycorp.com"
        action="query"
        attributes="subschemaSubentry"
        scope="base"
        start="">
    
    <!--- Use the DN from the subschemaSubEntry attribute to get the schema. --->
    <cfldap 
        name="EntryList2"
        server="ldap.mycorp.com"
        action="query"
        attributes="objectclasses, attributetypes"
        scope="base"
        filter="objectclass=*"
        start=#entryList.subschemaSubentry#>
    
    <!--- Only one record is returned, so query loop is not required. --->
    <h2>Object Classes</h2>
    <table border="1">
        <tr>
            <th>Name</th>
            <th>Superior class</th>
            <th>Must have</th>
            <th>May have</th>
        </tr>
        <cfloop index = "thisElement" list = #Entrylist2.objectclasses#>
            <cfscript>
                thiselement = Trim(thisElement);
                nameloc = Find("NAME", thisElement);
                descloc = Find("DESC", thisElement);
                suploc = Find("SUP", thisElement);
                mustloc = Find("MUST", thisElement);
                mayloc = Find("MAY", thisElement);
                endloc = Len(thisElement);
            </cfscript>
            <tr>
                <td><cfoutput>#Mid(thisElement, nameloc+6, descloc-nameloc-8)#
                    </cfoutput></td>
                <cfif #suploc# NEQ 0>
                    <td><cfoutput>#Mid(thisElement, suploc+5, mustloc-suploc-7)#
                    </cfoutput></td>
                <cfelse>
                    <td>NONE</td>
                </cfif>
                <cfif #mayloc# NEQ 0>
                    <td><cfoutput>#Replace(Mid(thisElement, mustloc+6,
                        mayloc-mustloc-9), " $ ", ", ", "all")#</cfoutput></td>
                    <td><cfoutput>#Replace(Mid(thisElement, mayloc+5, endloc-mayloc-8),
                        " $ ", ", ", "all")#</cfoutput></td>
                <cfelse>
                    <td><cfoutput>#Replace(Mid(thisElement, mustloc+6,
                        endloc-mustloc-9), " $ ", ", ", "all")#</cfoutput></td>
                    <td>NONE</td>
                </cfif>
            </tr>
        </cfloop> 
    </table>
    <br><br>
    
        <h2>Attribute Types</h2>
    <table border="1" >
        <tr>
            <th>Name</th>
            <th>Description</th>
            <th>multivalued?</th>
        </tr>
        <cfloop index = "thisElement" 
            list = #ReplaceNoCase(EntryList2.attributeTypes, ", alias", "<br> Alias", 
            "all")# delimiters = ",">
            <cfscript>
                thiselement = Trim(thisElement);
                nameloc = Find("NAME", thisElement);
                descloc = Find("DESC", thisElement);
                syntaxloc = Find("SYNTAX", thisElement);
                singleloc = Find("SINGLE", thisElement);
                endloc = Len(thisElement);
            </cfscript>
            <tr>
                <td><cfoutput>#Mid(thisElement, nameloc+6, descloc-nameloc-8)#
                    </cfoutput></td>
                <td><cfoutput>#Mid(thisElement, descloc+6, syntaxloc-descloc-8)#
                    </cfoutput></td>
                <cfif #singleloc# EQ 0>
                     <td><cfoutput>Yes</cfoutput></td>
                <cfelse>
                     <td><cfoutput>No</cfoutput></td>
                </cfif>
            </tr>
        </cfloop> 
    </table>
    </body>
    </html>
    

  2. Change the server from ldap.mycorp.com to your LDAP server. You might also need to specify a user ID and password in the cfldap tag.
  3. Save the template as ldapschema.cfm in myapps under your web root directory and view it in your browser.

Reviewing the code

The following table describes the code and its function:

Code

Description

<cfldap name="EntryList" server="ldap.mycorp.com" action="query" attributes="subschemaSubentry" scope="base" start="">

Gets the value of the subschemaSubentry attribute from the root of the directory server. The value is the DN of the schema.

<cfldap name="EntryList2" server="ldap.mycorp.com" action="query" attributes="objectclasses,attributetypes" scope="base" filter="objectclass=*" start=#entryList.subschemaSubentry#>

Uses the schema DN to get the objectclasses and attributetypes attributes from the schema.

<h2>Object Classes</h2> <table border="1"> <tr> <th>Name</th> <th>Superior class</th> <th>Must have</th> <th>May have</th> </tr> <cfloop index = "thisElement" list = #Entrylist2.objectclasses#> <cfscript> thisElement = Trim(thisElement); nameloc = Find("NAME", thisElement); descloc = Find("DESC", thisElement); suploc = Find("SUP", thisElement); mustloc = Find("MUST", thisElement); mayloc = Find("MAY", thisElement); endloc = Len(thisElement); </cfscript>

Displays the object class name, superior class, required attributes, and optional attributes for each object class in a table.

The schema contains the definitions of all object classes in a comma delimited list, so the code uses a list type cfloop tag.

The thisElement variable contains the object class definition. Trim off any leading or trailing spaces, then use the class definition field keywords in Find functions to get the starting locations of the required fields, including the Object class ID. (The ID is not displayed.)

Gets the length of the thisElement string for use in later calculations.

<tr> <td><cfoutput>#Mid(thisElement, nameloc+6, descloc-nameloc-8) #</cfoutput></td> <cfif #suploc# NEQ 0> <td><cfoutput>#Mid(thisElement, suploc+5, mustloc-suploc-7)# </cfoutput></td> <cfelse> <td>NONE</td> </cfif> <cfif #mayloc# NEQ 0> <td><cfoutput>#Replace (Mid(thisElement, mustloc+6, mayloc-mustloc-9), " $ ", ", ", "all")#</cfoutput></td> <td><cfoutput>#Replace (Mid(thisElement, mayloc+5, endloc-mayloc-8), " $ ", ", ", "all")#</cfoutput></td> <cfelse> <td><cfoutput>#Replace (Mid(thisElement, mustloc+6, endloc-mustloc-9), " $ ", ", ", "all")#</cfoutput></td> <td>NONE</td> </cfif> </tr> </cfloop> </table>

Displays the field values. Uses the Mid function to extract individual field values from the thisElement string.

The top object class does not have a superior class entry. Handles this special case by testing the suploc location variable. If the value is not 0, handles normally, otherwise, output "NONE".

There might not be any optional attributes. Handles this case similarly to the superior class. The calculation of the location of required attributes uses the location of the optional attributes if the field exists; otherwise, uses the end of the object class definition string.

<h2>Attribute Types</h2> <table border="1" > <tr> <th>Name</th> <th>Description</th> <th>Multivalued?</th> </tr> <cfloop index = "thisElement" list = #ReplaceNoCase(attributeTypes, ", alias", "<br> Alias", "all")# delimiters = ","> <cfscript> thiselement = Trim(thisElement); nameloc = Find("NAME", thisElement); descloc = Find("DESC", thisElement); syntaxloc = Find("SYNTAX", thisElement); singleloc = Find("SINGLE", thisElement); endloc = Len(thisElement); </cfscript> <tr> <td><cfoutput>#Mid(thisElement, nameloc+6, descloc-nameloc-8)# </cfoutput></td> <td><cfoutput>#Mid(thisElement, descloc+6, syntaxloc-descloc-8) #</cfoutput></td> <cfif #singleloc# EQ 0> <td><cfoutput>Yes</cfoutput> </td> <cfelse> <td><cfoutput>No</cfoutput> </td> </cfif> </tr> </cfloop> </table> </cfloop>

Does the same types of calculations for the attribute types as for the object classes.

 

 

 

The attribute type field can contain the text ", alias for....". This text includes a comma, which also delimits attribute entries. Use the REReplaceNoCase function to replace any comma that precedes the word "alias" with an HTML <br> tag.

 

 

 

The attribute definition includes a numeric syntax identifier, which the code does not display, but uses its location in calculating the locations of the other fields.