/*
* 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 legal-notices/CDDLv1_0.txt
* 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 legal-notices/CDDLv1_0.txt.
* 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 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS.
*/
/**
* This class provides the entry point for the DSML request.
* It parses the SOAP request, calls the appropriate class
* which performs the LDAP operation, and returns the response
* as a DSML response.
*/
// definitions of return error messages
// definitions of onError values
/** Prevent multiple logging when trying to set unavailable/unsupported parser features */
/**
* This method will be called by the Servlet Container when
* this servlet is being placed into service.
*
* @param config - the <CODE>ServletConfig</CODE> object that
* contains configuration information for this servlet.
* @throws ServletException If an error occurs during processing.
*/
try {
/*
* Find all the param-names matching the pattern:
* ldap.exop.string.1.2.3.4.5
* and if the value's true then mark that OID (1.2.3.4.5) as one returning
* a string value.
*/
while (names.hasMoreElements())
{
{
}
}
// allow the use of anyURI values in adds and modifies
if(jaxbContext==null)
{
}
// assign the DSMLv2 schema for validation
{
}
}
}
}
/**
* Check if using the proxy authz control will work, by using it to read
* the Root DSE.
*
* @param connection The authenticated LDAP connection used to check.
* @param authorizationID The authorization ID, in the format
* "u:<userid>" or "dn:<DN>".
* @return a configured proxy authz control.
* @throws LDAPConnectionException If an error occurs during the check.
*
*/
throws LDAPConnectionException
{
try
{
byte opType;
do {
readMessage();
switch (opType)
{
switch (responseMessage.getSearchResultDoneProtocolOp().
{
default:
throw new LDAPConnectionException(m, CLIENT_SIDE_CONNECT_ERROR,
null);
case LDAPResultCode.SUCCESS:
return proxyAuthzControl;
}
}
} while (true);
}
{
}
}
/**
* The HTTP POST operation. This servlet expects a SOAP message
* with a DSML request payload.
*
* @param req Information about the request received from the client.
* @param res Information about the response to send to the client.
* @throws ServletException If an error occurs during servlet processing.
* @throws IOException If an error occurs while interacting with the client.
*/
throws ServletException, IOException {
// Keep the Servlet input stream buffered in case the SOAP un-marshalling
// fails, the SAX parsing will be able to retrieve the requestID even if
// the XML is malformed by resetting the input stream.
65536);
if ( is.markSupported() ) {
}
// Create response in the beginning as it might be used if the parsing
// fails.
// Thi sis only used for building the response
if (useSSL || useStartTLS)
{
try
{
}
catch(SSLConnectionException e)
{
"Invalid SSL or TLS configuration to connect to LDAP server."))));
}
}
boolean authenticationInHeader = false;
boolean authenticationIsID = false;
while (en.hasMoreElements()) {
try
{
{
}
{
}
else {
throw new ServletException("Content-Type does not match SOAP 1.1 or SOAP 1.2");
}
}
catch (SOAPException e)
{
throw new ServletException(e.getMessage());
}
{
authenticationInHeader = true;
try {
if (colon > 0) {
if (useHTTPAuthzID)
{
authenticationIsID = true;
}
else
{
}
}
} catch (ParseException ex) {
break;
}
}
while (tk.hasMoreTokens()) {
}
}
if ( ! authenticationInHeader ) {
// if no authentication, set default user from web.xml
{
if (userPassword != null)
{
}
else
{
}
}
else
{
bindDN = "";
bindPassword = "";
}
} else {
// otherwise if DN or password is null, send back an error
&& batchResponses.isEmpty()) {
}
}
// if an error already occurred, the list is not empty
if ( batchResponses.isEmpty() ) {
try {
} catch (SOAPException ex) {
// SOAP was unable to parse XML successfully
}
}
if (!(obj instanceof SOAPElement)) {
continue;
}
// Parse and unmarshall the SOAP object - the implementation prevents the use of a
// DOCTYPE and xincludes, so should be safe. There is no way to configure a more
// restrictive parser.
try {
} catch (JAXBException e) {
// schema validation failed
}
if ( batchRequestElement != null ) {
boolean authzInBind = false;
boolean authzInControl = false;
/*
* Process optional authRequest (i.e. use authz)
*/
if (authenticationIsID) {
// If we are using SASL, then use the bind authz.
authzInBind = true;
} else {
// If we are using simple then we have to do some work after
// the bind.
authzInControl = true;
}
}
// set requestID in response
boolean connected = false;
if ( connection == null ) {
try {
if (authzInControl)
{
}
if (authzInBind || authzInControl)
{
}
connected = true;
} catch (LDAPConnectionException e) {
// if connection failed, return appropriate error response
}
}
if ( connected ) {
}
// evaluate response to check if an error occurred
if ( o instanceof ErrorResponse ) {
break;
}
} else if ( o instanceof LDAPResult ) {
{
break;
}
}
}
}
// close connection to LDAP server
if ( connection != null ) {
}
}
}
}
try {
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Safely set a feature on an XMLReader instance.
*
* @param xmlReader The reader to configure.
* @param feature The feature string to set.
* @param flag The value to set the feature to.
*/
{
try
{
}
catch (SAXNotSupportedException e)
{
if (logFeatureWarnings.compareAndSet(false, true))
{
}
}
catch (SAXNotRecognizedException e)
{
if (logFeatureWarnings.compareAndSet(false, true))
{
}
}
}
/**
* Returns an error response after a parsing error. The response has the
* requestID of the batch request, the error response message of the parsing
* 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
*
* @return a JAXBElement that contains an ErrorResponse
*/
try
{
// try alternative XML parsing using SAX to retrieve requestID value
}
{
// ignore
}
if ( parserErrorMessage!= null ) {
}
}
/**
* 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
*/
// potential exceptions are IOException, LDAPException, DecodeException
if ( t instanceof LDAPException ) {
switch(((LDAPException)t).getResultCode()) {
break;
break;
break;
default:
break;
}
} else if ( t instanceof LDAPConnectionException ) {
} else if ( t instanceof IOException ) {
} else {
}
}
/**
* Performs the LDAP operation and sends back the result (if any). In case
* 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.
*/
if (proxyAuthzControl != null)
{
}
try {
if (request instanceof SearchRequest) {
// Process the search request.
} else if (request instanceof AddRequest) {
// Process the add request.
} else if (request instanceof AbandonRequest) {
// Process the abandon request.
return null;
} else if (request instanceof ExtendedRequest) {
// Process the extended request.
controls);
} else if (request instanceof DelRequest) {
// Process the delete request.
} else if (request instanceof CompareRequest) {
// Process the compare request.
controls);
} else if (request instanceof ModifyDNRequest) {
// Process the Modify DN request.
controls);
} else if (request instanceof ModifyRequest) {
// Process the Modify request.
} else if (request instanceof AuthRequest) {
// Process the Auth request.
// Only returns an BatchResponse with an AuthResponse containing the
// LDAP result code AUTH_METHOD_NOT_SUPPORTED
}
} catch (Throwable t) {
return createErrorResponse(objFactory, t);
}
// should never happen as the schema was validated
return null;
}
/**
* Send a response back to the client. This could be either a SOAP fault
* 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, MessageFactory messageFactory, String contentType, HttpServletResponse res)
throws IOException, SOAPException {
header.detachNode();
reply.saveChanges();
}
/**
* Retrieves a message ID that may be used for the next LDAP message sent to
* the Directory Server.
*
* @return A message ID that may be used for the next LDAP message sent to
* the Directory Server.
*/
public static int nextMessageID() {
}
return nextID;
}
/**
* Safely set a feature on an DocumentBuilderFactory instance.
*
* @param factory The DocumentBuilderFactory to configure.
* @param feature The feature string to set.
* @param flag The value to set the feature to.
*/
{
try
{
}
catch (ParserConfigurationException e) {
if (logFeatureWarnings.compareAndSet(false, true))
{
Logger.getLogger(PKG_NAME).log(Level.SEVERE, "DocumentBuilderFactory unsupported feature " + feature);
}
}
}
/**
* Create a Document object that is safe against XML External Entity (XXE) Processing
* attacks.
*
* @return A Document object
* @throws ServletException if a Document object could not be created.
*/
throws ServletException
{
try
{
}
catch (ParserConfigurationException e)
{
if (logFeatureWarnings.compareAndSet(false, true)) {
Logger.getLogger(PKG_NAME).log(Level.SEVERE, "DocumentBuilderFactory cannot be configured securely");
}
}
dbf.setXIncludeAware(false);
dbf.setNamespaceAware(true);
dbf.setValidating(true);
dbf.setExpandEntityReferences(false);
final DocumentBuilder db;
try
{
}
catch (ParserConfigurationException e)
{
throw new ServletException(e.getMessage());
}
return db.newDocument();
}
/**
* Create an XMLReader that is safe against XML External Entity (XXE) Processing attacks.
*
* @return an XMLReader
* @throws ParserConfigurationException if we cannot obtain a parser.
* @throws SAXException if we cannot obtain a parser.
*/
{
// Ensure we are doing basic secure processing.
saxParserFactory.setXIncludeAware(false);
saxParserFactory.setValidating(false);
// Configure a safe XMLReader appropriate for SOAP.
return xmlReader;
}
/**
* This class is used when an XML request is malformed to retrieve the
* requestID value using an event XML parser.
*/
/**
* This function fetches the requestID value of the batchRequest xml
* element and call the default implementation (super).
*/
}
}
}
/**
* This is defensive - we prevent entity resolving by configuration, but
* just in case, we ensure that nothing resolves.
*/
{
{
}
}
}