Interacting with Directories


For the examples in this chapter, most LDAP servers will support the conventions used. You may, however, run into situations where certain attributes or object classes do not work, depending on the LDAP software you're using. To understand more about the specific structure of your platform, check the documentation included with it.

NOTE

One of the entities used in these examples is exclusive to ExchangeRecipients. If you're using another LDAP package, be sure to replace Recipients with the entity that contains your users.


ADSI and Exchange

To gain access to directories on Microsoft Exchange Server and Active Directory Services Interface, a bit of initial footwork is usually required, as well as administrative access to the server. In some cases, these directory servers by default are not configured to allow LDAP access. To gain access to LDAP, follow these steps:

1.

Open the Exchange or ADSI Administrator by selecting Start > Programs > Microsoft Exchange > Microsoft Exchange Administrator.

2.

In the container view (left pane), scroll down to DS Site Configuration and double-click it. This opens the DS Site Configuration Properties window.

3.

In the General tab, specify the Anonymous account. You can either select an existing account or create a new one.

4.

Click the Attributes tab and specify which attributes can be displayed based on the request type (Authenticated or Anonymous site users). For anonymous requests, check any of the values you want access to.

5.

Exit the configuration window and go to the Protocols section under Configuration. Double-click the LDAP listing. This opens the LDAP Site Defaults Properties window.

6.

On the General tab, select Enable This Protocol.

7.

On the Anonymous tab, select Allow Anonymous Access.

8.

Apply changes and try your query.

Depending on the level of access you need for your application, you may need to contact your system administrator for additional help.

Active Directories

Active Directory is an essential component of each version of Windows network architecture since Windows 2000. It behaves as a directory service to allow organizations to centrally manage information on users (including security information), as well as other network resources. Windows Domain Controllers each have an Active Directory service available, which provides access to the directory database. Using a standard CFLDAP tag, developers can integrate with this Active Directory to enable users to log into ColdFusion applications using their Windows network username and password. Listing 22.2 shows a simple example to authenticate users against an Active Directory.

Listing 22.2. Authenticating a User with <cfldap>
 <cflogin>     <cfif NOT isDefined("Form.username")>         <cfinclude template="login/login_form.cfm">         <cfabort>     <cfelse>         <cftry>            <cfldap action="QUERY"               name="auth"               attributes="cn"               start="cn=users,dc=tapper,dc=net"               server="localhost"               port="389"               username="#form.username#"               password="#form.password#">            <cfset isAuthenticated="yes">            <cfcatch type="ANY">               <cfset isAuthenticated="no">            </cfcatch>         </cftry>         <cfif variables.isAuthenticated>             <cfloginuser                 name="#Form.username#"                 password="#Form.password#"                 roles="Authenticated User">         <cfelse>             <cfinclude template="login/login_form.cfm">             <h3>Your information is not valid.             Please try again.</h3>             <cfabort>         </cfif>     </cfif> </cflogin> 

In Listing 22.2, an LDAP query is done against a Microsoft Active Directory (AD) and is wrapped with a <cflogin> tag. By specifying the username and password as provided by the end user's form input, this query will run successfully only if those fields match a valid user's username and password from the AD. If either the username or password is incorrect, the AD will throw an error message. By wrapping the call with a <cftry> tag, we are able to catch the error message. The end result is that we have set a variable called isAuthenticated to either true if the query is able to run, or false if not. After the end of the <cftry> block, we check the value of isAuthenticated. If it is true, the user is logged in; otherwise, the user is redirected to the login form.

Active Directory Schema

In order to code queries to the Active Directory effectively, you'll need to know what the schema looks like. Microsoft provides access to this schema through the MMC Active Directory Schema snap-in. This snap-in is not installed with Windows 2000 by default, however. Instructions for installing it are as follows:

1.

Log on as Administrator.

2.

Insert the Windows 2000 Server CD into your CD drive and click Browse This CD.

3.

Double-click the I386 folder, double-click Adminpak, and then follow the instructions that appear in the Windows 2000 Administration Tools Setup wizard.

4.

Click Start > Run, type mmc /a, and then click OK.

5.

On the Console menu, click Add/Remove Snap-in, and then click Add.

6.

Under Snap-in, double-click Active Directory Schema, and then click Close.

7.

Click OK.

Once the snap-in is installed, you can view all of the attributes that are available for you to query. For example, if you expand objectclasses and select the user object class, you will see all the available attributes of user in the right pane of the MMC. These are the attributes that you can use in your LDAP queries.

Querying Directories

One of the first things you need to know about any action within <cfldap> that requires authentication is how to use the USERNAME and PASSWORD attributes. The first common mistake is to enter the username by itself, as odd as that may sound. Often the full DN is required for the entry that represents the user, and the username:

 USERNAME="cn=dain_anderson,cn=Recipients,ou=OWS,o=Orange Whip Studios" 

Most of the time, however, you can just use the cn as the username, as in:

 USERNAME="cn=dain_anderson" 

So in this example, the username is actually dain_anderson, but the USERNAME attribute requires the cn= (common name) prefix.

The PASSWORD attribute, on the other hand, does not require any special considerations, so you simply enter it as it's written:

 PASSWORD="danderson_123" 

NOTE

Depending on the vendor software you're using, the USERNAME attribute might require the full DN. Netscape Directory Server is one example of software that requires it. Check your LDAP documentation to see which method is used for your particular software package.


To take it a step further, you can run a query to gather the user's name and email address as follows:

 <CFLDAP  ACTION="QUERY"  NAME="GetEmail"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="cn,mail"  START=""  FILTER="(uid=dain_anderson)"> 

In this example, you specify the SUBTREE scope that will recursively check all entries that contain a cn and mail attribute and that have a uid of dain_anderson. The last portion represents a filter; filters are discussed in more detail later in this section.

To output the data, you can use the value held in the NAME attribute as a query object reference. In other words, this is the value you put in the QUERY attribute of your <cfoutput> tag, as shown here:

 <TABLE WIDTH="100%" BORDER="1" CELLSPACING="0">  <TR>  <TH>User (cn)</TH>  <TH>Email</TH>  </TR> <CFOUTPUT QUERY="GetEmail">  <TR>  <TD>#cn#</TD>  <TD>#mail#</TD>  </TR> </CFOUTPUT> </TABLE> 

If your goal is to list all email addresses for employees, you could easily modify the FILTER attribute to accommodate this:

 filter="(uid=*)" 

Here, the asterisk (*) acts as a wildcard character that tells <cfldap> to return all cn and mail enTRies with a uid.

In addition to the wildcard character, you can specify a wide range of filter sequences. Table 22.3 shows the allowed characters for filter strings with their descriptions, along with examples. The default filter, if none is provided, is objectClass=*.

Table 22.3. <cfldap> Search Filters and Descriptions Start Here

FILTER

EXAMPLE

DESCRIPTION

()

(filter)

For noncomparative filters, parentheses are optional. For comparative filters, such as &, |, and !, parentheses are required.

*

uid=*

Any value. This example returns entries that contain any uid value.

=

c=US

An exact value match. This example returns values where the country is equal to US (United States).

~=

ou~=OWS

An approximate match. This example returns entries with organizational units (ou) that approximate OWS (Orange Whip Studios).

>=

sn>=anderson

Greater than or equal to. Alphabetically, this returns all values that would be ordered at or after the surname (sn) value of anderson.

<=

givenName<=dain

Less than or equal to. Alphabetically, this returns all values that would be ordered at or before the first name (givenName) value of dain.

&

(&(sn=An*)(cn=Da*))

Comparative AND. This example returns all entries that have a surname (sn) that starts with An and a common name (cn) that starts with Da.

|

(|(sn=An*)(cn=Da*))

Comparative OR. This example returns all entries that have a surname (sn) that starts with An or a common name (cn) that starts with Da.

!

(!(cn=Dain Anderson))

Comparative NOT. This example returns all entries other than those whose common name (cn) is equal to Dain Anderson.


Search filters can also contain multiple comparisons or any mixture of the filters seen in Table 22.3. To get all users in the OWS organizational unit (ou) with the last name Anderson or Forta, you can modify the filter as follows:

 FILTER="(&(ou=OWS)(|(cn=Anderson)(cn=Forta)))" 

To order the returned entries alphabetically, you can use the SORT attribute, as well:

 FILTER="(&(ou=OWS)(|(cn=Anderson)(cn=Forta)))" SORT="cn" 

To obtain greater sort control, you could also specify the sorting as case-insensitive (the default is case-sensitive) and in descending order:

 FILTER="(&(ou=OWS)(|(cn=Anderson)(cn=Forta)))" SORT="cn" SORTCONTROL="nocase DESC" 

If you know that the query will return hundreds of records, two additional attributes may be needed. The TIMEOUT attribute specifies the time, in seconds, to allow before the operation times out. Also, the MAXROWS attribute allows you to specify the maximum number of matching records to return:

 FILTER="(&(ou=OWS)(|(cn=Anderson)(cn=Forta)))" SORT="cn" SORTCONTROL="nocase DESC" TIMEOUT="10" MAXROWS="100" 

And finally, if you're using <cfldap> to page through hundreds of records, you may also want to consider using the STARTROW attribute, which allows you to return records from a specific row:

 FILTER="(&(ou=OWS)(|(cn=Anderson)(cn=Forta)))" SORT="cn" SORTCONTROL="nocase DESC" TIMEOUT="10" MAXROWS="100" STARTROW="#URL.StartRow#" 

Here, the #URL.StartRow# variable would represent a value sent from a previous page's URL.

NOTE

Sorting is performed on the LDAP server and is only supported on servers compatible with LDAPv3.


Adding Entries

To add an entry to LDAP, you need to pay close attention to two special values: the DN for the entry, and the entry's objectClass. The object class is essentially an object map to the entry using the object class entries. The DN, on the other hand, is a similar type of map except that it uses the DN sequence. To gather both of these values, you can easily list all name and value pairs for a DN, one being the objectClass.

If, for example, you want to add a user to a specific group, you can use another user's attributes from that group as a guideline for adding the new user. See Listing 22.3 to see how this is accomplished.

Listing 22.3. GetNameValues.cfmList Name/Value Pairs
 <!--- Query for all (*) uid's ---> <CFLDAP ACTION="QUERY"  NAME="GetNamesAndValues"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="*"  START=""  FILTER="(uid=*)"> <!--- Display all name/value pairs for each uid ---> <CFOUTPUT QUERY="GetNamesAndValues"> <TABLE WIDTH="100%" BORDER="1" CELLSPACING="0">  <!--- Show the column headers only for the first record --->  <CFIF CurrentRow EQ 1>  <TR>  <TH>Name</TH>  <TH>Value</TH>  </TR>  </CFIF>  <TR>  <TD>#name#</TD>  <TD>#value#</TD>  </TR> </TABLE> </CFOUTPUT> 

NOTE

Some software packages, such as Netscape Directory Server, return zero results if the START attribute is left blank. To resolve this, you can enter your company's organization as a minimum starting value.


By specifying an asterisk (*) for the ATTRIBUTES value, you're telling <cfldap> to return all attributes for all entries returned from the FILTER scope value. In this example, you used the (uid=*) filter to signify that you want all entries (*) that have a uid returned. The objectClass is now:

 organizationalPerson, person, Top 

and one of the DNs is:

 cn=dain_anderson, cn=Recipients, ou=OWS, o=Orange Whip Studios 

Having this list of available attributes allows you to build your ADD action construct. In Listing 22.4, you'll add "Ben Forta," along with his corresponding personal information values, to the Orange Whip Studios (OWS) organizational unit (ou) within the company.

Listing 22.4. AddEntry.cfmAdding and Testing an Entry
 <!--- Use the 'ADD' action to create a new entry ---> <CFLDAP ACTION="ADD"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  ATTRIBUTES="objectclass=organizationalPerson, person, Top;  cn=Ben Forta;  sn=Forta;  mail=Ben_Forta@orange-whip-studios.com;  ou=OWS"  DN="cn=ben_forta, cn=Recipients, ou=OWS, o=Orange Whip Studios"> <!--- Query to ensure the entry was added ---> <CFLDAP ACTION="QUERY"  NAME="GetUser"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="dn,cn"  START=""  FILTER="(cn=ben_forta)"> <!--- Display the query results ---> <TABLE WIDTH="100%" BORDER="1" CELLSPACING="0">  <TR>  <TH>User (cn)</TH>  <TH>DN</TH>  </tr>  <CFOUTPUT QUERY="GetUser">  <TR>  <TD>#cn#</TD>  <TD>#dn#</TD>  </TR>  </CFOUTPUT> </TABLE> 

Because you used a filter of cn=ben_forta, all records with that cn are returned in the query object (which in this case is only a single record). The next section on modifying entries shows how you could easily add or change attributes for Ben's user entry.

NOTE

If you receive an Access Denied error message when adding entries, talk to your system administrator to ensure that you have sufficient access to perform the operation.


Modifying Entries

The trickiest part of learning <cfldap> is understanding how to modify entries. This section shows you several examples using each of the methods to modify entries, and because of this, it is also the most lengthy section in this chapter.

Through the <cfldap> interface, you can perform several modification tasks:

  • Modify existing attribute values

  • Modify entries by adding entries (such as groups and users)

  • Modify entries by using the ModifyType attribute for better modification control

  • Modify an entry's Distinguished Name through the MODIFYDN action

Most of these examples require a bit of trial and error, depending on how your LDAP server is configured. Exact behavior and syntax can vary based on the LDAP server being used and its configuration, so you may have to do some due diligence to learn more about the server you are using. With that information, you'll be on your way to creating robust applications using <cfldap>.

CAUTION

Be sure to test all modifications on a test server before using them in a production environment. LDAP is a trial-and-error process that requires substantial testing. A simple mistake can have enormous impact on the existing data's integrity.


Modifying Existing Attribute Values

As with adding entries, before you can modify an entry you must first know the DN for the entry. This is used to reference the entity you want to modify or delete. To gather this information, you'll perform a simple query using the uid attribute as shown in Listing 22.4.

Listing 22.5 gathers the DN as well as the user's common name (CN) and telephone number (telephoneNumber). The telephoneNumber field appears blank at this point. You'll modify that blank entry in a later example; first you need the DN.

Listing 22.5. GetdN.cfmRunning a Simple Query
 <CFLDAP ACTION="QUERY"  NAME="GetDN"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="dn,cn,telephonenumber"  START=""  FILTER="(uid=dain_anderson)"> <TABLE WIDTH="100%" BORDER="1" CELLSPACING="0">  <TR>  <TH>User (cn)</TH>  <TH>DN</TH>  <TH>Telephone</TH>  </TR>  <CFOUTPUT QUERY="GetDN">  <TR>  <TD>#cn#</TD>  <TD>#dn#</TD>  <TD>#telephonenumber#</TD>  </TR>  </CFOUTPUT> </TABLE> 

The results of your query will return the cn, dn, and the telephoneNumber values. To restrict the number of results to a single user, you add a filter. And in this example, the uid=dain_anderson filter is used to return the values in the ATTRIBUTES parameter for the specific user.

After you have the DN for the entry you're modifying, you can run a second <cfldap> tag with the ACTION attribute set to MODIFY. The first query returned a DN of:

 cn=dain_anderson, cn=Recipients, ou=OWS, o=Orange Whip Studios 

which is what you'll use to modify the listing. For this next example, you'll change the telephone number value.

The first call to <cfldap>, as shown previously in Listing 22.4, gathers the DN. This value is required for any modifications you want to make. The second call uses the first call's DN as the value you supply to the DN attribute. Finally, one more <cfldap> call is used to requery the server, returning the newly modified results that contain the telephoneNumber value. See Listing 22.6 to get a better idea of how this works.

Listing 22.6. ModifyTelephone.cfmModifying an Entry
 <!--- Update the 'telephoneNumber' value ---> <!--- The DN value is used from a previous CFLDAP call ---> <CFLDAP ACTION="MODIFY"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  ATTRIBUTES="telephonenumber=(919) 555 - 5555"  DN="#GetDN.DN#"> <!--- Run a query to gather the new results ---> <CFLDAP ACTION="QUERY"  NAME="GetUserData"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="dn,cn,telephonenumber"  START=""  FILTER="(uid=dain_anderson)"> <!--- Display the new results ---> <TABLE WIDTH="100%" BORDER="1" CELLSPACING="0">  <TR>  <TH>User (cn)</TH>  <TH>DN</TH>  <TH>Telephone</TH>  </TR>  <CFOUTPUT QUERY="GetUserData">  <TR>  <TD>#cn#</TD>  <TD>#dn#</TD>  <TD>#telephonenumber#</TD>  </TR>  </CFOUTPUT> </TABLE> 

The telephone value is no longer blank. Running multiple calls to <cfldap> in one template is commonplace, just as you might run multiple <cfquery>s.

Modifying values is not restricted to a single value at a time; rather, you can make multiple modifications simultaneously with a single <cfldap> call, using a delimiter to separate each entry and its new value. Listing 22.7 shows how you would change the user's state as well as his street address.

Listing 22.7. ModifyStreetState.cfmUpdating Multiple Attributes
 <!--- Update the 'street' and 'state' values ---> <CFLDAP ACTION="MODIFY"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  ATTRIBUTES="st=NC; street=123 Orange Whip Lane"  MODIFYTYPE="ADD"  DN="cn=dain_anderson,cn=Recipients,ou=OWS,o=Orange Whip Studios"> <!--- Run a query to gather the new results ---> <CFLDAP ACTION="QUERY"  NAME="GetDN"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="cn,street,st"  START=""  FILTER="(uid=dain_anderson)"> <!--- Display the new results ---> <TABLE WIDTH="100%" BORDER="1" CELLSPACING="0">  <TR>  <TH>User (cn)</TH>  <TH>Street</TH>  <TH>State</TH>  </TR>  <CFOUTPUT QUERY="GetDN">  <TR>  <TD>#cn#</TD>  <TD>#street#</TD>  <TD>#st#</TD>  </TR>  </CFOUTPUT> </TABLE> 

Modification by Adding Entries

One of the more difficult modification tasks of <cfldap> is modifying entries by adding additional entries. The next few examples show how to modify a group by adding a member to it.

To begin this example, you'll start by querying an existing group to which you want to add a member. The first part is used to ensure that the group does, in fact, exist. If not, you would throw an error:

 <!--- This queries the group ---> <CFLDAP ACTION="query"  NAME="GroupExists"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="uniquemember"  START="cn=Marketing,cn=Recipients,ou=OWS,o=Orange Whip Studios"> <!--- If the group doesn't exist, throw an error message and abort ---> <CFIF NOT GroupExists.RecordCount>  <CFTHROW MESSAGE="Group does not exist.">  <CFABORT> </CFIF> 

At this point, you're checking to see whether the group exists where you want to place the new member(s). The value that defines whether it exists is the #GroupExists.RecordCount# variable. The GroupExists prefix is the name you assigned in the NAME attribute, which represents the name of the returned query object. If the group exists, you know that you can safely place a user into that group. Otherwise, you throw an error and abort processing.

The next step is to gather all users and their corresponding uid values for the existing group to which you want to add users. You can use the ColdFusion ValueList() function to create a list from all the uid values:

 <!--- Get all uid's for the 'Marketing' group ---> <CFLDAP ACTION="query"  NAME="GetUserList"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="uid"  START="cn=Marketing,cn=Recipients,ou=OWS,o=Orange Whip Studios"> <!--- Create a list from the query's uid values ---> <CFSET UserList=ValueList(GetUserList.uid)> 

For simplicity, the next section assumes that only two users are currently in the Marketing group (cn=Marketing), which are stored in the variable called #UserList#. Each element in the list is the user's uid value. To be sure, the #UserList# variable will be replaced with the actual list (dain_anderson,ben_forta):

 <!--- Primer for the members list ---> <CFPARAM NAME="Members" DEFAULT=""> <!--- Loop through each uid using UserList ---> <CFLOOP LIST="#UserList#" INDEX="User">  <!--- Get each user's DN from their uid --->  <CFLDAP ACTION="query"  NAME="GetUser"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="dn"  START=""  FILTER="(uid=#User#)">  <!--- Create a semicolon-separated list of user DN's --->  <!--- Each DN needs to have its commas escaped with another comma --->  <CFSET Members= Members & "," & Replace(GetUser.dn, ",", ",,", "ALL")> </CFLOOP> <!--- Remove the leading comma from the Members list ---> <CFSET Members=RemoveChars(Members, 1, 1)> 

The last section of code creates a list of lists. The outer list is a comma-separated list of all DNs for the group (Marketing). Within each DN (between each semicolon), another list contains an escaped comma-delimited list of attribute values for that DN (single user). Commas, in this context, must be escaped with a second comma so that <cfldap> does not mistake each DN's attributes as a separate entry. Had you not escaped these commas, none of the memberswhen you add additional memberswould be unique, because each attribute would become a new member. In other words, it would create two members called Marketing, two members called Recipients, and so on.

The results of the #Members# variable contain all current Marketing users:

 cn=dain_anderson,,cn=Recipients,,ou=OWS,,o=Orange Whip Studios; cn=ben_forta,,cn=Recipients,,ou=OWS,,o=Orange Whip Studios 

As you can see, each DN has its commas escaped, and each DN is separated by a single comma. It's always best to automate this process because this listing can become large.

In this example, you're going to add another user, John Doe, to the Marketing group. John Doe is currently not a member of any grouphe's an entirely new user. Had John Doe already existed somewhere in the directory, adding him as a member of Marketing would not physically change his location in the directory. To physically move him, you would have to delete him from his current location and add him to another. By placing him in Marketing, you are merely adding him as a member of Marketing, but he could exist elsewhere in the directory structure. The hard-coded value for this user before escaping will be:

 cn=john_doe,cn=Recipients,ou=OWS,o=Orange Whip Studios 

After escaping the commas, the entry will look like this:

 cn=john_doe,,cn=Recipients,,ou=OWS,,o=Orange Whip Studios 

To update the members list for Marketing, you have to add John Doe to the current members list; be sure to add a comma between each entry:

 <CFSET Members=Members & "," & "cn=john_doe,,cn=Recipients,,ou=OWS,,o=Orange Whip Studios"> 

Finally, to update the current members of the Marketing group, you can replace the uniqueMember (all current members) list with the new #Members# list, which contains the newly added John Doe entry as well as all the preexisting members:

 <CFLDAP ACTION="MODIFY"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  ATTRIBUTES="objectclass=groupOfUniqueNames;uniquemember=#Members#"  DN="cn=Marketing,cn=Recipients,ou=OWS,o=Orange Whip Studios"> 

While this is a tedious process, there is a far easier approach to making these modifications, with the use of the ModifyType attribute. The final code for these sections can be found encapsulated in the LDAP.cfc shown in listing 22.9

Modifying Entries with ModifyType

To help you appreciate the benefits of using the ModifyType attribute, the previous section demonstrated how cumbersome it can be to modify entries manually. Luckily, there is an easier way, by using the ModifyType attribute of the <cfldap> tag.

To recap, reread the section "The MODIFYTYPE Attribute" earlier in this chapter. The add modify type will look like the following:

 <CFLDAP ACTION="MODIFY"  MODIFYTYPE="ADD"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  ATTRIBUTES="cn=john_doe,cn=Recipients,ou=OWS,o=Orange Whip Studios"  DN="cn=Marketing,cn=Recipients,ou=OWS,o=Orange Whip Studios"> 

Had you added two users, you would separate each DN with a comma.

To replace entries, use the replace modify type.

CAUTION

Be careful that you do not overwrite existing entries with a single entry. The entries you supply to the ATTRIBUTES parameter will replace all existing entries for the DN specified.


For this example, you'll replace the current marketing users with a list of the old users plus a new user, John Doe. For this example, all the new users are placed in a variable called #Members#. Following is what the new users list will look like:

 cn=dain_anderson,cn=Recipients,ou=OWS,o=Orange Whip Studios, cn=ben_forta,cn=Recipients,ou=OWS,o=Orange Whip Studios, cn=john_doe,cn=Recipients,ou=OWS,o=Orange Whip Studios 

To replace the old members with the new, use the replace modify type:

 <CFLDAP ACTION="MODIFY"  MODIFYTYPE="REPLACE"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  ATTRIBUTES="#Members#"  DN="cn=Marketing,cn=Recipients,ou=OWS,o=Orange Whip Studios"> 

To delete an entry, use the delete modify type. This next example would delete the John Doe user from the Marketing group:

 <CFLDAP ACTION="MODIFY"  MODIFYTYPE="DELETE"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  ATTRIBUTES="cn=john_doe,cn=Recipients,ou=OWS,o=Orange Whip Studios"  DN="cn=Marketing,cn=Recipients,ou=OWS,o=Orange Whip Studios"> 

Modifying a Distinguished Name

Modifying a Distinguished Name (DN) requires <cfldap>'s MODIFYDN action. You cannot modify a Distinguished Name using the MODIFY action.

There are two values of interest when modifying a DN: the original DN and the replacement DN. The original DN is placed in the DN attribute, whereas the new replacement DN is placed in the ATTRIBUTES parameter as follows:

 <CFLDAP ACTION="MODIFYDN"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  ATTRIBUTES="cn=jane_doe,cn=Recipients,ou=OWS,o=Orange Whip Studios"  DN="cn=john_doe,cn=Recipients,ou=OWS,o=Orange Whip Studios"> 

Deleting Entries

Deleting an entry is possibly the easiest action to perform using <cfldap>. Because of this, it is worth pointing out that after an entry is deleted, it's gone for good, and there isn't an "undo" mechanism.

The following code snippet shows the process of removing an entry from LDAP. The only requirements for doing so are having sufficient access as well as the DN of the entry you want to delete.

 <CFLDAP ACTION="DELETE"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  DN="cn=dain_anderson,cn=Recipients,ou=OWS,o=Orange Whip Studios"> 

After the code is run, the entry is gone. As a safeguard, you may want to create a database to hold "deleted" entries in the event that you need to restore an accidentally deleted entry. Using this concept, you would query the entry to gather all its Name/Value pairs, run an insert query, and then, if all goes well, run the LDAP deletion.

To conclude this chapter, Listing 22.8 shows how to build a simple mailing list that enables you to send a message to every member in your LDAP directory. This example could be modified to filter specific groups or organizational units, or to enable you to specify filter options. The choices are unlimited.

Listing 22.8. LDAPMailList.cfmUsing LDAP to Create a Mailing List
 <!--- Process code if the form was submitted ---> <CFIF IsDefined("FORM.Submit")>  <!--- Simple form validation for each field --->  <CFIF NOT Len(FORM.MessageTitle)>  <CFTHROW MESSAGE="Please enter a message title.">  </CFIF>  <CFIF NOT Len(FORM.Message)>  <CFTHROW MESSAGE="Please enter a message to send.">  </CFIF>  <!--- Run the LDAP query --->  <CFLDAP ACTION="QUERY"  NAME="LDAPMailList"  SERVER="localhost"  USERNAME="cn=dain_anderson"  PASSWORD="danderson_123"  SCOPE="SUBTREE"  ATTRIBUTES="cn,mail"  START="">  <!--- If records are returned, run CFMAIL --->  <CFIF LDAPMailList.RecordCount>  <CFMAIL FROM="list-serve@orange-whip-studios.com"  TO="#mail#"  SUBJECT="#Form.MessageTitle#"  SERVER="mail.orange-whip-studios.com"  QUERY="LDAPMailList"> Hello, #cn# #FORM.Message#  </CFMAIL>  <!--- Feedback, sent --->  <B>Your message was successfully sent.</B><P>  <CFELSE>  <!--- Feedback, failed --->  <B>No records exist in the directory.</B>  </CFIF> </CFIF> <!--- Form used to enter the mailing list contents ---> <FORM ACTION="LDAPMailList.cfm" METHOD="post">  Enter a title for the mailing:<BR>  <INPUT NAME="MessageTitle" MAXLENGTH="200" SIZE="40"><P>  Enter the message text:<BR>  <TEXTAREA NAME="Message" COLS="40" ROWS="7"></TEXTAREA><P>  <INPUT TYPE="Submit" NAME"Submit" VALUE="Send Message"> </FORM> 

The first time you access the page, you will see a form that enables you to enter a title and content for the mailing. Clicking the Submit button posts the form values to the same page where processing the mailing begins.

The beginning of the ColdFusion code uses a simplified form of validation that checks whether a message and title are empty values; if they are, the <CFTHROW> tag is used to display an error message and the template aborts further processing.

If the validation passes, you make a call to the LDAP server requesting the cn and mail attributes for everyone. Because no filters are used, every entry containing a cn or mail attribute is returned as the LDAPMailList query. If records are returned, you use <CFMAIL>'s QUERY attribute to cycle once for each record in LDAPMailList. Upon template execution, a message is displayed indicating to you that the mailing was a success.



Advanced Macromedia ColdFusion MX 7 Application Development
Advanced Macromedia ColdFusion MX 7 Application Development
ISBN: 0321292693
EAN: 2147483647
Year: 2006
Pages: 240
Authors: Ben Forta, et al

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net