use of org.apache.commons.httpclient.Header in project zm-mailbox by Zimbra.
the class ProxyServlet method doProxy.
private void doProxy(HttpServletRequest req, HttpServletResponse resp) throws IOException {
ZimbraLog.clearContext();
boolean isAdmin = isAdminRequest(req);
AuthToken authToken = isAdmin ? getAdminAuthTokenFromCookie(req, resp, true) : getAuthTokenFromCookie(req, resp, true);
if (authToken == null) {
String zAuthToken = req.getParameter(QP_ZAUTHTOKEN);
if (zAuthToken != null) {
try {
authToken = AuthProvider.getAuthToken(zAuthToken);
if (authToken.isExpired()) {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "authtoken expired");
return;
}
if (!authToken.isRegistered()) {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "authtoken is invalid");
return;
}
if (isAdmin && !authToken.isAdmin()) {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "permission denied");
return;
}
} catch (AuthTokenException e) {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "unable to parse authtoken");
return;
}
}
}
if (authToken == null) {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "no authtoken cookie");
return;
}
// get the posted body before the server read and parse them.
byte[] body = copyPostedData(req);
// sanity check
String target = req.getParameter(TARGET_PARAM);
if (target == null) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// check for permission
URL url = new URL(target);
if (!isAdmin && !checkPermissionOnTarget(url, authToken)) {
resp.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
// determine whether to return the target inline or store it as an upload
String uploadParam = req.getParameter(UPLOAD_PARAM);
boolean asUpload = uploadParam != null && (uploadParam.equals("1") || uploadParam.equalsIgnoreCase("true"));
HttpMethod method = null;
try {
HttpClient client = ZimbraHttpConnectionManager.getExternalHttpConnMgr().newHttpClient();
HttpProxyUtil.configureProxy(client);
String reqMethod = req.getMethod();
if (reqMethod.equalsIgnoreCase("GET")) {
method = new GetMethod(target);
} else if (reqMethod.equalsIgnoreCase("POST")) {
PostMethod post = new PostMethod(target);
if (body != null)
post.setRequestEntity(new ByteArrayRequestEntity(body, req.getContentType()));
method = post;
} else if (reqMethod.equalsIgnoreCase("PUT")) {
PutMethod put = new PutMethod(target);
if (body != null)
put.setRequestEntity(new ByteArrayRequestEntity(body, req.getContentType()));
method = put;
} else if (reqMethod.equalsIgnoreCase("DELETE")) {
method = new DeleteMethod(target);
} else {
ZimbraLog.zimlet.info("unsupported request method: " + reqMethod);
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
return;
}
// handle basic auth
String auth, user, pass;
auth = req.getParameter(AUTH_PARAM);
user = req.getParameter(USER_PARAM);
pass = req.getParameter(PASS_PARAM);
if (auth != null && user != null && pass != null) {
if (!auth.equals(AUTH_BASIC)) {
ZimbraLog.zimlet.info("unsupported auth type: " + auth);
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
HttpState state = new HttpState();
state.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(user, pass));
client.setState(state);
method.setDoAuthentication(true);
}
Enumeration headers = req.getHeaderNames();
while (headers.hasMoreElements()) {
String hdr = (String) headers.nextElement();
ZimbraLog.zimlet.debug("incoming: " + hdr + ": " + req.getHeader(hdr));
if (canProxyHeader(hdr)) {
ZimbraLog.zimlet.debug("outgoing: " + hdr + ": " + req.getHeader(hdr));
if (hdr.equalsIgnoreCase("x-host"))
method.getParams().setVirtualHost(req.getHeader(hdr));
else
method.addRequestHeader(hdr, req.getHeader(hdr));
}
}
try {
if (!(reqMethod.equalsIgnoreCase("POST") || reqMethod.equalsIgnoreCase("PUT"))) {
method.setFollowRedirects(true);
}
HttpClientUtil.executeMethod(client, method);
} catch (HttpException ex) {
ZimbraLog.zimlet.info("exception while proxying " + target, ex);
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
int status = method.getStatusLine() == null ? HttpServletResponse.SC_INTERNAL_SERVER_ERROR : method.getStatusCode();
// workaround for Alexa Thumbnails paid web service, which doesn't bother to return a content-type line
Header ctHeader = method.getResponseHeader("Content-Type");
String contentType = ctHeader == null || ctHeader.getValue() == null ? DEFAULT_CTYPE : ctHeader.getValue();
InputStream targetResponseBody = method.getResponseBodyAsStream();
if (asUpload) {
String filename = req.getParameter(FILENAME_PARAM);
if (filename == null || filename.equals(""))
filename = new ContentType(contentType).getParameter("name");
if ((filename == null || filename.equals("")) && method.getResponseHeader("Content-Disposition") != null)
filename = new ContentDisposition(method.getResponseHeader("Content-Disposition").getValue()).getParameter("filename");
if (filename == null || filename.equals(""))
filename = "unknown";
List<Upload> uploads = null;
if (targetResponseBody != null) {
try {
Upload up = FileUploadServlet.saveUpload(targetResponseBody, filename, contentType, authToken.getAccountId());
uploads = Arrays.asList(up);
} catch (ServiceException e) {
if (e.getCode().equals(MailServiceException.UPLOAD_REJECTED))
status = HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE;
else
status = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
}
}
resp.setStatus(status);
FileUploadServlet.sendResponse(resp, status, req.getParameter(FORMAT_PARAM), null, uploads, null);
} else {
resp.setStatus(status);
resp.setContentType(contentType);
for (Header h : method.getResponseHeaders()) if (canProxyHeader(h.getName()))
resp.addHeader(h.getName(), h.getValue());
if (targetResponseBody != null)
ByteUtil.copy(targetResponseBody, true, resp.getOutputStream(), true);
}
} finally {
if (method != null)
method.releaseConnection();
}
}
use of org.apache.commons.httpclient.Header in project zm-mailbox by Zimbra.
the class SoapDebugListener method sendSoapMessage.
@Override
public void sendSoapMessage(PostMethod postMethod, Element envelope, HttpState httpState) {
if (level == Level.OFF) {
return;
}
System.out.println();
System.out.println("=== Request ===");
if (Level.needsHeader(level)) {
try {
URI uri = postMethod.getURI();
System.out.println(uri.toString());
} catch (URIException e) {
e.printStackTrace();
}
// headers
Header[] headers = postMethod.getRequestHeaders();
for (Header header : headers) {
// trim the ending crlf
System.out.println(header.toString().trim());
}
System.out.println();
//cookies
if (httpState != null) {
Cookie[] cookies = httpState.getCookies();
for (Cookie cookie : cookies) {
System.out.println("Cookie: " + cookie.toString());
}
}
System.out.println();
}
if (Level.needsBody(level)) {
System.out.println(envelope.prettyPrint());
}
}
use of org.apache.commons.httpclient.Header in project zm-mailbox by Zimbra.
the class TestCalDav method testAppleCaldavProxyFunctions.
/**
* http://svn.calendarserver.org/repository/calendarserver/CalendarServer/trunk/doc/Extensions/caldav-proxy.txt
* This is an Apple standard implemented by Apple Mac OSX at least up to Yosemite and offers a fairly simple
* sharing model for calendars. The model is simpler than Zimbra's native model and there are mismatches,
* for instance Zimbra requires the proposed delegate to accept shares.
*/
@Test
public void testAppleCaldavProxyFunctions() throws ServiceException, IOException {
Account sharer = users[3].create();
Account sharee1 = users[1].create();
Account sharee2 = users[2].create();
ZMailbox mboxSharer = TestUtil.getZMailbox(sharer.getName());
ZMailbox mboxSharee1 = TestUtil.getZMailbox(sharee1.getName());
ZMailbox mboxSharee2 = TestUtil.getZMailbox(sharee2.getName());
setZimbraPrefAppleIcalDelegationEnabled(mboxSharer, true);
setZimbraPrefAppleIcalDelegationEnabled(mboxSharee1, true);
setZimbraPrefAppleIcalDelegationEnabled(mboxSharee2, true);
// Test PROPPATCH to "calendar-proxy-read" URL
setGroupMemberSet(TestCalDav.getCalendarProxyReadUrl(sharer), sharer, sharee2);
// Test PROPPATCH to "calendar-proxy-write" URL
setGroupMemberSet(TestCalDav.getCalendarProxyWriteUrl(sharer), sharer, sharee1);
// verify that adding new members to groups triggered notification messages
List<ZMessage> msgs = TestUtil.waitForMessages(mboxSharee1, "in:inbox subject:\"Share Created: Calendar shared by \"", 1, 10000);
assertNotNull(String.format("Notification msgs for %s", sharee1.getName()), msgs);
assertEquals(String.format("num msgs for %s", sharee1.getName()), 1, msgs.size());
msgs = TestUtil.waitForMessages(mboxSharee2, "in:inbox subject:\"Share Created: Calendar shared by \"", 1, 10000);
assertNotNull(String.format("Notification msgs for %s", sharee2.getName()), msgs);
assertEquals(String.format("num msgs for %s", sharee2.getName()), 1, msgs.size());
// Simulate acceptance of the shares (would normally need to be done in ZWC
createCalendarMountPoint(mboxSharee1, sharer);
createCalendarMountPoint(mboxSharee2, sharer);
Document doc = delegateForExpandProperty(sharee1);
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(TestCalDav.NamespaceContextForXPath.forCalDAV());
XPathExpression xPathExpr;
try {
String xpathS = "/D:multistatus/D:response/D:href/text()";
xPathExpr = xpath.compile(xpathS);
NodeList result = (NodeList) xPathExpr.evaluate(doc, XPathConstants.NODESET);
assertEquals(String.format("num XPath nodes for %s for %s", xpathS, sharee1.getName()), 1, result.getLength());
String text = (String) xPathExpr.evaluate(doc, XPathConstants.STRING);
assertEquals("HREF for account owner", UrlNamespace.getPrincipalUrl(sharee1).replaceAll("@", "%40"), text);
xpathS = "/D:multistatus/D:response/D:propstat/D:prop/CS:calendar-proxy-write-for/D:response/D:href/text()";
xPathExpr = xpath.compile(xpathS);
result = (NodeList) xPathExpr.evaluate(doc, XPathConstants.NODESET);
assertEquals(String.format("num XPath nodes for %s for %s", xpathS, sharee1.getName()), 1, result.getLength());
text = (String) xPathExpr.evaluate(doc, XPathConstants.STRING);
assertEquals("HREF for sharer", UrlNamespace.getPrincipalUrl(sharer).replaceAll("@", "%40"), text);
} catch (XPathExpressionException e1) {
ZimbraLog.test.debug("xpath problem", e1);
}
// Check that proxy write has sharee1 in it
doc = groupMemberSetExpandProperty(sharer, sharee1, true);
// Check that proxy read has sharee2 in it
doc = groupMemberSetExpandProperty(sharer, sharee2, false);
String davBaseName = "notAllowed@There";
String url = String.format("%s%s", getFolderUrl(sharee1, "Shared Calendar").replaceAll(" ", "%20").replaceAll("@", "%40"), davBaseName);
HttpMethodExecutor exe = doIcalPut(url, sharee1, simpleEvent(sharer), HttpStatus.SC_MOVED_TEMPORARILY);
String location = null;
for (Header hdr : exe.respHeaders) {
if ("Location".equals(hdr.getName())) {
location = hdr.getValue();
}
}
assertNotNull("Location Header not returned when creating", location);
url = String.format("%s%s", getFolderUrl(sharee1, "Shared Calendar").replaceAll(" ", "%20").replaceAll("@", "%40"), location.substring(location.lastIndexOf('/') + 1));
doIcalPut(url, sharee1, simpleEvent(sharer), HttpStatus.SC_CREATED);
}
use of org.apache.commons.httpclient.Header in project zm-mailbox by Zimbra.
the class UserServlet method putRemoteResource.
public static Pair<Header[], HttpInputStream> putRemoteResource(ZAuthToken authToken, String url, InputStream req, Header[] headers) throws ServiceException, IOException {
StringBuilder u = new StringBuilder(url);
u.append("?").append(QP_AUTH).append('=').append(AUTH_COOKIE);
PutMethod method = new PutMethod(u.toString());
String contentType = "application/octet-stream";
if (headers != null) {
for (Header hdr : headers) {
String name = hdr.getName();
method.addRequestHeader(hdr);
if (name.equals("Content-Type"))
contentType = hdr.getValue();
}
}
method.setRequestEntity(new InputStreamRequestEntity(req, contentType));
Pair<Header[], HttpMethod> pair = doHttpOp(authToken, method);
return new Pair<Header[], HttpInputStream>(pair.getFirst(), new HttpInputStream(pair.getSecond()));
}
use of org.apache.commons.httpclient.Header in project zm-mailbox by Zimbra.
the class FileUploadServlet method fetchRemoteUpload.
private static Upload fetchRemoteUpload(String accountId, String uploadId, AuthToken authtoken) throws ServiceException {
// check if we have fetched the Upload from the remote server previously
String localUploadId = null;
synchronized (mProxiedUploadIds) {
localUploadId = mProxiedUploadIds.get(uploadId);
}
if (localUploadId != null) {
synchronized (mPending) {
Upload up = mPending.get(localUploadId);
if (up != null)
return up;
}
}
// the first half of the upload id is the server id where it lives
Server server = Provisioning.getInstance().get(Key.ServerBy.id, getUploadServerId(uploadId));
String url = AccountUtil.getBaseUri(server);
if (url == null)
return null;
String hostname = server.getServiceHostname();
url += ContentServlet.SERVLET_PATH + ContentServlet.PREFIX_PROXY + '?' + ContentServlet.PARAM_UPLOAD_ID + '=' + uploadId + '&' + ContentServlet.PARAM_EXPUNGE + "=true";
// create an HTTP client with auth cookie to fetch the file from the remote ContentServlet
HttpClient client = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
GetMethod get = new GetMethod(url);
authtoken.encode(client, get, false, hostname);
try {
// fetch the remote item
int statusCode = HttpClientUtil.executeMethod(client, get);
if (statusCode != HttpStatus.SC_OK)
return null;
// metadata is encoded in the response's HTTP headers
Header ctHeader = get.getResponseHeader("Content-Type");
String contentType = ctHeader == null ? "text/plain" : ctHeader.getValue();
Header cdispHeader = get.getResponseHeader("Content-Disposition");
String filename = cdispHeader == null ? "unknown" : new ContentDisposition(cdispHeader.getValue()).getParameter("filename");
// store the fetched upload along with original uploadId
Upload up = saveUpload(get.getResponseBodyAsStream(), filename, contentType, accountId);
synchronized (mProxiedUploadIds) {
mProxiedUploadIds.put(uploadId, up.uuid);
}
return up;
} catch (HttpException e) {
throw ServiceException.PROXY_ERROR(e, url);
} catch (IOException e) {
throw ServiceException.RESOURCE_UNREACHABLE("can't fetch remote upload", e, new InternalArgument(ServiceException.URL, url, Argument.Type.STR));
} finally {
get.releaseConnection();
}
}
Aggregations