Search in sources :

Example 1 with HttpInputStream

use of org.parosproxy.paros.network.HttpInputStream in project zaproxy by zaproxy.

the class ProxyThread method beginSSL.

/**
	 * @param targethost the host where you want to connect to
	 * @throws IOException if an error occurred while establishing the SSL/TLS connection
	 */
private void beginSSL(String targethost) throws IOException {
    // ZAP: added parameter 'targethost'
    try {
        inSocket = HttpSender.getSSLConnector().createTunnelServerSocket(targethost, inSocket);
    } catch (MissingRootCertificateException e) {
        // throw again, cause will be catched later.
        throw new MissingRootCertificateException(e);
    } catch (Exception e) {
        // ZAP: transform for further processing 
        throw new IOException("Error while establishing SSL connection for '" + targethost + "'!", e);
    }
    httpIn = new HttpInputStream(inSocket);
    httpOut = new HttpOutputStream(inSocket.getOutputStream());
}
Also used : MissingRootCertificateException(org.parosproxy.paros.security.MissingRootCertificateException) HttpOutputStream(org.parosproxy.paros.network.HttpOutputStream) IOException(java.io.IOException) HttpInputStream(org.parosproxy.paros.network.HttpInputStream) HttpMalformedHeaderException(org.parosproxy.paros.network.HttpMalformedHeaderException) SocketException(java.net.SocketException) SocketTimeoutException(java.net.SocketTimeoutException) HttpException(org.apache.commons.httpclient.HttpException) MissingRootCertificateException(org.parosproxy.paros.security.MissingRootCertificateException) IOException(java.io.IOException) SSLException(javax.net.ssl.SSLException)

Example 2 with HttpInputStream

use of org.parosproxy.paros.network.HttpInputStream in project zaproxy by zaproxy.

the class API method handleApiRequest.

public boolean handleApiRequest(HttpRequestHeader requestHeader, HttpInputStream httpIn, HttpOutputStream httpOut, boolean force) throws IOException {
    String url = requestHeader.getURI().toString();
    Format format = Format.OTHER;
    ApiImplementor callbackImpl = null;
    ApiImplementor shortcutImpl = null;
    // Check for callbacks
    if (url.contains(CALL_BACK_URL)) {
        if (!isPermittedAddr(requestHeader)) {
            return true;
        }
        logger.debug("handleApiRequest Callback: " + url);
        for (Entry<String, ApiImplementor> callback : callBacks.entrySet()) {
            if (url.startsWith(callback.getKey())) {
                callbackImpl = callback.getValue();
                break;
            }
        }
    }
    String path = requestHeader.getURI().getPath();
    if (path != null) {
        for (Entry<String, ApiImplementor> shortcut : shortcuts.entrySet()) {
            if (path.startsWith(shortcut.getKey())) {
                shortcutImpl = shortcut.getValue();
                break;
            }
        }
    }
    if (shortcutImpl == null && callbackImpl == null && !url.startsWith(API_URL) && !url.startsWith(API_URL_S) && !force) {
        return false;
    }
    if (!isPermittedAddr(requestHeader)) {
        return true;
    }
    if (getOptionsParamApi().isSecureOnly() && !requestHeader.isSecure()) {
        // Insecure request with secure only set, always ignore
        logger.debug("handleApiRequest rejecting insecure request");
        return true;
    }
    logger.debug("handleApiRequest " + url);
    HttpMessage msg = new HttpMessage();
    msg.setRequestHeader(requestHeader);
    if (requestHeader.getContentLength() > 0) {
        msg.setRequestBody(httpIn.readRequestBody(requestHeader));
    }
    String component = null;
    ApiImplementor impl = null;
    RequestType reqType = null;
    String contentType = "text/plain; charset=UTF-8";
    String response = "";
    String name = null;
    boolean error = false;
    try {
        JSONObject params = getParams(requestHeader.getURI().getEscapedQuery());
        if (shortcutImpl != null) {
            if (!getOptionsParamApi().isDisableKey() && !getOptionsParamApi().isNoKeyForSafeOps()) {
                if (!this.hasValidKey(requestHeader, params)) {
                    throw new ApiException(ApiException.Type.BAD_API_KEY);
                }
            }
            msg = shortcutImpl.handleShortcut(msg);
        } else if (callbackImpl != null) {
            // Callbacks have suitably random URLs and therefore don't require keys/nonces
            response = callbackImpl.handleCallBack(msg);
        } else {
            // Parse the query:
            // format of url is http://zap/format/component/reqtype/name/?params
            //                    0  1  2    3        4        5      6
            String[] elements = url.split("/");
            if (elements.length > 3 && elements[3].equalsIgnoreCase("favicon.ico")) {
                // Treat the favicon as a special case:)
                if (!getOptionsParamApi().isUiEnabled()) {
                    throw new ApiException(ApiException.Type.DISABLED);
                }
                InputStream is = API.class.getResourceAsStream("/resource/zap.ico");
                byte[] icon = new byte[is.available()];
                is.read(icon);
                is.close();
                msg.setResponseHeader(getDefaultResponseHeader(contentType));
                msg.getResponseHeader().setContentLength(icon.length);
                httpOut.write(msg.getResponseHeader());
                httpOut.write(icon);
                httpOut.flush();
                httpOut.close();
                httpIn.close();
                return true;
            } else if (elements.length > 3) {
                try {
                    format = Format.valueOf(elements[3].toUpperCase());
                    switch(format) {
                        case JSON:
                            contentType = "application/json; charset=UTF-8";
                            break;
                        case JSONP:
                            contentType = "application/javascript; charset=UTF-8";
                            break;
                        case XML:
                            contentType = "text/xml; charset=UTF-8";
                            break;
                        case HTML:
                            contentType = "text/html; charset=UTF-8";
                            break;
                        case UI:
                            contentType = "text/html; charset=UTF-8";
                            break;
                        default:
                            break;
                    }
                } catch (IllegalArgumentException e) {
                    format = Format.HTML;
                    throw new ApiException(ApiException.Type.BAD_FORMAT);
                }
            }
            if (elements.length > 4) {
                component = elements[4];
                impl = implementors.get(component);
                if (impl == null) {
                    throw new ApiException(ApiException.Type.NO_IMPLEMENTOR);
                }
            }
            if (elements.length > 5) {
                try {
                    reqType = RequestType.valueOf(elements[5]);
                } catch (IllegalArgumentException e) {
                    throw new ApiException(ApiException.Type.BAD_TYPE);
                }
            }
            if (elements.length > 6) {
                name = elements[6];
                if (name != null && name.indexOf("?") > 0) {
                    name = name.substring(0, name.indexOf("?"));
                }
            }
            if (format.equals(Format.UI)) {
                if (!isEnabled() || !getOptionsParamApi().isUiEnabled()) {
                    throw new ApiException(ApiException.Type.DISABLED);
                }
                response = webUI.handleRequest(component, impl, reqType, name);
                contentType = "text/html; charset=UTF-8";
            } else if (name != null) {
                if (!isEnabled()) {
                    throw new ApiException(ApiException.Type.DISABLED);
                }
                // Do this now as it might contain the api key/nonce
                if (requestHeader.getMethod().equalsIgnoreCase(HttpRequestHeader.POST)) {
                    String contentTypeHeader = requestHeader.getHeader(HttpHeader.CONTENT_TYPE);
                    if (contentTypeHeader != null && contentTypeHeader.equals(HttpHeader.FORM_URLENCODED_CONTENT_TYPE)) {
                        params = getParams(msg.getRequestBody().toString());
                    } else {
                        throw new ApiException(ApiException.Type.CONTENT_TYPE_NOT_SUPPORTED);
                    }
                }
                if (format.equals(Format.JSONP)) {
                    if (!getOptionsParamApi().isEnableJSONP()) {
                        // Not enabled
                        throw new ApiException(ApiException.Type.DISABLED);
                    }
                    if (!this.hasValidKey(requestHeader, params)) {
                        // An api key is required for ALL JSONP requests
                        throw new ApiException(ApiException.Type.BAD_API_KEY);
                    }
                }
                ApiResponse res;
                switch(reqType) {
                    case action:
                        if (!getOptionsParamApi().isDisableKey()) {
                            if (!this.hasValidKey(requestHeader, params)) {
                                throw new ApiException(ApiException.Type.BAD_API_KEY);
                            }
                        }
                        ApiAction action = impl.getApiAction(name);
                        if (action != null) {
                            // Checking for null to handle option actions
                            List<String> mandatoryParams = action.getMandatoryParamNames();
                            if (mandatoryParams != null) {
                                for (String param : mandatoryParams) {
                                    if (!params.has(param) || params.getString(param).length() == 0) {
                                        throw new ApiException(ApiException.Type.MISSING_PARAMETER, param);
                                    }
                                }
                            }
                        }
                        res = impl.handleApiOptionAction(name, params);
                        if (res == null) {
                            res = impl.handleApiAction(name, params);
                        }
                        switch(format) {
                            case JSON:
                                response = res.toJSON().toString();
                                break;
                            case JSONP:
                                response = this.getJsonpWrapper(res.toJSON().toString());
                                break;
                            case XML:
                                response = this.responseToXml(name, res);
                                break;
                            case HTML:
                                response = this.responseToHtml(name, res);
                                break;
                            default:
                                break;
                        }
                        break;
                    case view:
                        if (!getOptionsParamApi().isDisableKey() && !getOptionsParamApi().isNoKeyForSafeOps()) {
                            if (!this.hasValidKey(requestHeader, params)) {
                                throw new ApiException(ApiException.Type.BAD_API_KEY);
                            }
                        }
                        ApiView view = impl.getApiView(name);
                        if (view != null) {
                            // Checking for null to handle option actions
                            List<String> mandatoryParams = view.getMandatoryParamNames();
                            if (mandatoryParams != null) {
                                for (String param : mandatoryParams) {
                                    if (!params.has(param) || params.getString(param).length() == 0) {
                                        throw new ApiException(ApiException.Type.MISSING_PARAMETER, param);
                                    }
                                }
                            }
                        }
                        res = impl.handleApiOptionView(name, params);
                        if (res == null) {
                            res = impl.handleApiView(name, params);
                        }
                        switch(format) {
                            case JSON:
                                response = res.toJSON().toString();
                                break;
                            case JSONP:
                                response = this.getJsonpWrapper(res.toJSON().toString());
                                break;
                            case XML:
                                response = this.responseToXml(name, res);
                                break;
                            case HTML:
                                response = this.responseToHtml(name, res);
                                break;
                            default:
                                break;
                        }
                        break;
                    case other:
                        ApiOther other = impl.getApiOther(name);
                        if (other != null) {
                            // Checking for null to handle option actions
                            if (!getOptionsParamApi().isDisableKey() && (!getOptionsParamApi().isNoKeyForSafeOps() || other.isRequiresApiKey())) {
                                // Check if a valid api key has been used
                                if (!this.hasValidKey(requestHeader, params)) {
                                    throw new ApiException(ApiException.Type.BAD_API_KEY);
                                }
                            }
                            List<String> mandatoryParams = other.getMandatoryParamNames();
                            if (mandatoryParams != null) {
                                for (String param : mandatoryParams) {
                                    if (!params.has(param) || params.getString(param).length() == 0) {
                                        throw new ApiException(ApiException.Type.MISSING_PARAMETER, param);
                                    }
                                }
                            }
                        }
                        msg = impl.handleApiOther(msg, name, params);
                }
            } else {
                // Handle default front page, unless if the API UI is disabled
                if (!isEnabled() || !getOptionsParamApi().isUiEnabled()) {
                    throw new ApiException(ApiException.Type.DISABLED);
                }
                response = webUI.handleRequest(requestHeader.getURI(), this.isEnabled());
                format = Format.UI;
                contentType = "text/html; charset=UTF-8";
            }
        }
        logger.debug("handleApiRequest returning: " + response);
    } catch (Exception e) {
        if (!getOptionsParamApi().isReportPermErrors()) {
            if (e instanceof ApiException) {
                ApiException exception = (ApiException) e;
                if (exception.getType().equals(ApiException.Type.DISABLED) || exception.getType().equals(ApiException.Type.BAD_API_KEY)) {
                    // Fail silently
                    return true;
                }
            }
        }
        handleException(msg, format, contentType, e);
        error = true;
    }
    if (!error && !format.equals(Format.OTHER) && shortcutImpl == null) {
        msg.setResponseHeader(getDefaultResponseHeader(contentType));
        msg.setResponseBody(response);
        msg.getResponseHeader().setContentLength(msg.getResponseBody().length());
    }
    if (impl != null) {
        impl.addCustomHeaders(name, reqType, msg);
    }
    httpOut.write(msg.getResponseHeader());
    httpOut.write(msg.getResponseBody().getBytes());
    httpOut.flush();
    httpOut.close();
    httpIn.close();
    return true;
}
Also used : HttpInputStream(org.parosproxy.paros.network.HttpInputStream) InputStream(java.io.InputStream) URIException(org.apache.commons.httpclient.URIException) HttpMalformedHeaderException(org.parosproxy.paros.network.HttpMalformedHeaderException) IOException(java.io.IOException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) JSONObject(net.sf.json.JSONObject) HttpMessage(org.parosproxy.paros.network.HttpMessage)

Example 3 with HttpInputStream

use of org.parosproxy.paros.network.HttpInputStream in project zaproxy by zaproxy.

the class ProxyThread method run.

@Override
public void run() {
    proxyThreadList.add(thread);
    boolean isSecure = this instanceof ProxyThreadSSL;
    HttpRequestHeader firstHeader = null;
    try {
        BufferedInputStream bufferedInputStream = new BufferedInputStream(inSocket.getInputStream(), 2048);
        inSocket = new CustomStreamsSocket(inSocket, bufferedInputStream, inSocket.getOutputStream());
        httpIn = new HttpInputStream(inSocket);
        httpOut = new HttpOutputStream(inSocket.getOutputStream());
        firstHeader = httpIn.readRequestHeader(isSecure);
        firstHeader.setSenderAddress(inSocket.getInetAddress());
        if (firstHeader.getMethod().equalsIgnoreCase(HttpRequestHeader.CONNECT)) {
            HttpMessage connectMsg = new HttpMessage(firstHeader);
            connectMsg.setTimeSentMillis(System.currentTimeMillis());
            try {
                httpOut.write(CONNECT_HTTP_200);
                httpOut.flush();
                connectMsg.setResponseHeader(CONNECT_HTTP_200);
                connectMsg.setTimeElapsedMillis((int) (System.currentTimeMillis() - connectMsg.getTimeSentMillis()));
                notifyConnectMessage(connectMsg);
                byte[] bytes = new byte[3];
                bufferedInputStream.mark(3);
                bufferedInputStream.read(bytes);
                bufferedInputStream.reset();
                if (isSslTlsHandshake(bytes)) {
                    isSecure = true;
                    beginSSL(firstHeader.getHostName());
                }
                firstHeader = httpIn.readRequestHeader(isSecure);
                firstHeader.setSenderAddress(inSocket.getInetAddress());
                processHttp(firstHeader, isSecure);
            } catch (MissingRootCertificateException e) {
                // Unluckily Firefox and Internet Explorer will not show this message.
                // We should find a way to let the browsers display this error message.
                // May we can redirect to some kind of ZAP custom error page.
                final HttpMessage errmsg = new HttpMessage(firstHeader);
                setErrorResponse(errmsg, BAD_GATEWAY_RESPONSE_STATUS, e, "ZAP SSL Error");
                writeHttpResponse(errmsg, httpOut);
                throw new IOException(e);
            }
        } else {
            processHttp(firstHeader, isSecure);
        }
    } catch (SocketTimeoutException e) {
        // ZAP: Log the exception
        if (firstHeader != null) {
            if (HttpRequestHeader.CONNECT.equalsIgnoreCase(firstHeader.getMethod())) {
                log.warn("Timeout reading (client) message after CONNECT to " + firstHeader.getURI());
            } else {
                log.warn("Timeout accessing " + firstHeader.getURI());
            }
        } else {
            log.warn("Socket timeout while reading first message.");
            if (log.isDebugEnabled()) {
                log.debug(e, e);
            }
        }
    } catch (HttpMalformedHeaderException e) {
        log.warn("Malformed Header: ", e);
    } catch (HttpException e) {
        log.error(e.getMessage(), e);
    } catch (IOException e) {
        log.debug("IOException: ", e);
    } finally {
        proxyThreadList.remove(thread);
        // ZAP: do only close if flag is false
        if (!keepSocketOpen) {
            disconnect();
        }
    }
}
Also used : HttpOutputStream(org.parosproxy.paros.network.HttpOutputStream) IOException(java.io.IOException) HttpRequestHeader(org.parosproxy.paros.network.HttpRequestHeader) MissingRootCertificateException(org.parosproxy.paros.security.MissingRootCertificateException) SocketTimeoutException(java.net.SocketTimeoutException) BufferedInputStream(java.io.BufferedInputStream) HttpMalformedHeaderException(org.parosproxy.paros.network.HttpMalformedHeaderException) HttpException(org.apache.commons.httpclient.HttpException) HttpInputStream(org.parosproxy.paros.network.HttpInputStream) HttpMessage(org.parosproxy.paros.network.HttpMessage)

Aggregations

IOException (java.io.IOException)3 HttpInputStream (org.parosproxy.paros.network.HttpInputStream)3 HttpMalformedHeaderException (org.parosproxy.paros.network.HttpMalformedHeaderException)3 SocketTimeoutException (java.net.SocketTimeoutException)2 HttpException (org.apache.commons.httpclient.HttpException)2 HttpMessage (org.parosproxy.paros.network.HttpMessage)2 HttpOutputStream (org.parosproxy.paros.network.HttpOutputStream)2 MissingRootCertificateException (org.parosproxy.paros.security.MissingRootCertificateException)2 BufferedInputStream (java.io.BufferedInputStream)1 InputStream (java.io.InputStream)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 SocketException (java.net.SocketException)1 SSLException (javax.net.ssl.SSLException)1 JSONObject (net.sf.json.JSONObject)1 URIException (org.apache.commons.httpclient.URIException)1 HttpRequestHeader (org.parosproxy.paros.network.HttpRequestHeader)1