From e9558df199c35c488de80b8a2acd7d4149d46db1 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 13 Oct 2011 12:42:32 +0000
Subject: [PATCH] Preparation work for OPENDJ-308: Implement access log filtering and configurable message format

---
 opends/resource/schema/02-config.ldif                                                         |   72 +++
 opends/src/admin/defn/org/opends/server/admin/std/AccessLogFilteringCriteriaConfiguration.xml |  451 ++++++++++++++++++++++
 opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java                       |  528 +++++++++++++++++++++++++
 opends/src/server/org/opends/server/types/AddressMask.java                                    |   50 +-
 opends/src/server/org/opends/server/core/networkgroups/IPConnectionCriteria.java              |    9 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAddressMask.java        |    3 
 opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java                 |    8 
 opends/src/admin/messages/AccessLogFilteringCriteriaCfgDefn.properties                        |   54 ++
 8 files changed, 1,119 insertions(+), 56 deletions(-)

diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 9887e52..0414697 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -2676,6 +2676,74 @@
   NAME 'ds-cfg-log-record-type'
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.32
+  NAME 'ds-cfg-client-address-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.33
+  NAME 'ds-cfg-client-address-not-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.34
+  NAME 'ds-cfg-client-protocol-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.35
+  NAME 'ds-cfg-client-port-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.36
+  NAME 'ds-cfg-user-dn-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.37
+  NAME 'ds-cfg-user-dn-not-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.38
+  NAME 'ds-cfg-user-is-member-of'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.39
+  NAME 'ds-cfg-user-is-not-member-of'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.40
+  NAME 'ds-cfg-request-target-dn-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.41
+  NAME 'ds-cfg-request-target-dn-not-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.42
+  NAME 'ds-cfg-response-result-code-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.43
+  NAME 'ds-cfg-response-result-code-not-equal-to'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.44
+  NAME 'ds-cfg-response-etime-greater-than'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.45
+  NAME 'ds-cfg-response-etime-less-than'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.46
+  NAME 'ds-cfg-search-response-nentries-greater-than'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.47
+  NAME 'ds-cfg-search-response-nentries-less-than'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+  X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.48
+  NAME 'ds-cfg-search-response-is-indexed'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
+  X-ORIGIN 'OpenDJ Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
   NAME 'ds-cfg-access-control-handler'
   SUP top
@@ -4472,5 +4540,7 @@
   SUP top
   STRUCTURAL
   MUST ( cn )
-  MAY ( ds-cfg-log-record-type )
+  MAY ( ds-cfg-log-record-type $
+        ds-cfg-base-dn $
+        ds-cfg-scope )
   X-ORIGIN 'OpenDJ Directory Server' )
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/AccessLogFilteringCriteriaConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/AccessLogFilteringCriteriaConfiguration.xml
index ede1982..12a4239 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/AccessLogFilteringCriteriaConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/AccessLogFilteringCriteriaConfiguration.xml
@@ -43,10 +43,13 @@
   </adm:profile>
   <adm:property name="log-record-type" multi-valued="true">
     <adm:synopsis>
+      Filters log records based on their type.
     </adm:synopsis>
     <adm:default-behavior>
       <adm:alias>
-        <adm:synopsis>All records</adm:synopsis>
+        <adm:synopsis>
+          The log record type will be ignored during filtering.
+        </adm:synopsis>
       </adm:alias>
     </adm:default-behavior>
     <adm:syntax>
@@ -95,4 +98,450 @@
       </ldap:attribute>
     </adm:profile>
   </adm:property>
+  <adm:property name="client-address-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters log records associated with connections which match at least one
+      of the specified client host names or address masks. 
+    </adm:synopsis>
+    <adm:description>
+      Valid values include a host name, a fully qualified domain name, a 
+      domain name, an IP address, or a subnetwork with subnetwork mask.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on client address equality.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:ip-address-mask />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-client-address-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="client-address-not-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters log records associated with connections which do not match any
+      of the specified client host names or address masks. 
+    </adm:synopsis>
+    <adm:description>
+      Valid values include a host name, a fully qualified domain name, a 
+      domain name, an IP address, or a subnetwork with subnetwork mask.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on client address inequality.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:ip-address-mask />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-client-address-not-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="client-protocol-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters log records associated with connections which match any
+      of the specified protocols. 
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on the protocol.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:enumeration>
+        <adm:value name="ldap">
+          <adm:synopsis>LDAP clients</adm:synopsis>
+        </adm:value>
+        <adm:value name="ldaps">
+          <adm:synopsis>LDAPS clients</adm:synopsis>
+        </adm:value>
+        <adm:value name="jmx">
+          <adm:synopsis>JMX clients</adm:synopsis>
+        </adm:value>
+      </adm:enumeration>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-client-protocol-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="client-port-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters log records associated with connections to any of the specified
+      listener port numbers. 
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on the port.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer lower-limit="1" upper-limit="65535" />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-client-port-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="user-dn-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters log records associated with users matching at least one of the
+      specified DN patterns.
+    </adm:synopsis>
+    <adm:description>
+      Valid DN filters are strings composed of zero or more wildcards. A double
+      wildcard ** replaces one or more RDN components (as in
+      uid=dmiller,**,dc=example,dc=com). A simple wildcard * replaces either a
+      whole RDN, or a whole type, or a value substring (as in
+      uid=bj*,ou=people,dc=example,dc=com).
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on user DN equality.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-user-dn-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="user-dn-not-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters log records associated with users which do not match any of the
+      specified DN patterns.
+    </adm:synopsis>
+    <adm:description>
+      Valid DN filters are strings composed of zero or more wildcards. A double
+      wildcard ** replaces one or more RDN components (as in
+      uid=dmiller,**,dc=example,dc=com). A simple wildcard * replaces either a
+      whole RDN, or a whole type, or a value substring (as in
+      uid=bj*,ou=people,dc=example,dc=com).
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on user DN inequality.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-user-dn-not-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="user-is-member-of" multi-valued="true">
+    <adm:synopsis>
+      Filters log records associated with users which are members of at least
+      one of the specified groups.
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on group membership.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:dn />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-user-is-member-of</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="user-is-not-member-of" multi-valued="true">
+    <adm:synopsis>
+      Filters log records associated with users which are not members of any
+      of the specified groups.
+    </adm:synopsis>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on group non-membership.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:dn />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-user-is-not-member-of</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="request-target-dn-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters operation log records associated with operations which target
+      entries matching at least one of the specified DN patterns.
+    </adm:synopsis>
+    <adm:description>
+      Valid DN filters are strings composed of zero or more wildcards. A double
+      wildcard ** replaces one or more RDN components (as in
+      uid=dmiller,**,dc=example,dc=com). A simple wildcard * replaces either a
+      whole RDN, or a whole type, or a value substring (as in
+      uid=bj*,ou=people,dc=example,dc=com).
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on target DN equality.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-request-target-dn-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="request-target-dn-not-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters operation log records associated with operations which target
+      entries matching none of the specified DN patterns.
+    </adm:synopsis>
+    <adm:description>
+      Valid DN filters are strings composed of zero or more wildcards. A double
+      wildcard ** replaces one or more RDN components (as in
+      uid=dmiller,**,dc=example,dc=com). A simple wildcard * replaces either a
+      whole RDN, or a whole type, or a value substring (as in
+      uid=bj*,ou=people,dc=example,dc=com).
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on target DN inequality.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-request-target-dn-not-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="response-result-code-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters operation response log records associated with operations which
+      include any of the specified result codes.
+    </adm:synopsis>
+    <adm:description>
+      It is recommended to only use this criteria in conjunction with the
+      "combined" output mode of the access logger, since this filter criteria
+      is only applied to response log messages.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on result code equality.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-response-result-code-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="response-result-code-not-equal-to" multi-valued="true">
+    <adm:synopsis>
+      Filters operation response log records associated with operations which
+      do not include any of the specified result codes.
+    </adm:synopsis>
+    <adm:description>
+      It is recommended to only use this criteria in conjunction with the
+      "combined" output mode of the access logger, since this filter criteria
+      is only applied to response log messages.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on result code inequality.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-response-result-code-not-equal-to</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="response-etime-greater-than">
+    <adm:synopsis>
+      Filters operation response log records associated with operations which
+      took longer than the specified number of milli-seconds to complete.
+    </adm:synopsis>
+    <adm:description>
+      It is recommended to only use this criteria in conjunction with the
+      "combined" output mode of the access logger, since this filter criteria
+      is only applied to response log messages.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on the etime.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer>
+        <adm:unit-synopsis>milli-seconds</adm:unit-synopsis>
+      </adm:integer>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-response-etime-greater-than</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="response-etime-less-than">
+    <adm:synopsis>
+      Filters operation response log records associated with operations which
+      took less than the specified number of milli-seconds to complete.
+    </adm:synopsis>
+    <adm:description>
+      It is recommended to only use this criteria in conjunction with the
+      "combined" output mode of the access logger, since this filter criteria
+      is only applied to response log messages.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on the etime.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer>
+        <adm:unit-synopsis>milli-seconds</adm:unit-synopsis>
+      </adm:integer>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-response-etime-less-than</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="search-response-nentries-greater-than">
+    <adm:synopsis>
+      Filters search operation response log records associated with searches
+      which returned more than the specified number of entries.
+    </adm:synopsis>
+    <adm:description>
+      It is recommended to only use this criteria in conjunction with the
+      "combined" output mode of the access logger, since this filter criteria
+      is only applied to response log messages.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on the number of search results returned.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer>
+        <adm:unit-synopsis>entries</adm:unit-synopsis>
+      </adm:integer>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-search-response-nentries-greater-than</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="search-response-nentries-less-than">
+    <adm:synopsis>
+      Filters search operation response log records associated with searches
+      which returned less than the specified number of entries.
+    </adm:synopsis>
+    <adm:description>
+      It is recommended to only use this criteria in conjunction with the
+      "combined" output mode of the access logger, since this filter criteria
+      is only applied to response log messages.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on the number of search results returned.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:integer>
+        <adm:unit-synopsis>entries</adm:unit-synopsis>
+      </adm:integer>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-search-response-nentries-less-than</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="search-response-is-indexed">
+    <adm:synopsis>
+      Filters search operation response log records associated with searches
+      which were either indexed or unindexed.
+    </adm:synopsis>
+    <adm:description>
+      It is recommended to only use this criteria in conjunction with the
+      "combined" output mode of the access logger, since this filter criteria
+      is only applied to response log messages.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          Do not filter based on whether or not a search was indexed.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:boolean/>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-search-response-is-indexed</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
 </adm:managed-object>
diff --git a/opends/src/admin/messages/AccessLogFilteringCriteriaCfgDefn.properties b/opends/src/admin/messages/AccessLogFilteringCriteriaCfgDefn.properties
index 00038dc..f1e22cd 100644
--- a/opends/src/admin/messages/AccessLogFilteringCriteriaCfgDefn.properties
+++ b/opends/src/admin/messages/AccessLogFilteringCriteriaCfgDefn.properties
@@ -1,8 +1,21 @@
 user-friendly-name=Access Log Filtering Criteria
 user-friendly-plural-name=Access Log Filtering Criteria
 synopsis=A set of rules which together determine whether a log record should be logged or not.
-property.log-record-type.synopsis=
-property.log-record-type.default-behavior.alias.synopsis=All records
+property.client-address-equal-to.synopsis=Filters log records associated with connections which match at least one of the specified client host names or address masks.
+property.client-address-equal-to.description=Valid values include a host name, a fully qualified domain name, a domain name, an IP address, or a subnetwork with subnetwork mask.
+property.client-address-equal-to.default-behavior.alias.synopsis=Do not filter based on client address equality.
+property.client-address-not-equal-to.synopsis=Filters log records associated with connections which do not match any of the specified client host names or address masks.
+property.client-address-not-equal-to.description=Valid values include a host name, a fully qualified domain name, a domain name, an IP address, or a subnetwork with subnetwork mask.
+property.client-address-not-equal-to.default-behavior.alias.synopsis=Do not filter based on client address inequality.
+property.client-port-equal-to.synopsis=Filters log records associated with connections to any of the specified listener port numbers.
+property.client-port-equal-to.default-behavior.alias.synopsis=Do not filter based on the port.
+property.client-protocol-equal-to.synopsis=Filters log records associated with connections which match any of the specified protocols.
+property.client-protocol-equal-to.default-behavior.alias.synopsis=Do not filter based on the protocol.
+property.client-protocol-equal-to.syntax.enumeration.value.jmx.synopsis=JMX clients
+property.client-protocol-equal-to.syntax.enumeration.value.ldap.synopsis=LDAP clients
+property.client-protocol-equal-to.syntax.enumeration.value.ldaps.synopsis=LDAPS clients
+property.log-record-type.synopsis=Filters log records based on their type.
+property.log-record-type.default-behavior.alias.synopsis=The log record type will be ignored during filtering.
 property.log-record-type.syntax.enumeration.value.abandon.synopsis=Abandon operations
 property.log-record-type.syntax.enumeration.value.add.synopsis=Add operations
 property.log-record-type.syntax.enumeration.value.bind.synopsis=Bind operations
@@ -15,3 +28,40 @@
 property.log-record-type.syntax.enumeration.value.rename.synopsis=Rename operations
 property.log-record-type.syntax.enumeration.value.search.synopsis=Search operations
 property.log-record-type.syntax.enumeration.value.unbind.synopsis=Unbind operations
+property.request-target-dn-equal-to.synopsis=Filters operation log records associated with operations which target entries matching at least one of the specified DN patterns.
+property.request-target-dn-equal-to.description=Valid DN filters are strings composed of zero or more wildcards. A double wildcard ** replaces one or more RDN components (as in uid=dmiller,**,dc=example,dc=com). A simple wildcard * replaces either a whole RDN, or a whole type, or a value substring (as in uid=bj*,ou=people,dc=example,dc=com).
+property.request-target-dn-equal-to.default-behavior.alias.synopsis=Do not filter based on target DN equality.
+property.request-target-dn-not-equal-to.synopsis=Filters operation log records associated with operations which target entries matching none of the specified DN patterns.
+property.request-target-dn-not-equal-to.description=Valid DN filters are strings composed of zero or more wildcards. A double wildcard ** replaces one or more RDN components (as in uid=dmiller,**,dc=example,dc=com). A simple wildcard * replaces either a whole RDN, or a whole type, or a value substring (as in uid=bj*,ou=people,dc=example,dc=com).
+property.request-target-dn-not-equal-to.default-behavior.alias.synopsis=Do not filter based on target DN inequality.
+property.response-etime-greater-than.synopsis=Filters operation response log records associated with operations which took longer than the specified number of milli-seconds to complete.
+property.response-etime-greater-than.description=It is recommended to only use this criteria in conjunction with the "combined" output mode of the access logger, since this filter criteria is only applied to response log messages.
+property.response-etime-greater-than.default-behavior.alias.synopsis=Do not filter based on the etime.
+property.response-etime-less-than.synopsis=Filters operation response log records associated with operations which took less than the specified number of milli-seconds to complete.
+property.response-etime-less-than.description=It is recommended to only use this criteria in conjunction with the "combined" output mode of the access logger, since this filter criteria is only applied to response log messages.
+property.response-etime-less-than.default-behavior.alias.synopsis=Do not filter based on the etime.
+property.response-result-code-equal-to.synopsis=Filters operation response log records associated with operations which include any of the specified result codes.
+property.response-result-code-equal-to.description=It is recommended to only use this criteria in conjunction with the "combined" output mode of the access logger, since this filter criteria is only applied to response log messages.
+property.response-result-code-equal-to.default-behavior.alias.synopsis=Do not filter based on result code equality.
+property.response-result-code-not-equal-to.synopsis=Filters operation response log records associated with operations which do not include any of the specified result codes.
+property.response-result-code-not-equal-to.description=It is recommended to only use this criteria in conjunction with the "combined" output mode of the access logger, since this filter criteria is only applied to response log messages.
+property.response-result-code-not-equal-to.default-behavior.alias.synopsis=Do not filter based on result code inequality.
+property.search-response-is-indexed.synopsis=Filters search operation response log records associated with searches which were either indexed or unindexed.
+property.search-response-is-indexed.description=It is recommended to only use this criteria in conjunction with the "combined" output mode of the access logger, since this filter criteria is only applied to response log messages.
+property.search-response-is-indexed.default-behavior.alias.synopsis=Do not filter based on whether or not a search was indexed.
+property.search-response-nentries-greater-than.synopsis=Filters search operation response log records associated with searches which returned more than the specified number of entries.
+property.search-response-nentries-greater-than.description=It is recommended to only use this criteria in conjunction with the "combined" output mode of the access logger, since this filter criteria is only applied to response log messages.
+property.search-response-nentries-greater-than.default-behavior.alias.synopsis=Do not filter based on the number of search results returned.
+property.search-response-nentries-less-than.synopsis=Filters search operation response log records associated with searches which returned less than the specified number of entries.
+property.search-response-nentries-less-than.description=It is recommended to only use this criteria in conjunction with the "combined" output mode of the access logger, since this filter criteria is only applied to response log messages.
+property.search-response-nentries-less-than.default-behavior.alias.synopsis=Do not filter based on the number of search results returned.
+property.user-dn-equal-to.synopsis=Filters log records associated with users matching at least one of the specified DN patterns.
+property.user-dn-equal-to.description=Valid DN filters are strings composed of zero or more wildcards. A double wildcard ** replaces one or more RDN components (as in uid=dmiller,**,dc=example,dc=com). A simple wildcard * replaces either a whole RDN, or a whole type, or a value substring (as in uid=bj*,ou=people,dc=example,dc=com).
+property.user-dn-equal-to.default-behavior.alias.synopsis=Do not filter based on user DN equality.
+property.user-dn-not-equal-to.synopsis=Filters log records associated with users which do not match any of the specified DN patterns.
+property.user-dn-not-equal-to.description=Valid DN filters are strings composed of zero or more wildcards. A double wildcard ** replaces one or more RDN components (as in uid=dmiller,**,dc=example,dc=com). A simple wildcard * replaces either a whole RDN, or a whole type, or a value substring (as in uid=bj*,ou=people,dc=example,dc=com).
+property.user-dn-not-equal-to.default-behavior.alias.synopsis=Do not filter based on user DN inequality.
+property.user-is-member-of.synopsis=Filters log records associated with users which are members of at least one of the specified groups.
+property.user-is-member-of.default-behavior.alias.synopsis=Do not filter based on group membership.
+property.user-is-not-member-of.synopsis=Filters log records associated with users which are not members of any of the specified groups.
+property.user-is-not-member-of.default-behavior.alias.synopsis=Do not filter based on group non-membership.
diff --git a/opends/src/server/org/opends/server/core/networkgroups/IPConnectionCriteria.java b/opends/src/server/org/opends/server/core/networkgroups/IPConnectionCriteria.java
index 6575a22..b67e15e 100644
--- a/opends/src/server/org/opends/server/core/networkgroups/IPConnectionCriteria.java
+++ b/opends/src/server/org/opends/server/core/networkgroups/IPConnectionCriteria.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.core.networkgroups;
 
@@ -77,13 +78,10 @@
   public boolean matches(ClientConnection connection)
   {
     InetAddress ipAddr = connection.getRemoteAddress();
-    byte[] address = ipAddr.getAddress();
-    String hostName = ipAddr.getHostName();
 
     if (deniedClients.length > 0)
     {
-      if (AddressMask
-          .maskListContains(address, hostName, deniedClients))
+      if (AddressMask.maskListContains(ipAddr, deniedClients))
       {
         return false;
       }
@@ -91,8 +89,7 @@
 
     if (allowedClients.length > 0)
     {
-      if (!AddressMask.maskListContains(address, hostName,
-          allowedClients))
+      if (!AddressMask.maskListContains(ipAddr, allowedClients))
       {
         return false;
       }
diff --git a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
index 6a0e94b..346e4f5 100644
--- a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
@@ -30,11 +30,15 @@
 
 
 import static org.opends.messages.ConfigMessages.*;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.getTracer;
 import static org.opends.server.util.StaticUtils.getFileForPath;
 import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+import static org.opends.server.util.StaticUtils.toLowerCase;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.InetAddress;
 import java.util.*;
 
 import org.opends.messages.Message;
@@ -50,8 +54,11 @@
 import org.opends.server.api.AccessLogPublisher;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ExtendedOperationHandler;
+import org.opends.server.api.Group;
+import org.opends.server.authorization.dseecompat.PatternDN;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.*;
+import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.*;
 import org.opends.server.util.TimeThread;
 
@@ -65,7 +72,6 @@
     AccessLogPublisher<FileBasedAccessLogPublisherCfg> implements
     ConfigurationChangeListener<FileBasedAccessLogPublisherCfg>
 {
-
   /**
    * Criteria based filter.
    */
@@ -75,6 +81,15 @@
     private final boolean logConnectRecords;
     private final boolean logDisconnectRecords;
     private final EnumSet<OperationType> logOperationRecords;
+    private final AddressMask[] clientAddressEqualTo;
+    private final AddressMask[] clientAddressNotEqualTo;
+    private final PatternDN[] userDNEqualTo;
+    private final PatternDN[] userDNNotEqualTo;
+    private final PatternDN[] targetDNEqualTo;
+    private final PatternDN[] targetDNNotEqualTo;
+    private final DN[] userIsMemberOf;
+    private final DN[] userIsNotMemberOf;
+    private final String attachmentName;
 
 
 
@@ -83,11 +98,18 @@
      *
      * @param cfg
      *          The access log filter criteria.
+     * @throws DirectoryException
+     *           If the configuration cannot be parsed.
      */
     CriteriaFilter(final AccessLogFilteringCriteriaCfg cfg)
+        throws DirectoryException
     {
       this.cfg = cfg;
 
+      // Generate a unique identifier for attaching partial results to
+      // operations.
+      attachmentName = this.getClass().getName() + "#" + hashCode();
+
       // Pre-parse the log record types for more efficient queries.
       if (cfg.getLogRecordType().isEmpty())
       {
@@ -98,10 +120,10 @@
       }
       else
       {
-        logConnectRecords =
-          cfg.getLogRecordType().contains(LogRecordType.CONNECT);
-        logDisconnectRecords =
-          cfg.getLogRecordType().contains(LogRecordType.DISCONNECT);
+        logConnectRecords = cfg.getLogRecordType().contains(
+            LogRecordType.CONNECT);
+        logDisconnectRecords = cfg.getLogRecordType().contains(
+            LogRecordType.DISCONNECT);
 
         logOperationRecords = EnumSet.noneOf(OperationType.class);
         for (final LogRecordType type : cfg.getLogRecordType())
@@ -143,6 +165,43 @@
           }
         }
       }
+
+      clientAddressEqualTo = cfg.getClientAddressEqualTo().toArray(
+          new AddressMask[0]);
+      clientAddressNotEqualTo = cfg.getClientAddressNotEqualTo().toArray(
+          new AddressMask[0]);
+
+      userDNEqualTo = new PatternDN[cfg.getUserDNEqualTo().size()];
+      int i = 0;
+      for (final String s : cfg.getUserDNEqualTo())
+      {
+        userDNEqualTo[i++] = PatternDN.decode(s);
+      }
+
+      userDNNotEqualTo = new PatternDN[cfg.getUserDNNotEqualTo().size()];
+      i = 0;
+      for (final String s : cfg.getUserDNNotEqualTo())
+      {
+        userDNNotEqualTo[i++] = PatternDN.decode(s);
+      }
+
+      userIsMemberOf = cfg.getUserIsMemberOf().toArray(new DN[0]);
+      userIsNotMemberOf = cfg.getUserIsNotMemberOf().toArray(new DN[0]);
+
+      targetDNEqualTo = new PatternDN[cfg.getRequestTargetDNEqualTo().size()];
+      i = 0;
+      for (final String s : cfg.getRequestTargetDNEqualTo())
+      {
+        targetDNEqualTo[i++] = PatternDN.decode(s);
+      }
+
+      targetDNNotEqualTo = new PatternDN[cfg.getRequestTargetDNNotEqualTo()
+          .size()];
+      i = 0;
+      for (final String s : cfg.getRequestTargetDNNotEqualTo())
+      {
+        targetDNNotEqualTo[i++] = PatternDN.decode(s);
+      }
     }
 
 
@@ -157,7 +216,10 @@
         return false;
       }
 
-      // TODO: other checks.
+      if (!filterClientConnection(connection))
+      {
+        return false;
+      }
 
       return true;
     }
@@ -174,7 +236,15 @@
         return false;
       }
 
-      // TODO: other checks.
+      if (!filterClientConnection(connection))
+      {
+        return false;
+      }
+
+      if (!filterUser(connection))
+      {
+        return false;
+      }
 
       return true;
     }
@@ -186,14 +256,17 @@
      */
     public boolean isRequestLoggable(final Operation operation)
     {
-      if (!logOperationRecords.contains(operation.getOperationType()))
-      {
-        return false;
-      }
+      final ClientConnection connection = operation.getClientConnection();
+      final boolean matches = logOperationRecords.contains(operation
+          .getOperationType())
+          && filterClientConnection(connection)
+          && filterUser(connection) && filterRequest(operation);
 
-      // TODO: other checks.
+      // Cache the result so that it does not need to be recomputed for the
+      // response.
+      operation.setAttachment(attachmentName, matches);
 
-      return true;
+      return matches;
     }
 
 
@@ -203,20 +276,435 @@
      */
     public boolean isResponseLoggable(final Operation operation)
     {
-      if (!logOperationRecords.contains(operation.getOperationType()))
+      // First check the result that was computed for the initial request.
+      Boolean requestMatched = (Boolean) operation
+          .getAttachment(attachmentName);
+      if (requestMatched == null)
+      {
+        // This should not happen.
+        if (debugEnabled())
+        {
+          TRACER.debugWarning(
+              "Operation attachment %s not found while logging response",
+              attachmentName);
+        }
+        requestMatched = isRequestLoggable(operation);
+      }
+
+      if (!requestMatched)
       {
         return false;
       }
 
-      // TODO: other checks.
+      // Check the response parameters.
+      if (!filterResponse(operation))
+      {
+        return false;
+      }
 
       return true;
     }
 
+
+
+    private boolean filterClientConnection(final ClientConnection connection)
+    {
+      // Check client address.
+      final InetAddress ipAddr = connection.getRemoteAddress();
+      if (clientAddressNotEqualTo.length > 0)
+      {
+        if (AddressMask.maskListContains(ipAddr, clientAddressNotEqualTo))
+        {
+          return false;
+        }
+      }
+      if (clientAddressEqualTo.length > 0)
+      {
+        if (!AddressMask.maskListContains(ipAddr, clientAddressEqualTo))
+        {
+          return false;
+        }
+      }
+
+      // Check server port.
+      if (!cfg.getClientPortEqualTo().isEmpty())
+      {
+        if (!cfg.getClientPortEqualTo().contains(connection.getServerPort()))
+        {
+          return false;
+        }
+      }
+
+      // Check protocol.
+      if (!cfg.getClientProtocolEqualTo().isEmpty())
+      {
+        if (!cfg.getClientProtocolEqualTo().contains(
+            toLowerCase(connection.getProtocol())))
+        {
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+
+
+    private boolean filterRequest(final Operation operation)
+    {
+      // Check target DN.
+      if (targetDNNotEqualTo.length > 0 || targetDNEqualTo.length > 0)
+      {
+        if (!filterRequestTargetDN(operation))
+        {
+          return false;
+        }
+      }
+
+      // TODO: check required controls.
+
+      return true;
+    }
+
+
+
+    private boolean filterRequestTargetDN(final Operation operation)
+    {
+      // Obtain both the parsed and unparsed target DNs. Requests are logged
+      // before parsing so usually only the raw unparsed target DN will be
+      // present, and it may even be invalid.
+      DN targetDN = null;
+      ByteString rawTargetDN = null;
+
+      switch (operation.getOperationType())
+      {
+      case ABANDON:
+      case UNBIND:
+        // These operations don't have parameters which we can filter so
+        // always match them.
+        return true;
+      case EXTENDED:
+        // These operations could have parameters which can be filtered but
+        // we'd need to decode the request in order to find out. This is
+        // beyond the scope of the access log. Therefore, treat extended
+        // operations like abandon/unbind.
+        return true;
+      case ADD:
+        targetDN = ((AddOperation) operation).getEntryDN();
+        rawTargetDN = ((AddOperation) operation).getRawEntryDN();
+        break;
+      case BIND:
+        // For SASL bind operations the bind DN, if provided, will require the
+        // SASL credentials to be decoded which is beyond the scope of the
+        // access log.
+        targetDN = ((BindOperation) operation).getBindDN();
+        rawTargetDN = ((BindOperation) operation).getRawBindDN();
+        break;
+      case COMPARE:
+        targetDN = ((CompareOperation) operation).getEntryDN();
+        rawTargetDN = ((CompareOperation) operation).getRawEntryDN();
+        break;
+      case DELETE:
+        targetDN = ((DeleteOperation) operation).getEntryDN();
+        rawTargetDN = ((DeleteOperation) operation).getRawEntryDN();
+        break;
+      case MODIFY:
+        targetDN = ((ModifyOperation) operation).getEntryDN();
+        rawTargetDN = ((ModifyOperation) operation).getRawEntryDN();
+        break;
+      case MODIFY_DN:
+        targetDN = ((ModifyDNOperation) operation).getEntryDN();
+        rawTargetDN = ((ModifyDNOperation) operation).getRawEntryDN();
+        break;
+      case SEARCH:
+        targetDN = ((SearchOperation) operation).getBaseDN();
+        rawTargetDN = ((SearchOperation) operation).getRawBaseDN();
+        break;
+      }
+
+      // Attempt to parse the raw target DN if needed.
+      if (targetDN == null)
+      {
+        try
+        {
+          targetDN = DN.decode(rawTargetDN);
+        }
+        catch (final DirectoryException e)
+        {
+          // The DN raw target DN was invalid. It will never match any
+          // not-equal-to nor equal-to patterns, so return appropriate result.
+          if (targetDNEqualTo.length != 0)
+          {
+            // Invalid DN will never match equal-to patterns.
+            return false;
+          }
+          else
+          {
+            // Invalid DN does not match any not-equal-to patterns.
+            return true;
+          }
+        }
+      }
+
+      if (targetDNNotEqualTo.length > 0)
+      {
+        for (final PatternDN pattern : targetDNNotEqualTo)
+        {
+          if (pattern.matchesDN(targetDN))
+          {
+            return false;
+          }
+        }
+      }
+
+      if (targetDNEqualTo.length > 0)
+      {
+        for (final PatternDN pattern : targetDNNotEqualTo)
+        {
+          if (pattern.matchesDN(targetDN))
+          {
+            return true;
+          }
+        }
+      }
+
+      // The target DN did not match.
+      return false;
+    }
+
+
+
+    private boolean filterResponse(final Operation operation)
+    {
+      // Check response code.
+      final Integer resultCode = operation.getResultCode().getIntValue();
+
+      if (!cfg.getResponseResultCodeNotEqualTo().isEmpty())
+      {
+        if (cfg.getResponseResultCodeNotEqualTo().contains(resultCode))
+        {
+          return false;
+        }
+      }
+
+      if (!cfg.getResponseResultCodeEqualTo().isEmpty())
+      {
+        if (!cfg.getResponseResultCodeNotEqualTo().contains(resultCode))
+        {
+          return false;
+        }
+      }
+
+      // Check etime.
+      final long etime = operation.getProcessingTime();
+
+      final Integer etimeGT = cfg.getResponseEtimeLessThan();
+      if (etimeGT != null)
+      {
+        if (etime <= ((long) etimeGT))
+        {
+          return false;
+        }
+      }
+
+      final Integer etimeLT = cfg.getResponseEtimeLessThan();
+      if (etimeLT != null)
+      {
+        if (etime >= ((long) etimeLT))
+        {
+          return false;
+        }
+      }
+
+      // Check search response fields.
+      if (operation instanceof SearchOperation)
+      {
+        final SearchOperation searchOperation = (SearchOperation) operation;
+        final Boolean isIndexed= cfg.isSearchResponseIsIndexed();
+        if (isIndexed != null)
+        {
+          boolean wasUnindexed = false;
+          for (final AdditionalLogItem item : operation.getAdditionalLogItems())
+          {
+            if (item.getKey().equals("unindexed"))
+            {
+              wasUnindexed = true;
+              break;
+            }
+          }
+
+          if (isIndexed)
+          {
+            if (wasUnindexed)
+            {
+              return false;
+            }
+          }
+          else
+          {
+            if (!wasUnindexed)
+            {
+              return false;
+            }
+          }
+        }
+
+        final int nentries = searchOperation.getEntriesSent();
+
+        final Integer nentriesGT = cfg.getSearchResponseNentriesGreaterThan();
+        if (nentriesGT != null)
+        {
+          if (nentries <= nentriesGT)
+          {
+            return false;
+          }
+        }
+
+        final Integer nentriesLT = cfg.getSearchResponseNentriesLessThan();
+        if (nentriesLT != null)
+        {
+          if (nentries >= nentriesLT)
+          {
+            return false;
+          }
+        }
+      }
+
+      return true;
+    }
+
+
+
+    private boolean filterUser(final ClientConnection connection)
+    {
+      // Check user DN.
+      if (userDNNotEqualTo.length > 0 || userDNEqualTo.length > 0)
+      {
+        if (!filterUserBindDN(connection))
+        {
+          return false;
+        }
+      }
+
+      // Check group membership.
+      if (userIsNotMemberOf.length > 0 || userIsNotMemberOf.length > 0)
+      {
+        if (!filterUserIsMemberOf(connection))
+        {
+          return false;
+        }
+      }
+
+      return true;
+    }
+
+
+
+    private boolean filterUserBindDN(final ClientConnection connection)
+    {
+      final DN userDN = connection.getAuthenticationInfo()
+          .getAuthenticationDN();
+
+      // Fast-path for unauthenticated clients.
+      if (userDN == null)
+      {
+        return userDNEqualTo.length == 0;
+      }
+
+      if (userDNNotEqualTo.length > 0)
+      {
+        for (final PatternDN pattern : userDNNotEqualTo)
+        {
+          if (pattern.matchesDN(userDN))
+          {
+            return false;
+          }
+        }
+      }
+
+      if (userDNEqualTo.length > 0)
+      {
+        for (final PatternDN pattern : userDNNotEqualTo)
+        {
+          if (pattern.matchesDN(userDN))
+          {
+            return true;
+          }
+        }
+      }
+
+      // The user DN did not match.
+      return false;
+    }
+
+
+
+    private boolean filterUserIsMemberOf(final ClientConnection connection)
+    {
+      final Entry userEntry = connection.getAuthenticationInfo()
+          .getAuthenticationEntry();
+
+      // Fast-path for unauthenticated clients.
+      if (userEntry == null)
+      {
+        return userIsMemberOf.length == 0;
+      }
+
+      final GroupManager groupManager = DirectoryServer.getGroupManager();
+      if (userIsNotMemberOf.length > 0)
+      {
+        for (final DN groupDN : userIsNotMemberOf)
+        {
+          final Group<?> group = groupManager.getGroupInstance(groupDN);
+          try
+          {
+            if ((group != null) && group.isMember(userEntry))
+            {
+              return false;
+            }
+          }
+          catch (final DirectoryException e)
+          {
+            if (debugEnabled())
+            {
+              TRACER.debugCaught(DebugLogLevel.ERROR, e);
+            }
+          }
+        }
+      }
+
+      if (userIsMemberOf.length > 0)
+      {
+        for (final DN groupDN : userIsMemberOf)
+        {
+          final Group<?> group = groupManager.getGroupInstance(groupDN);
+          try
+          {
+            if ((group != null) && group.isMember(userEntry))
+            {
+              return true;
+            }
+          }
+          catch (final DirectoryException e)
+          {
+            if (debugEnabled())
+            {
+              TRACER.debugCaught(DebugLogLevel.ERROR, e);
+            }
+          }
+        }
+      }
+
+      // The user entry did not match.
+      return false;
+    }
+
   }
 
 
 
+  // TODO: update assigned OIDs WIKI page when complete.
+
   /**
    * Log message filter predicate.
    */
@@ -612,6 +1100,11 @@
 
 
   /**
+   * The tracer object for the debug logger.
+   */
+  private static final DebugTracer TRACER = getTracer();
+
+  /**
    * The category to use when logging responses.
    */
   private static final String CATEGORY_RESPONSE = "RES";
@@ -1992,6 +2485,11 @@
           // TODO: Unable to decode this access log criteria, so log a warning
           // and continue.
         }
+        catch (final DirectoryException e)
+        {
+          // TODO: Unable to decode this access log criteria, so log a warning
+          // and continue.
+        }
       }
     }
     final Filter orFilter = new OrFilter(subFilters.toArray(new Filter[0]));
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
index ffd5370..45cd861 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -1112,9 +1112,7 @@
     // Check to see if the client is on the denied list.
     // If so, then reject it immediately.
     if ((deniedClients.length > 0)
-        && AddressMask.maskListContains(clientAddr
-        .getAddress(), clientAddr.getHostName(),
-        deniedClients)) {
+        && AddressMask.maskListContains(clientAddr, deniedClients)) {
       clientConnection.disconnect(
           DisconnectReason.CONNECTION_REJECTED,
           currentConfig.isSendRejectionNotice(),
@@ -1127,9 +1125,7 @@
     // there is whether the client is on that list. If
     // not, then reject the connection.
     if ((allowedClients.length > 0)
-        && (!AddressMask.maskListContains(clientAddr
-        .getAddress(), clientAddr.getHostName(),
-        allowedClients))) {
+        && (!AddressMask.maskListContains(clientAddr, allowedClients))) {
       clientConnection.disconnect(
           DisconnectReason.CONNECTION_REJECTED,
           currentConfig.isSendRejectionNotice(),
diff --git a/opends/src/server/org/opends/server/types/AddressMask.java b/opends/src/server/org/opends/server/types/AddressMask.java
index ed96f04..4739b94 100644
--- a/opends/src/server/org/opends/server/types/AddressMask.java
+++ b/opends/src/server/org/opends/server/types/AddressMask.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.types;
 import org.opends.messages.Message;
@@ -376,26 +377,27 @@
         return new AddressMask(maskString);
     }
 
+
+
     /**
-     * Indicates whether provided address or hostname matches one of
-     * the address masks in the provided array.
+     * Indicates whether provided address matches one of the address masks in
+     * the provided array.
      *
-     * @param remoteAddr The remote address byte array.
-     * @param remoteName The remote host name string.
-     * @param masks      An array of address masks to check.
-     * @return <CODE>true</CODE> if the provided address or hostname
-     *          does match one of the given address masks, or
-     *         <CODE>false</CODE> if it does not.
+     * @param address
+     *          The address to check.
+     * @param masks
+     *          An array of address masks to check.
+     * @return <CODE>true</CODE> if the provided address matches one of the
+     *         given address masks, or <CODE>false</CODE> if it does not.
      */
-    public  static boolean maskListContains(byte[] remoteAddr,
-                                            String remoteName,
-                                            AddressMask[] masks)
+    public  static boolean maskListContains(InetAddress address,
+        AddressMask[] masks)
     {
-        for (AddressMask mask : masks) {
-            if(mask.match(remoteAddr, remoteName))
-                return true;
-        }
-        return false;
+      for (AddressMask mask : masks)
+      {
+        if (mask.match(address)) return true;
+      }
+      return false;
     }
 
     /**
@@ -412,12 +414,12 @@
     /**
      * Main match function that determines which rule-type match
      * function to use.
-     * @param remoteAddr The remote client address byte array.
-     * @param remoteName The remote client host name.
+     * @param address
+     *          The address to check.
      * @return <CODE>true</CODE>if one of the match functions found
      *         a match or <CODE>false</CODE>if not.
      */
-    private boolean match(byte[] remoteAddr, String remoteName)
+    private boolean match(InetAddress address)
     {
         boolean ret=false;
 
@@ -425,24 +427,24 @@
         case IPv6:
         case IPv4:
             //this Address mask is an IPv4 rule
-            ret=matchAddress(remoteAddr);
+            ret=matchAddress(address.getAddress());
             break;
 
         case HOST:
             // HOST rule use hostname
-            ret=matchHostName(remoteName);
+            ret=matchHostName(address.getHostName());
             break;
 
         case HOSTPATTERN:
             //HOSTPATTERN rule
-            ret=matchPattern(remoteName);
+            ret=matchPattern(address.getHostName());
             break;
 
         case ALLWILDCARD:
             //first try  ipv4 addr match, then hostname
-            ret=matchAddress(remoteAddr);
+            ret=matchAddress(address.getAddress());
             if(!ret)
-                ret=matchHostName(remoteName);
+                ret=matchHostName(address.getHostName());
             break;
         }
         return ret;
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAddressMask.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAddressMask.java
index 32ae9a8..54fbead 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAddressMask.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAddressMask.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.types;
 
@@ -257,7 +258,7 @@
     for(int j = 0; j < addrs.length; j++) {
       try  {
         InetAddress addr = InetAddress.getByName(addrs[j]);
-        if(!AddressMask.maskListContains(addr.getAddress(), hostNames[j], m)) {
+        if(!AddressMask.maskListContains(addr, m)) {
           ret=false;
           break;
         }

--
Gitblit v1.10.0