Java tutorial
/* * 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 org.apache.wookie.proxy; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLDecoder; import java.util.Properties; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.configuration.Configuration; import org.apache.commons.httpclient.auth.AuthenticationException; import org.apache.log4j.Logger; import org.apache.wookie.beans.IAccessRequest; import org.apache.wookie.beans.IWidgetInstance; import org.apache.wookie.beans.IWhitelist; import org.apache.wookie.beans.IWidget; import org.apache.wookie.beans.util.IPersistenceManager; import org.apache.wookie.beans.util.PersistenceManagerFactory; /** * A web proxy servlet which will translate calls for content and return them as if they came from * this domain */ public class ProxyServlet extends HttpServlet implements Servlet { private static final long serialVersionUID = 1L; public static final String UNAUTHORISED_MESSAGE = "Unauthorised"; static Logger fLogger = Logger.getLogger(ProxyServlet.class.getName()); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { dealWithRequest(request, response, "post"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { dealWithRequest(request, response, "get"); } /** * Check the validity of a proxy request, and execute it if it checks out * @param request * @param response * @param httpMethod * @throws ServletException */ private void dealWithRequest(HttpServletRequest request, HttpServletResponse response, String httpMethod) throws ServletException { try { // Properties systemProperties = System.getProperties(); // systemProperties.setProperty("http.proxyHost", "wwwcache.open.ac.uk"); // systemProperties.setProperty("http.proxyPort", "80"); Configuration properties = (Configuration) request.getSession().getServletContext() .getAttribute("properties"); // System.out.println("properties"); // properties.addProperty("http.proxyHost", "wwwcache.open.ac.uk"); // properties.addProperty("http.proxyPort", "80"); // systemProperties.setProperty("http.proxyHost", "wwwcache.open.ac.uk"); // systemProperties.setProperty("http.proxyPort", "80"); //System.out.println("$$$ 1"); // Check that the request is coming from the same domain (i.e. from a widget served by this server) if (properties.getBoolean("widget.proxy.checkdomain") && !isSameDomain(request)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "<error>" + UNAUTHORISED_MESSAGE + "</error>"); return; } //System.out.println("$$$ 2"); // Check that the request is coming from a valid widget IPersistenceManager persistenceManager = PersistenceManagerFactory.getPersistenceManager(); IWidgetInstance instance = persistenceManager .findWidgetInstanceByIdKey(request.getParameter("instanceid_key")); if (instance == null && !isDefaultGadget(request)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "<error>" + UNAUTHORISED_MESSAGE + "</error>"); return; } //System.out.println("$$$ 3"); // Create the proxy bean for the request ProxyURLBean bean; try { bean = new ProxyURLBean(request); } catch (MalformedURLException e) { response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); return; } //System.out.println("$$$ 4"); // should we filter urls? if (properties.getBoolean("widget.proxy.usewhitelist") && !isAllowed(bean.getNewUrl().toURI(), instance)) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "<error>URL Blocked</error>"); fLogger.warn("URL " + bean.getNewUrl().toExternalForm() + " Blocked"); return; } //System.out.println("$$$ 5"); ProxyClient proxyclient = new ProxyClient(request); PrintWriter out = response.getWriter(); //System.out.println("$$$ 6"); //TODO - find all the links etc & make them absolute - to make request come thru this servlet String output = ""; if (httpMethod.equals("get")) { output = proxyclient.get(bean.getNewUrl().toExternalForm(), properties); } else { output = proxyclient.post(bean.getNewUrl().toExternalForm(), getXmlData(request), properties); } response.setContentType(proxyclient.getCType()); out.print(output); } catch (Exception ex) { try { if (ex instanceof AuthenticationException) { response.sendError(HttpServletResponse.SC_UNAUTHORIZED); } else { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage()); } fLogger.error(ex.getMessage()); } catch (IOException e) { // give up! fLogger.error(ex.getMessage()); throw new ServletException(e); } } } /** * Gets the content of the request * @param request * @return * @throws IOException */ private String getXmlData(HttpServletRequest request) throws IOException { // Note that we cannot use a Reader for this as we already // call getParameter() which works on an InputStream - and you // can only use an InputStream OR a Reader, not both. byte[] b = new byte[request.getContentLength()]; request.getInputStream().read(b, 0, request.getContentLength()); String xml = new String(b); return xml; } /** * Checks that the request is from the same domain as this service * @param request * @param checkDomain * @return */ private boolean isSameDomain(HttpServletRequest request) { String remoteHost = request.getRemoteHost(); String serverHost = request.getServerName(); if (remoteHost.equals(serverHost)) { return true; } return false; } private boolean isDefaultGadget(HttpServletRequest request) { String instanceId = request.getParameter("instanceid_key"); // check if the default Shindig gadget key is being used Configuration properties = (Configuration) request.getSession().getServletContext() .getAttribute("opensocial"); if (properties.getBoolean("opensocial.enable") && properties.getString("opensocial.proxy.id").equals(instanceId)) { return true; } return false; } /** * Check to see if a given url appears in the whitelist * @param aUrl * @return */ public boolean isAllowed(URI requestedUri, IWidgetInstance instance) { // Check global whitelist IPersistenceManager persistenceManager = PersistenceManagerFactory.getPersistenceManager(); for (IWhitelist whiteList : persistenceManager.findAll(IWhitelist.class)) { // TODO - make this better then just comparing the beginning... if (requestedUri.toString().toLowerCase().startsWith(whiteList.getfUrl().toLowerCase())) { return true; } } // Check widget-specific policies using W3C WARP if (instance != null && isAllowedByPolicy(requestedUri, instance.getWidget())) { return true; } return false; } /** * Check widget-specific policies using W3C WARP * @param requestedUri the URI requested * @param widget the Widget requesting access to the URI * @return true if a policy grants access to the requested URI */ private boolean isAllowedByPolicy(URI requestedUri, IWidget widget) { IPersistenceManager persistenceManager = PersistenceManagerFactory.getPersistenceManager(); for (IAccessRequest policy : persistenceManager.findApplicableAccessRequests(widget)) { if (policy.isAllowed(requestedUri)) { return true; } } fLogger.warn("No policy grants widget " + widget.getWidgetTitle("en") + " access to: " + requestedUri.toString()); return false; } /** * * A class used to model a url both with and without a proxy address attached to it * */ private class ProxyURLBean { private URL fNewUrl; public ProxyURLBean(HttpServletRequest request) throws MalformedURLException, UnsupportedEncodingException { doParse(request); } private void doParse(HttpServletRequest request) throws MalformedURLException, UnsupportedEncodingException { URL proxiedEndPointURL = null; String endPointURL = null; // Try to find a "url" parameter from the QueryString of the request String file = request.getRequestURI(); if (request.getQueryString() != null) { file += '?' + request.getQueryString(); // build the requested path proxiedEndPointURL = new URL(request.getScheme(), request.getServerName(), request.getServerPort(), file); // find where the url parameter is .. int idx = proxiedEndPointURL.toString().indexOf("url="); if (idx > -1) { // reconstruct the path to be proxied by removing the reference to this servlet endPointURL = proxiedEndPointURL.toString().substring(idx + 4, proxiedEndPointURL.toString().length()); // fix initial querystring component - this is a hack for JQuery support. See WOOKIE-118 for // more information about this. if (endPointURL.contains("&") && !endPointURL.contains("?")) { endPointURL = endPointURL.replaceFirst("&", "?"); } } } // try to locate a POST form parameter instead if (endPointURL == null) { endPointURL = request.getParameter("url"); } // the request didn't contain any params, so throw an exception if (endPointURL == null) { throw new MalformedURLException("Unable to obtain url from args"); } try { fNewUrl = new URL(endPointURL); } catch (Exception ex) { // try decoding the URL fNewUrl = new URL(URLDecoder.decode(endPointURL, "UTF-8")); } } public URL getNewUrl() { return fNewUrl; } } }