/** * Convert the SOAP XML we extract from the DIME message into our local object. Here Axis2 is not * parsing the SOAP for us. I tried to use the Amazon PutObject parser but it keep throwing * exceptions. * * @param putObjectInline * @return * @throws Exception */ public static S3PutObjectRequest toEnginePutObjectRequest(InputStream is) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(is); Node parent = null; Node contents = null; NodeList children = null; String temp = null; String element = null; int count = 0; S3PutObjectRequest request = new S3PutObjectRequest(); // [A] Pull out the simple nodes first NodeList part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Bucket"); if (null != part) { if (null != (contents = part.item(0))) request.setBucketName(contents.getFirstChild().getNodeValue()); } part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Key"); if (null != part) { if (null != (contents = part.item(0))) request.setKey(contents.getFirstChild().getNodeValue()); } part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "ContentLength"); if (null != part) { if (null != (contents = part.item(0))) { String length = contents.getFirstChild().getNodeValue(); if (null != length) request.setContentLength(Long.decode(length)); } } part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "AWSAccessKeyId"); if (null != part) { if (null != (contents = part.item(0))) request.setAccessKey(contents.getFirstChild().getNodeValue()); } part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Signature"); if (null != part) { if (null != (contents = part.item(0))) request.setSignature(contents.getFirstChild().getNodeValue()); } part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Timestamp"); if (null != part) { if (null != (contents = part.item(0))) request.setRawTimestamp(contents.getFirstChild().getNodeValue()); } part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "StorageClass"); if (null != part) { if (null != (contents = part.item(0))) request.setStorageClass(contents.getFirstChild().getNodeValue()); } part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Credential"); if (null != part) { if (null != (contents = part.item(0))) request.setCredential(contents.getFirstChild().getNodeValue()); } // [B] Get a list of all 'Metadata' elements part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Metadata"); if (null != part) { count = part.getLength(); S3MetaDataEntry[] metaEntry = new S3MetaDataEntry[count]; for (int i = 0; i < count; i++) { parent = part.item(i); metaEntry[i] = new S3MetaDataEntry(); // -> get a list of all the children elements of the 'Metadata' parent element if (null != (children = parent.getChildNodes())) { int numChildren = children.getLength(); for (int j = 0; j < numChildren; j++) { contents = children.item(j); element = contents.getNodeName().trim(); if (element.endsWith("Name")) { temp = contents.getFirstChild().getNodeValue(); if (null != temp) metaEntry[i].setName(temp); } else if (element.endsWith("Value")) { temp = contents.getFirstChild().getNodeValue(); if (null != temp) metaEntry[i].setValue(temp); } } } } request.setMetaEntries(metaEntry); } // [C] Get a list of all Grant elements in an AccessControlList part = getElement(doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Grant"); if (null != part) { S3AccessControlList engineAcl = new S3AccessControlList(); count = part.getLength(); for (int i = 0; i < count; i++) { parent = part.item(i); S3Grant engineGrant = new S3Grant(); // -> get a list of all the children elements of the 'Grant' parent element if (null != (children = parent.getChildNodes())) { int numChildren = children.getLength(); for (int j = 0; j < numChildren; j++) { contents = children.item(j); element = contents.getNodeName().trim(); if (element.endsWith("Grantee")) { NamedNodeMap attbs = contents.getAttributes(); if (null != attbs) { Node type = attbs.getNamedItemNS("http://www.w3.org/2001/XMLSchema-instance", "type"); if (null != type) temp = type.getFirstChild().getNodeValue().trim(); else temp = null; if (null != temp && temp.equalsIgnoreCase("CanonicalUser")) { engineGrant.setGrantee(SAcl.GRANTEE_USER); engineGrant.setCanonicalUserID(getChildNodeValue(contents, "ID")); } else throw new UnsupportedOperationException( "Missing http://www.w3.org/2001/XMLSchema-instance:type value"); } } else if (element.endsWith("Permission")) { temp = contents.getFirstChild().getNodeValue().trim(); if (temp.equalsIgnoreCase("READ")) engineGrant.setPermission(SAcl.PERMISSION_READ); else if (temp.equalsIgnoreCase("WRITE")) engineGrant.setPermission(SAcl.PERMISSION_WRITE); else if (temp.equalsIgnoreCase("READ_ACP")) engineGrant.setPermission(SAcl.PERMISSION_READ_ACL); else if (temp.equalsIgnoreCase("WRITE_ACP")) engineGrant.setPermission(SAcl.PERMISSION_WRITE_ACL); else if (temp.equalsIgnoreCase("FULL_CONTROL")) engineGrant.setPermission(SAcl.PERMISSION_FULL); else throw new UnsupportedOperationException("Unsupported permission: " + temp); } } engineAcl.addGrant(engineGrant); } } request.setAcl(engineAcl); } return request; }
/** * A DIME request is really a SOAP request that we are dealing with, and so its authentication is * the SOAP authentication approach. Since Axis2 does not handle DIME messages we deal with them * here. * * @param request * @param response */ private void processDimeRequest(HttpServletRequest request, HttpServletResponse response) { S3PutObjectRequest putRequest = null; S3PutObjectResponse putResponse = null; int bytesRead = 0; S3Engine engine = new S3Engine(); try { logRequest(request); MultiPartDimeInputStream ds = new MultiPartDimeInputStream(request.getInputStream()); // -> the first stream MUST be the SOAP party if (ds.nextInputStream()) { // logger.debug( "DIME msg [" + ds.getStreamType() + "," + ds.getStreamTypeFormat() + "," + // ds.getStreamId() + "]" ); byte[] buffer = new byte[8192]; bytesRead = ds.read(buffer, 0, 8192); // logger.debug( "DIME SOAP Bytes read: " + bytesRead ); ByteArrayInputStream bis = new ByteArrayInputStream(buffer, 0, bytesRead); putRequest = toEnginePutObjectRequest(bis); } // -> we only need to support a DIME message with two bodyparts if (null != putRequest && ds.nextInputStream()) { InputStream is = ds.getInputStream(); putRequest.setData(is); } // -> need to do SOAP level auth here, on failure return the SOAP fault StringBuffer xml = new StringBuffer(); String AWSAccessKey = putRequest.getAccessKey(); UserInfo info = ServiceProvider.getInstance().getUserInfo(AWSAccessKey); try { S3SoapAuth.verifySignature( putRequest.getSignature(), "PutObject", putRequest.getRawTimestamp(), AWSAccessKey, info.getSecretKey()); } catch (AxisFault e) { String reason = e.toString(); int start = reason.indexOf(".AxisFault:"); if (-1 != start) reason = reason.substring(start + 11); xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); xml.append( "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" >\n"); xml.append("<soap:Body>\n"); xml.append("<soap:Fault>\n"); xml.append("<faultcode>").append(e.getFaultCode().toString()).append("</faultcode>\n"); xml.append("<faultstring>").append(reason).append("</faultstring>\n"); xml.append("</soap:Fault>\n"); xml.append("</soap:Body></soap:Envelope>"); endResponse(response, xml.toString()); return; } // -> PutObject S3 Bucket Policy would be done in the engine.handleRequest() call UserContext.current() .initContext(AWSAccessKey, info.getSecretKey(), AWSAccessKey, "S3 DIME request", request); putResponse = engine.handleRequest(putRequest); xml.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); xml.append( "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:tns=\"http://s3.amazonaws.com/doc/2006-03-01/\">"); xml.append("<soap:Body>"); xml.append("<tns:PutObjectResponse>"); xml.append("<tns:PutObjectResponse>"); xml.append("<tns:ETag>\"").append(putResponse.getETag()).append("\"</tns:ETag>"); xml.append("<tns:LastModified>") .append(DatatypeConverter.printDateTime(putResponse.getLastModified())) .append("</tns:LastModified>"); xml.append("</tns:PutObjectResponse></tns:PutObjectResponse>"); xml.append("</soap:Body></soap:Envelope>"); endResponse(response, xml.toString()); } catch (PermissionDeniedException e) { logger.error("Unexpected exception " + e.getMessage(), e); response.setStatus(403); endResponse(response, "Access denied"); } catch (Throwable e) { logger.error("Unexpected exception " + e.getMessage(), e); } finally { } }