public static void authenticateRequest(HttpServletRequest request, S3AuthParams params) throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException { RestAuth auth = new RestAuth(ServiceProvider.getInstance().getUseSubDomain()); String AWSAccessKey = null; String signature = null; String authorization = null; // [A] Is it an annonymous request? if (null == (authorization = params.getHeader("Authorization"))) { UserContext.current().initContext(); return; } // [B] Is it an authenticated request? int offset = authorization.indexOf("AWS"); if (-1 != offset) { String temp = authorization.substring(offset + 3).trim(); offset = temp.indexOf(":"); AWSAccessKey = temp.substring(0, offset); signature = temp.substring(offset + 1); } // [C] Calculate the signature from the request's headers auth.setDateHeader(request.getHeader("Date")); auth.setContentTypeHeader(request.getHeader("Content-Type")); auth.setContentMD5Header(request.getHeader("Content-MD5")); auth.setHostHeader(request.getHeader("Host")); auth.setQueryString(request.getQueryString()); auth.addUriPath(request.getRequestURI()); // -> are their any Amazon specific (i.e. 'x-amz-' ) headers? HeaderParam[] headers = params.getHeaders(); for (int i = 0; null != headers && i < headers.length; i++) { String headerName = headers[i].getName(); String ignoreCase = headerName.toLowerCase(); if (ignoreCase.startsWith("x-amz-")) auth.addAmazonHeader(headerName + ":" + headers[i].getValue()); } UserInfo info = ServiceProvider.getInstance().getUserInfo(AWSAccessKey); if (info == null) throw new PermissionDeniedException("Unable to authenticate access key: " + AWSAccessKey); try { if (auth.verifySignature(request.getMethod(), info.getSecretKey(), signature)) { UserContext.current() .initContext( AWSAccessKey, info.getSecretKey(), AWSAccessKey, info.getDescription(), request); return; } } catch (SignatureException e) { throw new PermissionDeniedException(e); } catch (UnsupportedEncodingException e) { throw new PermissionDeniedException(e); } throw new PermissionDeniedException("Invalid signature"); }
/** * 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 { } }
private ServletAction routeRequest(HttpServletRequest request) { // URL routing for S3 REST calls. String pathInfo = request.getPathInfo(); String bucketName = null; String key = null; String serviceEndpoint = ServiceProvider.getInstance().getServiceEndpoint(); String host = request.getHeader("Host"); // Check for unrecognized forms of URI information in request if ((pathInfo == null) || (pathInfo.indexOf('/') != 0)) if ("POST".equalsIgnoreCase(request.getMethod())) // Case where request is POST operation with no pathinfo // This is the POST alternative to PUT described at s3.amazonaws.com API doc page 141 { return routePlainPostRequest(request); } // Irrespective of whether the requester is using subdomain or full host naming of path // expressions // to buckets, wherever the request is made up of a service endpoint followed by a /, in AWS S3 // this always // conveys a ListAllMyBuckets command if ((serviceEndpoint.equalsIgnoreCase(host)) && (pathInfo.equalsIgnoreCase("/"))) { request.setAttribute(S3Constants.BUCKET_ATTR_KEY, "/"); return new S3BucketAction(); // for ListAllMyBuckets } // Because there is a leading / at position 0 of pathInfo, now subtract this to process the // remainder pathInfo = pathInfo.substring(1); if (ServiceProvider.getInstance().getUseSubDomain()) { // -> verify the format of the bucket name int endPos = host.indexOf(ServiceProvider.getInstance().getMasterDomain()); if (endPos > 0) { bucketName = host.substring(0, endPos); S3Engine.verifyBucketName(bucketName, false); request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); } else request.setAttribute(S3Constants.BUCKET_ATTR_KEY, ""); if (pathInfo == null || pathInfo.equalsIgnoreCase("/")) { return new S3BucketAction(); } else { String objectKey = pathInfo.substring(1); request.setAttribute(S3Constants.OBJECT_ATTR_KEY, objectKey); return new S3ObjectAction(); } } else { int endPos = pathInfo.indexOf('/'); // Subsequent / character? if (endPos < 1) { bucketName = pathInfo; S3Engine.verifyBucketName(bucketName, false); request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); return new S3BucketAction(); } else { bucketName = pathInfo.substring(0, endPos); key = pathInfo.substring(endPos + 1); S3Engine.verifyBucketName(bucketName, false); if (!key.isEmpty()) { request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); request.setAttribute(S3Constants.OBJECT_ATTR_KEY, pathInfo.substring(endPos + 1)); return new S3ObjectAction(); } else { request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); return new S3BucketAction(); } } } }