Search in sources :

Example 26 with HttpState

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;
    }
}
Also used : Account(com.zimbra.cs.account.Account) Options(com.zimbra.cs.dav.service.method.Options) Server(com.zimbra.cs.account.Server) Element(org.dom4j.Element) HttpState(org.apache.commons.httpclient.HttpState) Folder(com.zimbra.cs.mailbox.Folder) ZFolder(com.zimbra.client.ZFolder) Document(org.dom4j.Document) ItemId(com.zimbra.cs.service.util.ItemId) Provisioning(com.zimbra.cs.account.Provisioning) ZMailbox(com.zimbra.client.ZMailbox) Mailbox(com.zimbra.cs.mailbox.Mailbox) ZMailbox(com.zimbra.client.ZMailbox) ZFolder(com.zimbra.client.ZFolder) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) GZIPInputStream(java.util.zip.GZIPInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) XmlParseException(com.zimbra.common.soap.XmlParseException) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) ServiceException(com.zimbra.common.service.ServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) Header(org.apache.commons.httpclient.Header) HttpClient(org.apache.commons.httpclient.HttpClient) AuthToken(com.zimbra.cs.account.AuthToken) HttpMethod(org.apache.commons.httpclient.HttpMethod)

Example 27 with HttpState

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);
}
Also used : ZMailbox(com.zimbra.client.ZMailbox) HttpClient(org.apache.commons.httpclient.HttpClient) GetMethod(org.apache.commons.httpclient.methods.GetMethod) HttpState(org.apache.commons.httpclient.HttpState) AuthToken(com.zimbra.cs.account.AuthToken) ZAuthToken(com.zimbra.common.auth.ZAuthToken) ZimbraAuthToken(com.zimbra.cs.account.ZimbraAuthToken) URI(java.net.URI) ZAuthToken(com.zimbra.common.auth.ZAuthToken) Test(org.junit.Test)

Example 28 with HttpState

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);
}
Also used : ServiceException(com.zimbra.common.service.ServiceException) HttpClient(org.apache.commons.httpclient.HttpClient) HttpState(org.apache.commons.httpclient.HttpState) GetMethod(org.apache.commons.httpclient.methods.GetMethod) AuthToken(com.zimbra.cs.account.AuthToken) ZAuthToken(com.zimbra.common.auth.ZAuthToken) ZimbraAuthToken(com.zimbra.cs.account.ZimbraAuthToken) Test(org.junit.Test)

Example 29 with HttpState

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);
}
Also used : Cookie(org.apache.commons.httpclient.Cookie) Account(com.zimbra.cs.account.Account) ZMailbox(com.zimbra.client.ZMailbox) HttpClient(org.apache.commons.httpclient.HttpClient) HttpState(org.apache.commons.httpclient.HttpState) GetMethod(org.apache.commons.httpclient.methods.GetMethod) URI(java.net.URI) Test(org.junit.Test)

Example 30 with HttpState

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);
}
Also used : ZMailbox(com.zimbra.client.ZMailbox) HttpClient(org.apache.commons.httpclient.HttpClient) GetMethod(org.apache.commons.httpclient.methods.GetMethod) HttpState(org.apache.commons.httpclient.HttpState) AuthToken(com.zimbra.cs.account.AuthToken) ZAuthToken(com.zimbra.common.auth.ZAuthToken) ZimbraAuthToken(com.zimbra.cs.account.ZimbraAuthToken) URI(java.net.URI) ZAuthToken(com.zimbra.common.auth.ZAuthToken) Test(org.junit.Test)

Aggregations

HttpState (org.apache.commons.httpclient.HttpState)33 HttpClient (org.apache.commons.httpclient.HttpClient)25 GetMethod (org.apache.commons.httpclient.methods.GetMethod)18 Test (org.junit.Test)13 ServiceException (com.zimbra.common.service.ServiceException)9 ZAuthToken (com.zimbra.common.auth.ZAuthToken)8 URI (java.net.URI)8 Cookie (org.apache.commons.httpclient.Cookie)8 PostMethod (org.apache.commons.httpclient.methods.PostMethod)8 ZMailbox (com.zimbra.client.ZMailbox)7 AuthToken (com.zimbra.cs.account.AuthToken)7 UsernamePasswordCredentials (org.apache.commons.httpclient.UsernamePasswordCredentials)6 Account (com.zimbra.cs.account.Account)5 IOException (java.io.IOException)5 Map (java.util.Map)5 HttpMethod (org.apache.commons.httpclient.HttpMethod)5 Element (com.zimbra.common.soap.Element)4 SoapHttpTransport (com.zimbra.common.soap.SoapHttpTransport)4 ZimbraAuthToken (com.zimbra.cs.account.ZimbraAuthToken)4 ArrayList (java.util.ArrayList)4