use of org.apache.commons.httpclient.HttpState in project zm-mailbox by Zimbra.
the class DavServlet method isProxyRequest.
private boolean isProxyRequest(DavContext ctxt, DavMethod m) throws IOException, DavException, ServiceException {
Provisioning prov = Provisioning.getInstance();
ItemId target = null;
String extraPath = null;
String requestPath = ctxt.getPath();
try {
if (ctxt.getUser() == null) {
return false;
}
if (requestPath == null || requestPath.length() < 2) {
return false;
}
Account account = prov.getAccountByName(ctxt.getUser());
if (account == null) {
return false;
}
Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(account);
Pair<Folder, String> match = mbox.getFolderByPathLongestMatch(ctxt.getOperationContext(), Mailbox.ID_FOLDER_USER_ROOT, requestPath);
Folder targetFolder = match.getFirst();
if (!(targetFolder instanceof Mountpoint)) {
return false;
}
Mountpoint mp = (Mountpoint) targetFolder;
target = new ItemId(mp.getOwnerId(), mp.getRemoteId());
extraPath = match.getSecond();
} catch (ServiceException e) {
ZimbraLog.dav.debug("can't get path", e);
return false;
}
// we also don't proxy DELETE on a mountpoint.
if (extraPath == null && (m.getName().equals(PropFind.PROPFIND) && ctxt.getDepth() == DavContext.Depth.zero || m.getName().equals(PropPatch.PROPPATCH) || m.getName().equals(Delete.DELETE))) {
return false;
}
String prefix = ctxt.getPath();
if (extraPath != null) {
prefix = prefix.substring(0, prefix.indexOf(extraPath));
}
prefix = HttpUtil.urlEscape(DAV_PATH + "/" + ctxt.getUser() + prefix);
if (!prefix.endsWith("/")) {
prefix += "/";
}
// make sure the target account exists.
Account acct = prov.getAccountById(target.getAccountId());
if (acct == null) {
return false;
}
Server server = prov.getServer(acct);
if (server == null) {
return false;
}
// get the path to the target mail item
AuthToken authToken = AuthProvider.getAuthToken(ctxt.getAuthAccount());
ZMailbox.Options zoptions = new ZMailbox.Options(authToken.toZAuthToken(), AccountUtil.getSoapUri(acct));
zoptions.setNoSession(true);
zoptions.setTargetAccount(target.getAccountId());
zoptions.setTargetAccountBy(Key.AccountBy.id);
ZMailbox zmbx = ZMailbox.getMailbox(zoptions);
ZFolder f = zmbx.getFolderById("" + target.toString());
if (f == null) {
return false;
}
String path = f.getPath();
String newPrefix = HttpUtil.urlEscape(DAV_PATH + "/" + acct.getName() + f.getPath());
if (ctxt.hasRequestMessage()) {
// replace the path in <href> of the request with the path to the target mail item.
Document req = ctxt.getRequestMessage();
for (Object hrefObj : req.getRootElement().elements(DavElements.E_HREF)) {
if (!(hrefObj instanceof Element)) {
continue;
}
Element href = (Element) hrefObj;
String v = href.getText();
// prefix matching is not as straightforward as we have jetty redirect from /dav to /home/dav.
href.setText(newPrefix + "/" + v.substring(v.lastIndexOf('/') + 1));
}
}
// build proxy request
String url = getProxyUrl(ctxt.getRequest(), server, DAV_PATH) + HttpUtil.urlEscape("/" + acct.getName() + path + "/" + (extraPath == null ? "" : extraPath));
HttpState state = new HttpState();
authToken.encode(state, false, server.getAttr(Provisioning.A_zimbraServiceHostname));
HttpClient client = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
client.setState(state);
HttpMethod method = m.toHttpMethod(ctxt, url);
method.setRequestHeader(new Header(DavProtocol.HEADER_USER_AGENT, "Zimbra-DAV/" + BuildInfo.VERSION));
if (ZimbraLog.dav.isDebugEnabled()) {
Enumeration<String> headers = ctxt.getRequest().getHeaderNames();
while (headers.hasMoreElements()) {
String hdr = headers.nextElement();
if (!PROXY_REQUEST_HEADERS.contains(hdr) && !IGNORABLE_PROXY_REQUEST_HEADERS.contains(hdr)) {
ZimbraLog.dav.debug("Dropping header(s) with name [%s] from proxy request (not in PROXY_REQUEST_HEADERS)", hdr);
}
}
}
for (String h : PROXY_REQUEST_HEADERS) {
String hval = ctxt.getRequest().getHeader(h);
if (hval != null) {
method.addRequestHeader(h, hval);
}
}
int statusCode = HttpClientUtil.executeMethod(client, method);
if (ZimbraLog.dav.isDebugEnabled()) {
for (Header hval : method.getResponseHeaders()) {
String hdrName = hval.getName();
if (!PROXY_RESPONSE_HEADERS.contains(hdrName) && !IGNORABLE_PROXY_RESPONSE_HEADERS.contains(hdrName)) {
ZimbraLog.dav.debug("Dropping header [%s] from proxy response (not in PROXY_RESPONSE_HEADERS)", hval);
}
}
}
for (String h : PROXY_RESPONSE_HEADERS) {
for (Header hval : method.getResponseHeaders(h)) {
String hdrValue = hval.getValue();
if (DavProtocol.HEADER_LOCATION.equals(h)) {
int pfxLastSlashPos = prefix.lastIndexOf('/');
int lastSlashPos = hdrValue.lastIndexOf('/');
if ((lastSlashPos > 0) && (pfxLastSlashPos > 0)) {
hdrValue = prefix.substring(0, pfxLastSlashPos) + hdrValue.substring(lastSlashPos);
ZimbraLog.dav.debug("Original [%s] from proxy response new value '%s'", hval, hdrValue);
}
}
ctxt.getResponse().addHeader(h, hdrValue);
}
}
ctxt.getResponse().setStatus(statusCode);
ctxt.setStatus(statusCode);
try (InputStream in = method.getResponseBodyAsStream()) {
switch(statusCode) {
case DavProtocol.STATUS_MULTI_STATUS:
// rewrite the <href> element in the response to point to local mountpoint.
try {
Document response = W3cDomUtil.parseXMLToDom4jDocUsingSecureProcessing(in);
Element top = response.getRootElement();
for (Object responseObj : top.elements(DavElements.E_RESPONSE)) {
if (!(responseObj instanceof Element)) {
continue;
}
Element href = ((Element) responseObj).element(DavElements.E_HREF);
String v = href.getText();
v = URLDecoder.decode(v);
// Bug:106438, because v contains URL encoded value(%40) for '@' the comparison fails
if (v.startsWith(newPrefix)) {
href.setText(prefix + v.substring(newPrefix.length() + 1));
}
}
if (ZimbraLog.dav.isDebugEnabled()) {
ZimbraLog.dav.debug("PROXY RESPONSE:\n%s", new String(DomUtil.getBytes(response), "UTF-8"));
}
DomUtil.writeDocumentToStream(response, ctxt.getResponse().getOutputStream());
ctxt.responseSent();
} catch (XmlParseException e) {
ZimbraLog.dav.warn("proxy request failed", e);
return false;
}
break;
default:
if (in != null) {
ByteUtil.copy(in, true, ctxt.getResponse().getOutputStream(), false);
}
ctxt.responseSent();
break;
}
return true;
}
}
use of org.apache.commons.httpclient.HttpState in project zm-mailbox by Zimbra.
the class TestCookieReuse method testReuseUserCookieWithCsrf.
/**
* Verify that we CAN make a GET request by reusing a valid CSRF-enabled cookie
*/
@Test
public void testReuseUserCookieWithCsrf() throws Exception {
AuthToken at = AuthProvider.getAuthToken(TestUtil.getAccount(USER_NAME));
ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
URI uri = mbox.getRestURI("Inbox?fmt=rss&thief=true");
at.setCsrfTokenEnabled(true);
GetMethod get = new GetMethod(uri.toString());
HttpClient eve = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
HttpState state = HttpClientUtil.newHttpState(new ZAuthToken(at.getEncoded()), uri.getHost(), false);
eve.setState(state);
eve.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
int statusCode = HttpClientUtil.executeMethod(eve, get);
Assert.assertEquals("This request should succeed. Getting status code " + statusCode + " Response: " + get.getResponseBodyAsString(), HttpStatus.SC_OK, statusCode);
}
use of org.apache.commons.httpclient.HttpState in project zm-mailbox by Zimbra.
the class TestCookieReuse method testReuseAdminCookieWithoutCsrf.
/**
* Verify that we CAN make an admin GET request by re-using a valid non-csrf-enabled cookie
*/
@Test
public void testReuseAdminCookieWithoutCsrf() throws Exception {
AuthToken at = AuthProvider.getAdminAuthToken();
at.setCsrfTokenEnabled(false);
int port = 7071;
try {
port = Provisioning.getInstance().getLocalServer().getIntAttr(Provisioning.A_zimbraAdminPort, 0);
} catch (ServiceException e) {
ZimbraLog.test.error("Unable to get admin SOAP port", e);
}
String host = Provisioning.getInstance().getLocalServer().getName();
String getServerConfigURL = "https://localhost:" + port + "/service/collectconfig/?host=" + host;
HttpClient eve = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
HttpState state = new HttpState();
at.encode(state, true, "localhost");
eve.setState(state);
GetMethod get = new GetMethod(getServerConfigURL);
int statusCode = HttpClientUtil.executeMethod(eve, get);
Assert.assertEquals("This request should succeed. Getting status code " + statusCode, HttpStatus.SC_OK, statusCode);
}
use of org.apache.commons.httpclient.HttpState in project zm-mailbox by Zimbra.
the class TestCookieReuse method testWebLogOut.
/**
* Verify that we canNOT RE-use the cookie for REST session after logging out of plain HTML client
* @throws URISyntaxException
* @throws InterruptedException
*/
@Test
public void testWebLogOut() throws ServiceException, IOException, URISyntaxException, InterruptedException {
//establish legitimate connection
TestUtil.setAccountAttr(USER_NAME, Provisioning.A_zimbraForceClearCookies, "FALSE");
ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
URI uri = mbox.getRestURI("Inbox?fmt=rss");
HttpClient alice = mbox.getHttpClient(uri);
//create evesdropper's connection
HttpClient eve = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
Cookie[] cookies = alice.getState().getCookies();
HttpState state = new HttpState();
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
state.addCookie(new Cookie(uri.getHost(), cookie.getName(), cookie.getValue(), "/", null, false));
}
eve.setState(state);
Account a = TestUtil.getAccount(USER_NAME);
a.setForceClearCookies(false);
URI logoutUri = new URI(String.format("%s://%s%s/?loginOp=logout", uri.getScheme(), uri.getHost(), (uri.getPort() > 80 ? (":" + uri.getPort()) : "")));
GetMethod logoutMethod = new GetMethod(logoutUri.toString());
int statusCode = alice.executeMethod(logoutMethod);
Assert.assertEquals("Log out request should succeed. Getting status code " + statusCode, HttpStatus.SC_OK, statusCode);
GetMethod get = new GetMethod(uri.toString());
statusCode = HttpClientUtil.executeMethod(eve, get);
Assert.assertEquals("This request should not succeed. Getting status code " + statusCode, HttpStatus.SC_UNAUTHORIZED, statusCode);
}
use of org.apache.commons.httpclient.HttpState in project zm-mailbox by Zimbra.
the class TestCookieReuse method testReuseUserCookieWithoutCsrf.
/**
* Verify that we CAN make a GET request by reusing a valid non-csrf-enabled cookie
*/
@Test
public void testReuseUserCookieWithoutCsrf() throws Exception {
AuthToken at = AuthProvider.getAuthToken(TestUtil.getAccount(USER_NAME));
ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
URI uri = mbox.getRestURI("Inbox?fmt=rss&thief=false");
at.setCsrfTokenEnabled(false);
GetMethod get = new GetMethod(uri.toString());
HttpClient eve = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
HttpState state = HttpClientUtil.newHttpState(new ZAuthToken(at.getEncoded()), uri.getHost(), false);
eve.setState(state);
eve.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
int statusCode = HttpClientUtil.executeMethod(eve, get);
Assert.assertEquals("This request should succeed. Getting status code " + statusCode + " Response: " + get.getResponseBodyAsString(), HttpStatus.SC_OK, statusCode);
}
Aggregations