/* * © Copyright IBM Corp. 2012 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.ibm.sbt.service.basic; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.CoreProtocolPNames; import com.ibm.commons.runtime.Context; import com.ibm.commons.runtime.RuntimeConstants; import com.ibm.commons.util.StringUtil; import com.ibm.sbt.service.core.handlers.ProxyHandler; import com.ibm.sbt.service.debug.ProxyDebugUtil; import com.ibm.sbt.services.client.ClientServicesException; import com.ibm.sbt.services.endpoints.Endpoint; import com.ibm.sbt.services.endpoints.EndpointFactory; import com.ibm.sbt.services.util.SSLUtil; /** * Basic proxy using an endpoint. * <p> * This proxy is using an endpoint name before the actual proxied URL and ensures that * the endpoint is defined for the current user. It also checks that the URL parameter is * the one defined by the endpoint.<br> * Finally, this proxy also ensures that the referer points to the the current server, thus * preventing pages without this referer to work. * </p> * @author Philippe Riand */ public class ProxyEndpointService extends ProxyService { protected Endpoint endpoint; protected String requestURI; public ProxyEndpointService() { } public Endpoint getEndpoint() { return endpoint; } protected String getProxyUrlPath() { return ProxyHandler.URL_PATH; } @Override protected boolean isHeaderAllowed(String headerName) throws ServletException { // Don't pass the basic authorization as this must be set by the endpoint if(StringUtil.equals(headerName,"Authorization")) { return false; } if(!(this.getEndpoint().isHeaderAllowed(headerName, requestURI))){ return false; } // And pass all the other headers return super.isHeaderAllowed(headerName); } @Override protected DefaultHttpClient getClient(HttpServletRequest request, int timeout) { DefaultHttpClient httpClient = super.getClient(request, timeout); if(endpoint!=null) { if(endpoint.isForceTrustSSLCertificate() && requestURI!=null) { httpClient = SSLUtil.wrapHttpClient(httpClient); } if (endpoint.isForceDisableExpectedContinue()) { httpClient.getParams().setParameter( CoreProtocolPNames.USE_EXPECT_CONTINUE, false); } String httpProxy = getHttpProxy(endpoint); if(StringUtil.isNotEmpty(httpProxy)) { httpClient = ProxyDebugUtil.wrapHttpClient(httpClient, httpProxy); } } return httpClient; } @Override protected void checkRequestAllowed(HttpServletRequest request) throws ServletException { if(!isRefererAllowed(request)) { throw new ServletException("Invalid request referer"); } super.checkRequestAllowed(request); } protected boolean isRefererAllowed(HttpServletRequest request) { // For now... return true; // String referer = request.getHeader("Referer"); // if(StringUtil.isNotEmpty(referer)) { // StringBuilder b = new StringBuilder(128); // b.append(request.getScheme()); // b.append("://"); // b.append(request.getServerName()); // int port = request.getServerPort(); // b.append(":"); // b.append(Integer.toString(port)); // b.append(request.getContextPath()); // b.append("/"); // String url = b.toString(); // if(referer.startsWith(url)) { // return true; // } // } // return false; } @Override protected boolean prepareForwardingMethod(HttpRequestBase method, HttpServletRequest request, DefaultHttpClient client) throws ServletException { boolean ret = super.prepareForwardingMethod(method, request, client); initEndpoint(method, request, client, endpoint); return ret; } @Override protected boolean forwardCookies(HttpRequestBase method, HttpServletRequest request) { return false; } protected void initEndpoint(HttpRequestBase method, HttpServletRequest request, DefaultHttpClient client, Endpoint endpoint) throws ServletException { try { endpoint.initialize(client); endpoint.updateHeaders(client, method); } catch(ClientServicesException ex) { throw new ServletException(ex); } } @Override protected void initProxy(HttpServletRequest request, HttpServletResponse response) throws ServletException { String pathInfo = request.getPathInfo(); // Skip the URL_PATH of the proxy // /[proxy root]/[URL_PATH]/[endpointname]/[full qualified url starting with http] // or // /[proxy root]/[URL_PATH]/[endpointname]/[service url] int startEndPoint = getProxyUrlPath().length() + 2; if (startEndPoint < pathInfo.length()) { int startProxyUrl = pathInfo.indexOf('/', startEndPoint); if (startProxyUrl >= 0) { String endPointName = pathInfo.substring(startEndPoint, startProxyUrl); this.endpoint = EndpointFactory.getEndpoint(endPointName); if (!endpoint.isAllowClientAccess()) { throw new ServletException(StringUtil.format( "Client access forbidden for the specified endpoint {0}", endPointName)); } String url = null; String endpointUrl = endpoint.getUrl(); if (pathInfo.substring(startProxyUrl+1).startsWith("http")) { url = pathInfo.substring(startProxyUrl+1).replaceAll(" ", "%20").replaceFirst("\\/", "://"); /* if (!url.startsWith(endpointUrl)) { throw new ServletException(StringUtil.format( "The proxied url does not correspond to the endpoint {0}", endPointName)); } */ } else { pathInfo = pathInfo.substring(startProxyUrl).replaceAll(" ", "%20"); url = endpointUrl + pathInfo; } requestURI = url; return; } } StringBuffer b = request.getRequestURL(); String q = request.getQueryString(); if (StringUtil.isNotEmpty(q)) { b.append('?'); b.append(q); } throw new ServletException(StringUtil.format("Invalid url {0}", b.toString())); } @Override protected String getRequestURIPath(HttpServletRequest request) throws ServletException { return requestURI; } public static String getProxyUrlForEndpoint(Context context, String proxyName, String endpointName, String url) { StringBuilder b = new StringBuilder(); RuntimeConstants.get().appendBaseProxyUrl(b,context); b.append("/"); b.append(proxyName); b.append("/"); b.append(endpointName); if(StringUtil.isNotEmpty(url)) { b.append("/"); String newUrl = url.replaceFirst("://","\\/"); b.append(newUrl); } String proxyUrl = b.toString(); return proxyUrl; } @Override protected String getRequestURLQueryString(HttpServletRequest request) throws ServletException { String queryargs = request.getQueryString(); String proxyqueryargs = endpoint.getProxyQueryArgs(); if (proxyqueryargs != null) { if (queryargs == null) return proxyqueryargs; else return queryargs + "&" + proxyqueryargs; } return queryargs; } /* * Return the HttpProxy value if configured */ private String getHttpProxy(Endpoint endpoint) { String httpProxy = endpoint.getHttpProxy(); if (StringUtil.isEmpty(httpProxy)) { httpProxy = Context.get().getProperty("sbt.httpProxy"); } return httpProxy; } }