From 43cb93c0c4c4bdf7649f32768eeea9563f1d5d80 Mon Sep 17 00:00:00 2001
From: Chris Ridd <chris.ridd@forgerock.com>
Date: Tue, 28 Apr 2015 15:55:24 +0000
Subject: [PATCH] CR-6671 OPENDJ-1915 make DSML servlet threadsafe
---
opendj-sdk/opendj-server-legacy/src/dsml/org/opends/dsml/protocol/DSMLServlet.java | 95 ++++++++++++++++++++++++++---------------------
1 files changed, 52 insertions(+), 43 deletions(-)
diff --git a/opendj-sdk/opendj-server-legacy/src/dsml/org/opends/dsml/protocol/DSMLServlet.java b/opendj-sdk/opendj-server-legacy/src/dsml/org/opends/dsml/protocol/DSMLServlet.java
index 34e22d3..90ec1a9 100644
--- a/opendj-sdk/opendj-server-legacy/src/dsml/org/opends/dsml/protocol/DSMLServlet.java
+++ b/opendj-sdk/opendj-server-legacy/src/dsml/org/opends/dsml/protocol/DSMLServlet.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2006-2010 Sun Microsystems, Inc.
- * Portions Copyright 2011-2015 ForgeRock AS
+ * Portions Copyright 2011-2015 ForgeRock AS.
*/
package org.opends.dsml.protocol;
@@ -140,19 +140,8 @@
private static final String ON_ERROR_EXIT = "exit";
private static JAXBContext jaxbContext;
- private ObjectFactory objFactory;
private static Schema schema;
- private MessageFactory messageFactory;
- private MessageFactory messageFactorySOAP_1_1;
- private MessageFactory messageFactorySOAP_1_2;
- private String contentType;
- /**
- * This extends the default handler of SAX parser. It helps to retrieve the
- * requestID value when the xml request is malformed and thus unparsable
- * using SOAP or JAXB.
- */
- private DSMLContentHandler contentHandler;
/** Prevent multiple logging when trying to set unavailable/unsupported parser features */
private static AtomicBoolean logFeatureWarnings = new AtomicBoolean(false);
@@ -167,7 +156,6 @@
private Boolean trustAll;
private Boolean useHTTPAuthzID;
private HashSet<String> exopStrings = new HashSet<String>();
- private org.opends.server.types.Control proxyAuthzControl;
/**
* This method will be called by the Servlet Container when
@@ -239,12 +227,6 @@
}
}
- objFactory = new ObjectFactory();
- messageFactorySOAP_1_1 = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
- messageFactorySOAP_1_2 = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
-
- this.contentHandler = new DSMLContentHandler();
-
DirectoryServer.bootstrapClient();
} catch (Exception je) {
je.printStackTrace();
@@ -353,10 +335,16 @@
// Create response in the beginning as it might be used if the parsing
// fails.
+ ObjectFactory objFactory = new ObjectFactory();
BatchResponse batchResponse = objFactory.createBatchResponse();
List<JAXBElement<?>> batchResponses = batchResponse.getBatchResponses();
+
+ // Thi sis only used for building the response
Document doc = createSafeDocument();
+ MessageFactory messageFactory = null;
+ String messageContentType = null;
+
if (useSSL || useStartTLS)
{
SSLConnectionFactory sslConnectionFactory = new SSLConnectionFactory();
@@ -368,7 +356,7 @@
catch(SSLConnectionException e)
{
batchResponses.add(
- createErrorResponse(
+ createErrorResponse(objFactory,
new LDAPException(LDAPResultCode.CLIENT_SIDE_CONNECT_ERROR,
LocalizableMessage.raw(
"Invalid SSL or TLS configuration to connect to LDAP server."))));
@@ -388,14 +376,25 @@
String headerName = (String) en.nextElement();
String headerVal = req.getHeader(headerName);
if (headerName.equalsIgnoreCase("content-type")) {
- if (headerVal.startsWith(SOAPConstants.SOAP_1_1_CONTENT_TYPE)) {
- messageFactory = messageFactorySOAP_1_1;
- contentType = SOAPConstants.SOAP_1_1_CONTENT_TYPE;
- } else if (headerVal.startsWith(SOAPConstants.SOAP_1_2_CONTENT_TYPE)) {
- messageFactory = messageFactorySOAP_1_2;
- contentType = SOAPConstants.SOAP_1_2_CONTENT_TYPE;
- } else {
- throw new ServletException("Content-Type does not match SOAP 1.1 or SOAP 1.2");
+ try
+ {
+ if (headerVal.startsWith(SOAPConstants.SOAP_1_1_CONTENT_TYPE))
+ {
+ messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
+ messageContentType = SOAPConstants.SOAP_1_1_CONTENT_TYPE;
+ }
+ else if (headerVal.startsWith(SOAPConstants.SOAP_1_2_CONTENT_TYPE))
+ {
+ MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
+ messageContentType = SOAPConstants.SOAP_1_2_CONTENT_TYPE;
+ }
+ else {
+ throw new ServletException("Content-Type does not match SOAP 1.1 or SOAP 1.2");
+ }
+ }
+ catch (SOAPException e)
+ {
+ throw new ServletException(e.getmessage());
}
} else if (headerName.equalsIgnoreCase("authorization") && headerVal.startsWith("Basic "))
{
@@ -421,7 +420,7 @@
} catch (ParseException ex) {
// user/DN:password parsing error
batchResponses.add(
- createErrorResponse(
+ createErrorResponse(objFactory,
new LDAPException(LDAPResultCode.INVALID_CREDENTIALS,
LocalizableMessage.raw(ex.getMessage()))));
break;
@@ -445,7 +444,7 @@
else
{
batchResponses.add(
- createErrorResponse(
+ createErrorResponse(objFactory,
new LDAPException(LDAPResultCode.INVALID_CREDENTIALS,
LocalizableMessage.raw("Invalid configured credentials."))));
}
@@ -460,7 +459,7 @@
if (((!authenticationIsID && (bindDN == null)) || bindPassword == null)
&& batchResponses.isEmpty()) {
batchResponses.add(
- createErrorResponse(
+ createErrorResponse(objFactory,
new LDAPException(LDAPResultCode.INVALID_CREDENTIALS,
LocalizableMessage.raw("Unable to retrieve credentials."))));
}
@@ -475,6 +474,7 @@
// SOAP was unable to parse XML successfully
batchResponses.add(
createXMLParsingErrorResponse(is,
+ objFactory,
batchResponse,
String.valueOf(ex.getCause())));
}
@@ -499,6 +499,7 @@
} catch (JAXBException e) {
// schema validation failed
batchResponses.add(createXMLParsingErrorResponse(is,
+ objFactory,
batchResponse,
String.valueOf(e)));
}
@@ -524,6 +525,7 @@
}
// set requestID in response
batchResponse.setRequestID(batchRequest.getRequestID());
+ org.opends.server.types.Control proxyAuthzControl = null;
boolean connected = false;
@@ -549,14 +551,14 @@
connected = true;
} catch (LDAPConnectionException e) {
// if connection failed, return appropriate error response
- batchResponses.add(createErrorResponse(e));
+ batchResponses.add(createErrorResponse(objFactory, e));
}
}
if ( connected ) {
List<DsmlMessage> list = batchRequest.getBatchRequests();
for (DsmlMessage request : list) {
- JAXBElement<?> result = performLDAPRequest(connection, request);
+ JAXBElement<?> result = performLDAPRequest(connection, objFactory, proxyAuthzControl, request);
if ( result != null ) {
batchResponses.add(result);
}
@@ -588,7 +590,7 @@
try {
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(objFactory.createBatchResponse(batchResponse), doc);
- sendResponse(doc, res);
+ sendResponse(doc, messageFactory, messageContentType, res);
} catch (Exception e) {
e.printStackTrace();
}
@@ -634,6 +636,7 @@
* exception message and the type 'malformed request'.
*
* @param is the XML InputStream to parse
+ * @param objFactory the object factory
* @param batchResponse the JAXB object to fill in
* @param parserErrorMessage the parsing error message
*
@@ -641,18 +644,17 @@
*/
private JAXBElement<ErrorResponse> createXMLParsingErrorResponse(
InputStream is,
+ ObjectFactory objFactory,
BatchResponse batchResponse,
String parserErrorMessage) {
ErrorResponse errorResponse = objFactory.createErrorResponse();
+ DSMLContentHandler contentHandler = new DSMLContentHandler();
try
{
// try alternative XML parsing using SAX to retrieve requestID value
final XMLReader xmlReader = createSafeXMLReader();
-
- // clear previous match
- this.contentHandler.requestID = null;
- xmlReader.setContentHandler(this.contentHandler);
+ xmlReader.setContentHandler(contentHandler);
is.reset();
xmlReader.parse(new InputSource(is));
@@ -672,7 +674,7 @@
if ( parserErrorMessage!= null ) {
errorResponse.setMessage(parserErrorMessage);
}
- batchResponse.setRequestID(this.contentHandler.requestID);
+ batchResponse.setRequestID(contentHandler.requestID);
errorResponse.setType(MALFORMED_REQUEST);
@@ -683,11 +685,12 @@
* Returns an error response with attributes set according to the exception
* provided as argument.
*
+ * @param objFactory the object factory
* @param t the exception that occurred
*
* @return a JAXBElement that contains an ErrorResponse
*/
- private JAXBElement<ErrorResponse> createErrorResponse(Throwable t) {
+ private JAXBElement<ErrorResponse> createErrorResponse(ObjectFactory objFactory, Throwable t) {
// potential exceptions are IOException, LDAPException, DecodeException
ErrorResponse errorResponse = objFactory.createErrorResponse();
@@ -730,12 +733,16 @@
* of error, an error response is returned.
*
* @param connection a connected connection
+ * @param objFactory the object factory
+ * @param proxyAuthzControl a proxy authz control, or null
* @param request the JAXB request to perform
*
* @return null for an abandon request, the expect result for all other
* requests or an error in case of unexpected behaviour.
*/
private JAXBElement<?> performLDAPRequest(LDAPConnection connection,
+ ObjectFactory objFactory,
+ org.opends.server.types.Control proxyAuthzControl,
DsmlMessage request) {
ArrayList<org.opends.server.types.Control> controls =
new ArrayList<org.opends.server.types.Control>(1);
@@ -812,7 +819,7 @@
return objFactory.createBatchResponseAuthResponse(ldapResult);
}
} catch (Throwable t) {
- return createErrorResponse(t);
+ return createErrorResponse(objFactory, t);
}
// should never happen as the schema was validated
return null;
@@ -824,12 +831,14 @@
* or a correct DSML response.
*
* @param doc The document to include in the response.
+ * @param messageFactory The SOAP message factory.
+ * @param contentType The MIME content type to send appropriate for the MessageFactory
* @param res Information about the HTTP response to the client.
*
* @throws IOException If an error occurs while interacting with the client.
* @throws SOAPException If an encoding or decoding error occurs.
*/
- private void sendResponse(Document doc, HttpServletResponse res)
+ private void sendResponse(Document doc, MessageFactory messageFactory, String contentType, HttpServletResponse res)
throws IOException, SOAPException {
SOAPMessage reply = messageFactory.createMessage();
@@ -959,7 +968,7 @@
* This class is used when an XML request is malformed to retrieve the
* requestID value using an event XML parser.
*/
- private static class DSMLContentHandler extends DefaultHandler {
+ private class DSMLContentHandler extends DefaultHandler {
private String requestID;
/**
* This function fetches the requestID value of the batchRequest xml
--
Gitblit v1.10.0