Examples and Considerations

Generally, there are two types of proxy rules:

  • Rules that define target servers

  • Rules that can change requests/results

This chapter provides some examples to illustrate the use of both types of rule with a special focus on operation-routing rules and the rewriting rules.

As described in the chapter “Proxy Rules”, all rules have a condition key. Rules that define target servers specify target servers while rules that define request/result rewriting rules have action keys.

Operation-Routing Rules: Examples

The following examples illustrate the impact of different settings of the keepconn and failover keys in operation-routing rules. The examples include failover and non-failover scenarios.

Example 1: All Target LDAP Servers Up and Running

In this example, the following rules exist:

  • User-routing rule: Forward User_A to LDAP_Server_1.

  • Operation-routing rule: Forward all add operations to LDAP_Server_2.

No operation routing rules are defined for search operations.

The following tables illustrate where the operations are routed to based on the keepconn key.

keepconn=1

Step # Operation executed Target server selected for operation

Step 1

User_A binds.

LDAP_Server_1.

Step 2

User_A performs an add operation.

LDAP_Server_2.

Step 3

User_A performs a search operation

LDAP_Server_2 due to keepconn=1 from Step 2.

keepconn=0

Step # Operation executed Target server selected for operation

Step 1

User_A binds.

LDAP_Server_1.

Step 2

User_A performs an add operation.

LDAP_Server_2.

Step 3

User_A performs a search operation

LDAP_Server_1 due to keepconn=0 from Step 2.

These tables show that keepconn=1 overrules the target server from a previous user-routing rule for all subsequent operations that do not have their own rule. A keepconn=1 can also be seen as a “switch-connection” operation. (Of course the switch is only applied if the operation was successful).

Example 2: Target Server Failure, no Failover Servers Defined

In this example, the following rules exist:

  • User-routing rule: Forward User_A to LDAP_Server_1.

  • Operation-routing rule: Forward add operations to LDAP_Server_2.

No operation-routing rules are defined for search operations.

The following tables illustrate where the operations are routed to based on the keepconn settings in the operation-routing rule:

Note that a server failure means that the server cannot be reached via the network for the rest of the test sequence; that is, it is not available again until end of the sequence.

Sequence 1: Keepconn=1 or keepconn=0

Step # Operation executed Target server selected for operation

Step 1

User_A binds.

LDAP_Server_1.

!

LDAP_Server_2 fails.

Step 2

User_A performs an add operation.

Operation fails, due to no failover servers defined.

Step 3

User_A performs a search operation

LDAP_Server_1 due to no connection available from Step 2.

Sequence 2: keepconn=1

Step # Operation executed Target server selected for operation

Step 1

User_A binds.

LDAP_Server_1.

Step 2

User_A performs an add operation.

LDAP_Server_2.

!

LDAP_Server_2 fails.

Step 3

User_A performs a search operation

Operation fails due to LDAP_Server_2 failure after Step 2 and keepconn=1 in Step 2.

Sequence 2: keepconn=0

Step # Operation executed Target server selected for operation

Step 1

User_A binds.

LDAP_Server_1.

Step 2

User_A performs an add operation.

LDAP_Server_2.

!

LDAP_Server_2 fails.

Step 3

User_A performs a search operation

LDAP_Server_1 due to keepconn=0 for Step 2.

As the example shows, the reaction towards the client depends on when the target server drops out, although the client executes the same sequence. As the target servers are transparent to the client (the client is unaware of being physically connected to a DLP server and not to an LDAP server) this might look strange, because the client never “lost” the LDAP-connection but might still receive different results.

Example 3: Target Server Failure, Failover=1, Multiple Targets

In this example, the following rules exist:

  • User-routing rule: Forward User_A to LDAP_Server_1.

  • Operation-routing rule: Forward add operations to LDAP_Server_2 or LDAP_Server_3.

No operation-routing rules are defined for search operations.

The following tables illustrate where the operations are routed to based on various keepconn settings and failover=1 in the operation-routing rule:

Sequence 1: Keepconn=1

Step # Operation executed Target server selected for operation

Step 1

User_A binds.

LDAP_Server_1.

!

LDAP_Server_2 fails.

Step 2

User_A performs an add operation.

LDAP_Server_3 due to failover=1.

Step 3

User_A performs a search operation

LDAP_Server_3 due to keepconn=1 from Step 2.

Sequence 1: Keepconn=0

Step # Operation executed Target server selected for operation

Step 1

User_A binds.

LDAP_Server_1.

!

LDAP_Server_2 fails.

Step 2

User_A performs an add operation.

LDAP_Server_3 due to failover=1.

Step 3

User_A performs a search operation.

LDAP_Server_1 due to keepconn=0 from Step 2.

Sequence 2: Keepconn=1

Step # Operation executed Target server selected for operation

Step 1

User_A binds.

LDAP_Server_1.

Step 2

User_A performs an add operation.

LDAP_Server_2.

!

LDAP_Server_2 fails.

Step 3

User_A performs a search operation.

LDAP_Server_3 due to keepconn=1 from Step 2 and failover=1 for LDAP_Server_2 down.

Sequence 2: Keepconn=0

Step # Operation executed Target server selected for operation

Step 1

User_A binds.

LDAP_Server_1.

Step 2

User_A performs an add operation.

LDAP_Server_2.

!

LDAP_Server_2 fails.

Step 3

User_A performs a search operation

LDAP_Server_1 due to keepconn=0 from Step 2.

Rewriting Rules: Examples and Considerations

This section supplies some examples of rewriting rules and describes considerations to keep in mind when using rewriting rules.

Examples of Rewriting Conditions and Actions

Here are some condition/action pair examples.In these examples, C: refers to a condition and A: refers to an action.

Example 1: Enforce SSL/TLS

Enforce all users to connect via SSL/TLS only by denying any operation that comes from plain/unsecure socket:

C: (&(opr.req.type=* )(security=plain))

A: denyreq

Example 2: Deny Requests from Local Host

Do not allow any requests from the local host (this rule does not apply to extended operations)

C: (&(opr.req.type=*)(ip=127.0.0.1))

A: denyreq

Example 3: Reject binds from a User

Reject binds from a specific user:

C: (&(opr.req.type=bind)(bind.req.name=cn=hohner,ou=sales,o=my-company))

A: denyreq

Example 4: Reject Anonymous Users

Reject all operations from anonymous users:

C: (&(opr.req.type=*)(user=anonymous))

A: denyreq

Example 5: Replace a Base Object String in a Request

Replace the substring “o=pqr” with “o=my-company” in the base object of incoming search requests:

C: (opr.req.type=search)

A: search.req.baseObject.replace(o=pqr,o=my-company,NULL)

Example 6: Remove a Base Object String

Remove the string “ou=sales” from the incoming BaseObject

C: (opr.req.type=search)

A: search.req.baseObject.replace(ou=sales,NULL,NULL)

Example 7: Add/Remove Requested Attributes (Two Actions)

Add the requested attribute mycn and remove an existing requested attribute cn in a search request:

C: (opr.req.type=search)

A: search.req.attributes.add(mycn,NULL,NULL) ← first action

A: search.req.attributes.del(cn,NULL,NULL) ← second action

Example 8: Add/Remove Requested Attributes (One Action)

Add the requested attribute mycn and remove an existing requested attribute cn in a search request with one action:

C: (opr.req.type=search)

A: search.req.attributes.replace(cn,mycn,NULL)

Example 9: Change a Filter Attribute Name

Change the attribute name cn to mycn in all filter attribute-names:

C: (opr.req.type=search)

A: search.req.filter.replace(cn,mycn,NULL)

Example 10: Change a String in One Attribute Filter Value

Change the substring pqr to my-company in all filter values for the attribute organization:

C: (opr.req.type=search)

A: search.req.filter.replace(o,pqr,my-company)

Example 11: Change a String in All Attribute Filter Values

Change the substring pqr to my-company for all attributes in the filter:

C: (opr.req.type=search)

A: search.req.filter.replace(,pqr,my-company)*

Example 12: Deny Anonymous User Subtree Searches

Deny subtree searches for anonymous users:

C: (&(opr.req.type=search)(search.req.scope=wholeSubtree)(user=anonymous))

A: denyreq

Example 13: Deny Unlimited Searches

Deny unlimited (sizelimit=0) searches:

C: (&(opr.req.type=search)(search.req.sizelimit=0))

A: denyreq

Example 14: Set a Size Limit for Anonymous User Searches

Set a size-limit of 1000 for any search from anonymous users:

C: (&(opr.req.type=search)(user=anonymous))

A: search.req.sizeLimit.set(1000,NULL,NULL);

Example 15: Change a String in all Entry DNs of a Search Result

Change the string o=my-company to o=pqr in all resulting entry DNs of a search request:

C: (opr.req.type=search)

A: search.res.objectName.replace(o=my-company,o=pqr,NULL)

Example 16: Hide an Attribute from Returned Search Result Entries

Hide the attribute secret (with all its values) from any returned search result entry:

C: (opr.req.type=search)

A: search.res.attributes.del(secret,NULL,NULL)

Example 17: Remove an Attribute from a Request List

Remove the attribute secret from the request list:

C: (opr.req.type=search)

A: search.req.attributes.del(secret,NULL,NULL)

Example 18: Change an Attribute Value in Returned Search Results

Change the string MainStreet to Hauptstrasse in all values of the attribute street in any returned search result entry:

C: (opr.req.type=search)

A: search.res.attributes.replace(street,MainStreet,Hauptstrasse)

Example 19: Escape a Special Character

Replace a substring that contains a comma using the LDAP escape character \ (backslash). The original output is description=The,dogs bark loud. The desired output is description=The wolves bark loud.

the double escape is necessary because ‘\’ (backslash) is defined as a meta-character in JSON.

C: (opr.req.type=search)

A: search.res.attributes.replace(description,The\\,dogs,The wolves)

Example 20: Deny Renaming or Moving Entries

Deny renaming or moving entries in the DIT:

C: (opr.req.type=modDN)

A: denyreq

Example 21: Prevent Attribute Value Creation for New Entries

Prohibit creation of any values for the attribute strange for newly created entries:

C: (opr.req.type=add)

A: add.req.attributes.del(strange,NULL,NULL)

Example 22: Prevent an Attribute Modification

Never modify the attribute strange:

C: (opr.req.type=modify)

A: modify.req.changes_add.del(strange,NULL,NULL)

A: modify.req.changes_del.del(strange,NULL,NULL)

A: modify.req.changes_replace.del(strange,NULL,NULL)

Considerations for Rewriting Rules

When search results are changed/re-written, it is usually necessary to add additional rules in order to maintain a consistent approach to the database in subsequent calls.

To illustrate this concept, let’s look at the following simple example.Suppose there is a group of legacy clients that are accessing a DIT tree via LDAP calls.The DIT tree consists of a simple structure with a context prefix (CP) of o=companyX.The company decides to rename itself from companyX to companyZ and all the entries in the DIT need to reflect this change to the calling clients.

One way of achieving the result is to rename all entries in the DIT by changing the entry o=companyX to o=companyZ.This solution also implies that all clients must use o=companyZ as new target addresses; for example, for baseObjects in searches or in entry DNs for adds or modifys.But what if some of the legacy clients cannot be changed so easily?

A better approach is to use the DirX Directory LDAP proxy server with a simple rewriting rule like this:

C: (opr.req.type=search)

A: search.req.baseObject.replace(companyX,companyZ,NULL)

This rule changes any occurrence of companyX on-the-fly into companyZ in the baseObject of any search, making the search successful again for clients that are only aware of o=company.

Well, but what is returned now? The returned entries from the LDAP server will contain the new name o=companyZ again. Clients may now struggle to receive entries containing o=companyZ in their DNs although they have given a baseObject of o=companyX and therefore expect such resulting DNs.

Again, the DLP server can help by adding another simple result-rewriting action to another rule like:

C: (opr.req.type=search)

A: search.res.objectName.replace(companyZ,companyX,NULL)

Note that it must be another rule because the rule will now operate on results and so the ruleType must be ResRewrite. The baseObject change was performed by a ReqRewrite rule type.

By adding this result-rewriting rule, a client now receives the resulting entries as usual with the well-known old name companyX.

What if the client now decides to create a new group-of-names entry containing all received DNs as members from the previous search result? The client will surely issue an add request. As the client is only aware of o=companyX, the target DN of the add operation may again contain companyX and the member attributes will also contain the companyX name.

Clearly this add operation is bound to fail, as the LDAP servers no longer recognize companyX. Thus, it will be necessary to define further rules like

C: (opr.req.type=add)

A: add.req.entry.replace(companyX,companyZ,NULL)

A: add.req.attributes.replace(member,companyX,companyZ)

where the first action corrects the DN and the second action changes the members to the new name.

If you plan to deploy result rewriting, you need to have a full understanding of client behavior. You may need to add many more additional rules to manage the changes in subsequent add, modify, delete, moddn or compare operations properly.