From 475b62de777edb285f32607cd4501b9c9d551d63 Mon Sep 17 00:00:00 2001
From: Chris Ridd <chris.ridd@forgerock.com>
Date: Mon, 19 Nov 2012 15:25:30 +0000
Subject: [PATCH] Fix OPENDJ-502 DSML gateway not correctly forwarding modifications to userCertificate;binary attributes

---
 opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java |   30 ----
 opends/build.xml                                                    |    6 
 opends/src/dsml/org/opends/dsml/protocol/ByteStringUtility.java     |   95 +++++++++++++++
 opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java   |    6 
 opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java      |    6 
 opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java   |   71 +++++++----
 opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java  |    3 
 opends/resource/dsml/schema/bindings.xjb                            |   94 +++++++++++++++
 opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java           |    8 
 9 files changed, 255 insertions(+), 64 deletions(-)

diff --git a/opends/build.xml b/opends/build.xml
index 3cbb130..140be66 100644
--- a/opends/build.xml
+++ b/opends/build.xml
@@ -1313,7 +1313,11 @@
 
     <mkdir dir="${dsml.gen.dir}/org/opends/dsml/protocol" />
     <xjc target="${dsml.gen.dir}" schema="${dsml.dir}/schema/DSMLv2.xsd"
-         removeOldOutput="yes" package="org.opends.dsml.protocol">
+         removeOldOutput="yes" package="org.opends.dsml.protocol"
+         binding="${dsml.dir}/schema/bindings.xjb">
+      <!-- Don't generate package-info.java as it conflicts with
+           the one in src/dsml -->
+      <arg value="-npa"/>
       <produces dir="${dsml.gen.dir}/org/opends/dsml/protocol"
            includes="* impl/*" />
     </xjc>
diff --git a/opends/resource/dsml/schema/bindings.xjb b/opends/resource/dsml/schema/bindings.xjb
new file mode 100644
index 0000000..ce4d5c6
--- /dev/null
+++ b/opends/resource/dsml/schema/bindings.xjb
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ! CDDL HEADER START
+  !
+  ! The contents of this file are subject to the terms of the
+  ! Common Development and Distribution License, Version 1.0 only
+  ! (the "License").  You may not use this file except in compliance
+  ! with the License.
+  !
+  ! You can obtain a copy of the license at
+  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
+  ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+  ! See the License for the specific language governing permissions
+  ! and limitations under the License.
+  !
+  ! When distributing Covered Code, include this CDDL HEADER in each
+  ! file and include the License file at
+  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+  ! add the following below this CDDL HEADER, with the fields enclosed
+  ! by brackets "[]" replaced with your own identifying information:
+  !      Portions Copyright [yyyy] [name of copyright owner]
+  !
+  ! CDDL HEADER END
+  !
+  !
+  !      Copyright 2012 ForgeRock, AS.
+  ! -->
+<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="2.0" 
+xmlns:xsd="http://www.w3.org/2001/XMLSchema" schemaLocation="DSMLv2.xsd" >
+ <bindings 
+node="//xsd:complexType[@name='AttributeValueAssertion']/xsd:sequence/xsd:element[@name='value']">
+  <property>
+   <baseType name="java.lang.Object"/>
+  </property>
+ </bindings>
+ <bindings 
+node="//xsd:complexType[@name='SubstringFilter']/xsd:sequence/xsd:element[@name='initial']">
+  <property>
+   <baseType name="java.lang.Object"/>
+  </property>
+ </bindings>
+ <bindings 
+node="//xsd:complexType[@name='SubstringFilter']/xsd:sequence/xsd:element[@name='any']">
+  <property>
+   <baseType name="java.lang.Object"/>
+  </property>
+ </bindings>
+ <bindings 
+node="//xsd:complexType[@name='SubstringFilter']/xsd:sequence/xsd:element[@name='final']">
+  <property>
+   <baseType name="java.lang.Object"/>
+  </property>
+ </bindings>
+ <bindings 
+node="//xsd:complexType[@name='MatchingRuleAssertion']/xsd:sequence/xsd:element[@name='value']">
+  <property>
+   <baseType name="java.lang.Object"/>
+  </property>
+ </bindings>
+ <bindings 
+node="//xsd:complexType[@name='DsmlAttr']/xsd:sequence/xsd:element[@name='value']">
+  <property>
+   <baseType name="java.lang.Object"/>
+  </property>
+ </bindings>
+ <bindings 
+node="//xsd:complexType[@name='DsmlModification']/xsd:sequence/xsd:element[@name='value']">
+  <property>
+   <baseType name="java.lang.Object"/>
+  </property>
+ </bindings>
+ <!--
+ <bindings node="//xsd:complexType[@name='ResultCode']">
+  <property>
+   <baseType name="org.opends.dsml.protocol.SafeResultCode"/>
+  </property>
+ </bindings>
+ <bindings node="//xsd:complexType[@name='LDAPResult']/xsd:complexContent/xsd:extension[@base='DsmlMessage']/xsd:sequence/xsd:element[@name='resultCode']">
+  <property>
+    <baseType name="org.opends.dsml.protocol.SafeResultCode"/>
+  </property>
+ </bindings>
+ -->
+ <bindings node="//xsd:complexType[@name='ExtendedRequest']/xsd:complexContent/xsd:extension[@base='DsmlMessage']/xsd:sequence/xsd:element[@name='requestValue']">
+  <property>
+   <baseType name="java.lang.Object"/>
+  </property>
+ </bindings>
+ <bindings node="//xsd:complexType[@name='ExtendedResponse']/xsd:complexContent/xsd:extension[@base='LDAPResult']/xsd:sequence/xsd:element[@name='response']">
+  <property>
+   <baseType name="java.lang.Object"/>
+  </property>
+ </bindings>
+</bindings>
diff --git a/opends/src/dsml/org/opends/dsml/protocol/ByteStringUtility.java b/opends/src/dsml/org/opends/dsml/protocol/ByteStringUtility.java
new file mode 100644
index 0000000..c0498df
--- /dev/null
+++ b/opends/src/dsml/org/opends/dsml/protocol/ByteStringUtility.java
@@ -0,0 +1,95 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2012 ForgeRock AS.
+ */
+package org.opends.dsml.protocol;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ByteStringBuilder;
+import org.w3c.dom.Element;
+
+/**
+ * A utility class to assist in converting DsmlValues (in Objects) into
+ * the required ByteStrings.
+ */
+public class ByteStringUtility
+{
+  /**
+   * Returns a ByteString from a DsmlValue Object.
+   *
+   * @param obj
+   *           the DsmlValue object.
+   * @return a new ByteString object with the value, or null if val was null,
+   *         or if it could not be converted.
+   * @throws IOException if any problems occurred retrieving an anyURI value.
+   */
+  public static ByteString convertValue(Object obj)
+      throws IOException, MalformedURLException
+  {
+    ByteString bs = null;
+    if (obj != null)
+    {
+      if (obj instanceof String)
+      {
+        bs = ByteString.valueOf((String)obj);
+      }
+      else if (obj instanceof byte [])
+      {
+        bs = ByteString.wrap((byte [])obj);
+      }
+      else if (obj instanceof URI)
+      {
+        // read raw content and return as a byte[].
+        InputStream is = null;
+        try
+        {
+          is = ((URI) obj).toURL().openStream();
+          ByteStringBuilder bsb = new ByteStringBuilder();
+          while (bsb.append(is, 2048) != -1)
+          {
+            // do nothing
+          }
+          bs = bsb.toByteString();
+        }
+        finally
+        {
+          is.close();
+        }
+      }
+      else if (obj instanceof Element)
+      {
+        Element element = (Element) obj;
+        bs = ByteString.valueOf(element.getTextContent());
+      }
+    }
+    return bs;
+  }
+
+}
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java
index 7b32cbd..ef8a3e4 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLAddOperation.java
@@ -98,10 +98,10 @@
     for(DsmlAttr attr : addList)
     {
       ArrayList<ByteString> values = new ArrayList<ByteString>();
-      List<String> vals = attr.getValue();
-      for(String val : vals)
+      List<Object> vals = attr.getValue();
+      for(Object val : vals)
       {
-        values.add(ByteString.valueOf(val));
+        values.add(ByteStringUtility.convertValue(val));
       }
       LDAPAttribute ldapAttribute = new LDAPAttribute(attr.getName(), values);
       attributes.add(ldapAttribute);
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java
index c8c4706..b01e399 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLCompareOperation.java
@@ -91,7 +91,8 @@
     // Read the attribute name and value for the compare request.
     AttributeValueAssertion attrValAssertion = compareRequest.getAssertion();
     String attrName = attrValAssertion.getName();
-    ByteString attrValue = ByteString.valueOf(attrValAssertion.getValue());
+    Object assertion = attrValAssertion.getValue();
+    ByteString attrValue = ByteStringUtility.convertValue(assertion);
     ByteString dnStr = ByteString.valueOf(compareRequest.getDn());
 
     // Create and send the LDAP compare request to the server.
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java
index 59681b7..4179833 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLExtendedOperation.java
@@ -43,8 +43,6 @@
 import org.opends.server.types.ByteString;
 import org.opends.server.types.LDAPException;
 
-import org.w3c.dom.Element;
-
 
 /**
  * This class provides the functionality for the performing an
@@ -114,33 +112,7 @@
 
     String requestName = extendedRequest.getRequestName();
     Object value = extendedRequest.getRequestValue();
-    ByteString asnValue = null;
-    // value is optional in the request
-    if (value != null)
-    {
-      /*
-       * The processing of the value is tricky, because the schema defines
-       * the requestValue with type="xsd:anyType".
-       *
-       * Consequently if we have:
-       * <requestValue xsi:type="xsd:base64Binary">(base64)</requestValue>
-       * then JAXB returns us a byte [] containing the decoded data.
-       */
-      if (value instanceof byte [])
-      {
-        asnValue = ByteString.wrap((byte [])value);
-      }
-      else
-      {
-        /*
-         * On the other hand if we have:
-         * <requestValue>arbitrary text</requestValue>
-         * then we get an Element which we have to extract the text from.
-         */
-        Element content = (Element)value;
-        asnValue = ByteString.valueOf(content.getTextContent());
-      }
-    }
+    ByteString asnValue = ByteStringUtility.convertValue(value);
 
     // Create and send the LDAP request to the server.
     ProtocolOp op = new ExtendedRequestProtocolOp(requestName, asnValue);
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java
index 3361549..364d154 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLModifyOperation.java
@@ -114,10 +114,10 @@
       String attrType = attr.getName();
       ArrayList<ByteString> values = new ArrayList<ByteString> ();
 
-      List<String> vals = attr.getValue();
-      for(String val : vals)
+      List<Object> vals = attr.getValue();
+      for(Object val : vals)
       {
-        values.add(ByteString.valueOf(val));
+        values.add(ByteStringUtility.convertValue(val));
       }
       LDAPAttribute ldapAttr = new LDAPAttribute(attrType, values);
 
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java
index e7325a2..a0b2337 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLSearchOperation.java
@@ -93,9 +93,10 @@
    * @throws LDAPException
    *           an LDAPException is thrown if the creation of a filter
    *           component fails.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
   private static LDAPFilter createANDFilter(FilterSet filterSet)
-      throws LDAPException
+      throws LDAPException, IOException
   {
     List<JAXBElement<?>> list = filterSet.getFilterGroup();
     ArrayList<RawFilter> filters = new ArrayList<RawFilter>(list.size());
@@ -118,11 +119,13 @@
    *          filter.
    * @return a new Approximate search filter with the provided
    *         information.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
   private static LDAPFilter createApproximateFilter(AttributeValueAssertion ava)
+    throws IOException
   {
-    return LDAPFilter.createApproximateFilter(ava.getName(), ByteString
-        .valueOf(ava.getValue()));
+    return LDAPFilter.createApproximateFilter(ava.getName(),
+        ByteStringUtility.convertValue(ava.getValue()));
   }
 
 
@@ -135,11 +138,13 @@
    *          the attribute value assertion for this Equality filter.
    * @return a new Equality search filter with the provided
    *         information.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
   private static LDAPFilter createEqualityFilter(AttributeValueAssertion ava)
+    throws IOException
   {
-    return LDAPFilter.createEqualityFilter(ava.getName(), ByteString
-        .valueOf(ava.getValue()));
+    return LDAPFilter.createEqualityFilter(ava.getName(),
+        ByteStringUtility.convertValue(ava.getValue()));
   }
 
 
@@ -152,11 +157,14 @@
    *          the matching rule assertion for this Extensible filter.
    * @return a new Extensible search filter with the provided
    *         information.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
   private static LDAPFilter createExtensibleFilter(MatchingRuleAssertion mra)
+    throws IOException
   {
     return LDAPFilter.createExtensibleFilter(mra.getMatchingRule(), mra
-        .getName(), ByteString.valueOf(mra.getValue()), mra.isDnAttributes());
+        .getName(), ByteStringUtility.convertValue(mra.getValue()),
+        mra.isDnAttributes());
   }
 
 
@@ -170,12 +178,14 @@
    *          filter.
    * @return a new GreaterOrEqual search filter with the provided
    *         information.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
   private static LDAPFilter createGreaterOrEqualFilter(
       AttributeValueAssertion ava)
+    throws IOException
   {
-    return LDAPFilter.createGreaterOrEqualFilter(ava.getName(), ByteString
-        .valueOf(ava.getValue()));
+    return LDAPFilter.createGreaterOrEqualFilter(ava.getName(),
+        ByteStringUtility.convertValue(ava.getValue()));
   }
 
 
@@ -189,11 +199,13 @@
    *          filter.
    * @return a new LessOrEqual search filter with the provided
    *         information.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
   private static LDAPFilter createLessOrEqualFilter(AttributeValueAssertion ava)
+    throws IOException
   {
-    return LDAPFilter.createLessOrEqualFilter(ava.getName(), ByteString
-        .valueOf(ava.getValue()));
+    return LDAPFilter.createLessOrEqualFilter(ava.getName(),
+        ByteStringUtility.convertValue(ava.getValue()));
   }
 
 
@@ -207,8 +219,10 @@
    * @throws LDAPException
    *           an LDAPException is thrown if the creation of the
    *           provided filter fails.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
-  private static LDAPFilter createNOTFilter(Filter filter) throws LDAPException
+  private static LDAPFilter createNOTFilter(Filter filter)
+    throws LDAPException, IOException
   {
     return LDAPFilter.createNOTFilter(createFilter(filter));
   }
@@ -226,9 +240,10 @@
    * @throws LDAPException
    *           an LDAPException is thrown if the creation of a filter
    *           component fails.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
   private static LDAPFilter createORFilter(FilterSet filterSet)
-      throws LDAPException
+      throws LDAPException, IOException
   {
     List<JAXBElement<?>> list = filterSet.getFilterGroup();
     ArrayList<RawFilter> filters = new ArrayList<RawFilter>(list.size());
@@ -271,17 +286,19 @@
    *          the substring filter for this Substring filter.
    * @return a new Substring search filter with the provided
    *         information.
+   * @throws LDAPException if the filter could not be decoded.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
   private static LDAPFilter createSubstringFilter(SubstringFilter sf)
-        throws LDAPException
+        throws LDAPException, IOException
   {
-    List<String> anys = sf.getAny();
-    ArrayList<ByteString> subAnyElements = new ArrayList<ByteString>(anys
+    List<Object> anyo = sf.getAny();
+    ArrayList<ByteString> subAnyElements = new ArrayList<ByteString>(anyo
         .size());
 
-    for (String s : anys)
+    for (Object o : anyo)
     {
-      subAnyElements.add(ByteString.valueOf(s));
+      subAnyElements.add(ByteStringUtility.convertValue(o));
     }
     if(sf.getInitial() == null && subAnyElements.isEmpty()
             && sf.getFinal()==null)
@@ -289,9 +306,12 @@
       Message message = ERR_LDAP_FILTER_DECODE_NULL.get();
       throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
     }
-    return LDAPFilter.createSubstringFilter(sf.getName(), sf.getInitial()==null?
-      null:ByteString.valueOf(sf.getInitial()), subAnyElements,
-      sf.getFinal()==null?null:ByteString.valueOf(sf.getFinal()));
+    return LDAPFilter.createSubstringFilter(sf.getName(),
+        sf.getInitial() == null ? null : ByteStringUtility
+            .convertValue(sf.getInitial()),
+        subAnyElements,
+        sf.getFinal() == null ? null : ByteStringUtility
+            .convertValue(sf.getFinal()));
   }
 
 
@@ -310,9 +330,10 @@
    * @throws LDAPException
    *           an LDAPException is thrown if the creation of the
    *           targeted filter fails.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
   private static LDAPFilter createFilter(JAXBElement<?> xmlElement)
-      throws LDAPException
+      throws LDAPException, IOException
   {
     LDAPFilter result = null;
 
@@ -395,8 +416,10 @@
    * @throws LDAPException
    *           an LDAPException is thrown if the creation of the
    *           targeted filter fails.
+   * @throws IOException if a value is an anyURI and cannot be fetched.
    */
-  private static LDAPFilter createFilter(Filter filter) throws LDAPException
+  private static LDAPFilter createFilter(Filter filter)
+    throws LDAPException, IOException
   {
 
     LDAPFilter result = null;
@@ -561,11 +584,11 @@
             DsmlAttr dsmlAttr = objFactory.createDsmlAttr();
 
             dsmlAttr.setName(nm);
-            List<String> dsmlAttrVal = dsmlAttr.getValue();
+            List<Object> dsmlAttrVal = dsmlAttr.getValue();
             ArrayList<ByteString> vals = attr.getValues();
             for (ByteString val : vals)
             {
-              dsmlAttrVal.add(val.toString());
+              dsmlAttrVal.add(val);
             }
             attrList.add(dsmlAttr);
           }
diff --git a/opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java b/opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java
index 83191ae..e127c91 100644
--- a/opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java
+++ b/opends/src/dsml/org/opends/dsml/protocol/DSMLServlet.java
@@ -124,6 +124,7 @@
   private static final String AUTHENTICATION_FAILED = "authenticationFailed";
   private static final String COULD_NOT_CONNECT = "couldNotConnect";
   private static final String GATEWAY_INTERNAL_ERROR = "gatewayInternalError";
+  private static final String UNRESOLVABLE_URI = "unresolvableURI";
 
   private static final String UNKNOWN_ERROR = "Unknown error";
 
@@ -199,11 +200,10 @@
        * and if the value's true then mark that OID (1.2.3.4.5) as one returning
        * a string value.
        */
-      Enumeration<String> names = config.getServletContext()
-          .getInitParameterNames();
+      Enumeration names = config.getServletContext().getInitParameterNames();
       while (names.hasMoreElements())
       {
-        String name = names.nextElement().toString();
+        String name = (String) names.nextElement();
         if (name.startsWith(EXOPSTRINGPREFIX) &&
             Boolean.valueOf(config.getServletContext().getInitParameter(name)))
         {
@@ -650,6 +650,8 @@
       }
     } else if ( t instanceof LDAPConnectionException ) {
       errorResponse.setType(COULD_NOT_CONNECT);
+    } else if ( t instanceof IOException ) {
+      errorResponse.setType(UNRESOLVABLE_URI);
     } else {
       errorResponse.setType(GATEWAY_INTERNAL_ERROR);
     }

--
Gitblit v1.10.0