com.zimbra.qa.unittest.TestFileUpload.java Source code

Java tutorial

Introduction

Here is the source code for com.zimbra.qa.unittest.TestFileUpload.java

Source

/*
 * ***** BEGIN LICENSE BLOCK *****
 * Zimbra Collaboration Suite Server
 * Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Synacor, Inc.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software Foundation,
 * version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with this program.
 * If not, see <https://www.gnu.org/licenses/>.
 * ***** END LICENSE BLOCK *****
 */
package com.zimbra.qa.unittest;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;

import org.apache.commons.httpclient.HeaderElement;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;
import org.junit.Test;

import com.zimbra.client.ZMailbox;
import com.zimbra.common.httpclient.HttpClientUtil;
import com.zimbra.common.localconfig.LC;
import com.zimbra.common.service.ServiceException;
import com.zimbra.common.soap.Element;
import com.zimbra.common.soap.SoapHttpTransport;
import com.zimbra.common.soap.SoapProtocol;
import com.zimbra.common.util.Constants;
import com.zimbra.common.util.ZimbraCookie;
import com.zimbra.common.util.ZimbraHttpConnectionManager;
import com.zimbra.common.util.ZimbraLog;
import com.zimbra.cs.account.Provisioning;
import com.zimbra.soap.JaxbUtil;

public class TestFileUpload extends TestCase {

    private static final String USER_NAME = "user1";
    private static final String NAME_PREFIX = TestFileUpload.class.getSimpleName();
    private static final String FILE_NAME = "my_zimlet.zip";
    private static String RESP_STR = "window.parent._uploadManager.loaded";
    private static String ADMIN_UPLOAD_URL = "/service/upload";

    public void setUp() throws Exception {
        cleanUp();
    }

    public void testUnauthorizedExtended() throws Exception {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        String uriString = mbox.getUploadURI().toString().replace("fmt=raw", "fmt=extended");
        URI uri = new URI(uriString);
        String responseContent = postAndVerify(mbox, uri, true);
        assertTrue(responseContent, responseContent.contains("401,"));
    }

    public void testUnauthorizedRaw() throws Exception {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        URI uri = mbox.getUploadURI();
        String responseContent = postAndVerify(mbox, uri, true);
        assertTrue(responseContent, responseContent.startsWith("401,"));
    }

    public void testRaw() throws Exception {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        URI uri = mbox.getUploadURI();
        String responseContent = postAndVerify(mbox, uri, false);
        assertTrue(responseContent, responseContent.startsWith("200,"));
    }

    public void testRawEmpty() throws Exception {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        URI uri = mbox.getUploadURI();
        String responseContent = postAndVerify(mbox, uri, false, "rawEmpty", null);
        assertTrue(responseContent, responseContent.startsWith("204,"));
    }

    @Test
    public void testAdminUploadWithCsrfInHeader() throws Exception {
        SoapHttpTransport transport = new SoapHttpTransport(TestUtil.getAdminSoapUrl());
        com.zimbra.soap.admin.message.AuthRequest req = new com.zimbra.soap.admin.message.AuthRequest(
                LC.zimbra_ldap_user.value(), LC.zimbra_ldap_password.value());
        req.setCsrfSupported(true);
        Element response = transport.invoke(JaxbUtil.jaxbToElement(req, SoapProtocol.SoapJS.getFactory()));
        com.zimbra.soap.admin.message.AuthResponse authResp = JaxbUtil.elementToJaxb(response);
        String authToken = authResp.getAuthToken();
        String csrfToken = authResp.getCsrfToken();
        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 Url = "https://localhost:" + port + ADMIN_UPLOAD_URL;
        PostMethod post = new PostMethod(Url);
        FilePart part = new FilePart(FILE_NAME, new ByteArrayPartSource(FILE_NAME, "some file content".getBytes()));
        String contentType = "application/x-msdownload";
        part.setContentType(contentType);
        HttpClient client = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
        HttpState state = new HttpState();
        state.addCookie(new org.apache.commons.httpclient.Cookie("localhost",
                ZimbraCookie.authTokenCookieName(true), authToken, "/", null, false));
        client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
        client.setState(state);
        post.setRequestEntity(new MultipartRequestEntity(new Part[] { part }, post.getParams()));
        post.addRequestHeader(Constants.CSRF_TOKEN, csrfToken);
        int statusCode = HttpClientUtil.executeMethod(client, post);
        assertEquals("This request should succeed. Getting status code " + statusCode, HttpStatus.SC_OK,
                statusCode);
        String resp = post.getResponseBodyAsString();
        assertNotNull("Response should not be empty", resp);
        assertTrue("Incorrect HTML response", resp.contains(RESP_STR));
    }

    @Test
    public void testMissingCsrfAdminUpload() throws Exception {
        SoapHttpTransport transport = new SoapHttpTransport(TestUtil.getAdminSoapUrl());
        com.zimbra.soap.admin.message.AuthRequest req = new com.zimbra.soap.admin.message.AuthRequest(
                LC.zimbra_ldap_user.value(), LC.zimbra_ldap_password.value());
        req.setCsrfSupported(true);
        Element response = transport.invoke(JaxbUtil.jaxbToElement(req, SoapProtocol.SoapJS.getFactory()));
        com.zimbra.soap.admin.message.AuthResponse authResp = JaxbUtil.elementToJaxb(response);
        String authToken = authResp.getAuthToken();
        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 Url = "https://localhost:" + port + ADMIN_UPLOAD_URL;
        PostMethod post = new PostMethod(Url);
        FilePart part = new FilePart(FILE_NAME, new ByteArrayPartSource(FILE_NAME, "some file content".getBytes()));
        String contentType = "application/x-msdownload";
        part.setContentType(contentType);
        HttpClient client = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
        HttpState state = new HttpState();
        state.addCookie(new org.apache.commons.httpclient.Cookie("localhost",
                ZimbraCookie.authTokenCookieName(true), authToken, "/", null, false));
        client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
        client.setState(state);
        post.setRequestEntity(new MultipartRequestEntity(new Part[] { part }, post.getParams()));
        int statusCode = HttpClientUtil.executeMethod(client, post);
        assertEquals("This request should succeed. Getting status code " + statusCode, HttpStatus.SC_OK,
                statusCode);
        String resp = post.getResponseBodyAsString();
        assertNotNull("Response should not be empty", resp);
        assertTrue("Incorrect HTML response", resp.contains(RESP_STR));
    }

    @Test
    public void testAdminUploadWithCsrfInFormField() throws Exception {
        SoapHttpTransport transport = new SoapHttpTransport(TestUtil.getAdminSoapUrl());
        com.zimbra.soap.admin.message.AuthRequest req = new com.zimbra.soap.admin.message.AuthRequest(
                LC.zimbra_ldap_user.value(), LC.zimbra_ldap_password.value());
        req.setCsrfSupported(true);
        Element response = transport.invoke(JaxbUtil.jaxbToElement(req, SoapProtocol.SoapJS.getFactory()));
        com.zimbra.soap.admin.message.AuthResponse authResp = JaxbUtil.elementToJaxb(response);
        String authToken = authResp.getAuthToken();
        String csrfToken = authResp.getCsrfToken();
        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 Url = "https://localhost:" + port + ADMIN_UPLOAD_URL;
        PostMethod post = new PostMethod(Url);
        FilePart part = new FilePart(FILE_NAME, new ByteArrayPartSource(FILE_NAME, "some file content".getBytes()));
        Part csrfPart = new StringPart("csrfToken", csrfToken);
        String contentType = "application/x-msdownload";
        part.setContentType(contentType);
        HttpClient client = ZimbraHttpConnectionManager.getInternalHttpConnMgr().newHttpClient();
        HttpState state = new HttpState();
        state.addCookie(new org.apache.commons.httpclient.Cookie("localhost",
                ZimbraCookie.authTokenCookieName(true), authToken, "/", null, false));
        client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
        client.setState(state);
        post.setRequestEntity(new MultipartRequestEntity(new Part[] { part, csrfPart }, post.getParams()));
        int statusCode = HttpClientUtil.executeMethod(client, post);
        assertEquals("This request should succeed. Getting status code " + statusCode, HttpStatus.SC_OK,
                statusCode);
        String resp = post.getResponseBodyAsString();
        assertNotNull("Response should not be empty", resp);
        assertTrue("Incorrect HTML response", resp.contains(RESP_STR));
    }

    /**
     * Confirms that <tt>requestId</tt> parameter values are restricted as desired.
     * See bug 99914 and bug 40377.
     * @throws Exception
     */
    public void testRequestIdScript() throws Exception {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        URI uri = mbox.getUploadURI();
        String responseContent = postAndVerify(mbox, uri, false, "<script></script>", "anything");
        assertFalse("Response does not contain 'script': " + responseContent, responseContent.contains("script"));
        assertTrue(responseContent, responseContent.startsWith("400,"));
    }

    public void testRequestIdAlert() throws Exception {
        ZMailbox mbox = TestUtil.getZMailbox(USER_NAME);
        URI uri = mbox.getUploadURI();
        String responseContent = postAndVerify(mbox, uri, false, "alert(1)", null);
        assertFalse("Response does not contain 'alert': " + responseContent, responseContent.contains("alert"));
        assertTrue(responseContent, responseContent.startsWith("400,"));
    }

    private String postAndVerify(ZMailbox mbox, URI uri, boolean clearCookies) throws IOException {
        return postAndVerify(mbox, uri, clearCookies, "myReqId", "some data");
    }

    private String postAndVerify(ZMailbox mbox, URI uri, boolean clearCookies, String requestId, String attContent)
            throws IOException {
        HttpClient client = mbox.getHttpClient(uri);
        if (clearCookies) {
            client.getState().clearCookies();
        }

        List<Part> parts = new ArrayList<Part>();
        parts.add(new StringPart("requestId", requestId));
        if (attContent != null) {
            parts.add(mbox.createAttachmentPart("test.txt", attContent.getBytes()));
        }

        PostMethod post = new PostMethod(uri.toString());
        post.setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[parts.size()]), post.getParams()));
        int status = HttpClientUtil.executeMethod(client, post);
        assertEquals(200, status);

        String contentType = getHeaderValue(post, "Content-Type");
        assertTrue(contentType, contentType.startsWith("text/html"));
        String content = post.getResponseBodyAsString();
        post.releaseConnection();
        return content;
    }

    private String getHeaderValue(HttpMethod method, String name) {
        HeaderElement[] header = method.getResponseHeader(name).getElements();
        String value = null;
        if (header.length > 0) {
            value = header[0].getName();
        }
        return value;
    }

    public void tearDown() throws Exception {
        cleanUp();
    }

    private void cleanUp() throws Exception {
        TestUtil.deleteTestData(USER_NAME, NAME_PREFIX);
    }

    public static void main(String[] args) throws Exception {
        TestUtil.cliSetup();
        TestUtil.runTest(TestFileUpload.class);
    }
}