Commit c1bdea84 authored by Daryl Herzmann's avatar Daryl Herzmann Committed by akrherz

Add CORS headers to HTTP-Binding/BOSH OF-342


git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13272 b35dd754-fafc-0310-a699-88a17e54d16e
parent 327ff110
......@@ -23,6 +23,7 @@ package org.jivesoftware.openfire.http;
import java.io.File;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -67,6 +68,24 @@ public final class HttpBindManager {
public static final String HTTP_BIND_SECURE_PORT = "httpbind.port.secure";
public static final int HTTP_BIND_SECURE_PORT_DEFAULT = 7443;
// http binding CORS default properties
public static final String HTTP_BIND_CORS_ENABLED = "httpbind.CORS.enabled";
public static final boolean HTTP_BIND_CORS_ENABLED_DEFAULT = true;
public static final String HTTP_BIND_CORS_ALLOW_ORIGIN = "httpbind.CORS.domains";
public static final String HTTP_BIND_CORS_ALLOW_ORIGIN_DEFAULT = "*";
public static final String HTTP_BIND_CORS_ALLOW_METHODS_DEFAULT = "GET, POST, OPTIONS";
public static final String HTTP_BIND_CORS_ALLOW_HEADERS_DEFAULT = "Content-Type";
public static final String HTTP_BIND_CORS_MAX_AGE_DEFAULT = "86400";
public static Map<String, Boolean> HTTP_BIND_ALLOWED_ORIGINS = new HashMap<String, Boolean>();
private static HttpBindManager instance = new HttpBindManager();
......@@ -85,6 +104,9 @@ public final class HttpBindManager {
private ContextHandlerCollection contexts;
// is all orgin allowed flag
private boolean allowAllOrigins;
public static HttpBindManager getInstance() {
return instance;
}
......@@ -96,6 +118,9 @@ public final class HttpBindManager {
PropertyEventDispatcher.addListener(new HttpServerPropertyListener());
this.httpSessionManager = new HttpSessionManager();
contexts = new ContextHandlerCollection();
// setup the cache for the allowed origins
this.setupAllowedOriginsMap();
}
public void start() {
......@@ -242,7 +267,57 @@ public final class HttpBindManager {
public String getJavaScriptUrl() {
return "http://" + XMPPServer.getInstance().getServerInfo().getXMPPDomain() + ":" +
bindPort + "/scripts/";
}
// http binding CORS support start
private void setupAllowedOriginsMap() {
String originString = getCORSAllowOrigin();
if (originString.equals(HTTP_BIND_CORS_ALLOW_ORIGIN_DEFAULT)) {
allowAllOrigins = true;
} else {
allowAllOrigins = false;
String[] origins = originString.split(",");
// reset the cache
HTTP_BIND_ALLOWED_ORIGINS.clear();
for (String str : origins) {
HTTP_BIND_ALLOWED_ORIGINS.put(str, true);
}
}
}
public boolean isCORSEnabled() {
return JiveGlobals.getBooleanProperty(HTTP_BIND_CORS_ENABLED, HTTP_BIND_CORS_ENABLED_DEFAULT);
}
public void setCORSEnabled(Boolean value) {
if (value != null)
JiveGlobals.setProperty(HTTP_BIND_CORS_ENABLED, String.valueOf(value));
}
public String getCORSAllowOrigin() {
return JiveGlobals.getProperty(HTTP_BIND_CORS_ALLOW_ORIGIN , HTTP_BIND_CORS_ALLOW_ORIGIN_DEFAULT);
}
public void setCORSAllowOrigin(String origins) {
if (origins == null || origins.trim().isEmpty())
origins = HTTP_BIND_CORS_ALLOW_ORIGIN_DEFAULT;
else {
origins = origins.replaceAll("\\s+", "");
}
JiveGlobals.setProperty(HTTP_BIND_CORS_ALLOW_ORIGIN, origins);
setupAllowedOriginsMap();
}
public boolean isAllOriginsAllowed() {
return allowAllOrigins;
}
public boolean isThisOriginAllowed(String origin) {
return HTTP_BIND_ALLOWED_ORIGINS.get(origin) != null;
}
// http binding CORS support end
public void setHttpBindEnabled(boolean isEnabled) {
JiveGlobals.setProperty(HTTP_BIND_ENABLED, String.valueOf(isEnabled));
......
......@@ -96,6 +96,14 @@ public class HttpBindServlet extends HttpServlet {
sessionManager.stop();
}
@Override
protected void doOptions(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// Use HttpServlet's implementation to add basic headers ('Allow').
super.doOptions(request, response);
addCORSHeaders(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
......@@ -198,7 +206,7 @@ public class HttpBindServlet extends HttpServlet {
try {
if ((session.getMajorVersion() == 1 && session.getMinorVersion() >= 6) ||
session.getMajorVersion() > 1) {
respond(session, response, createErrorBody(bindingError.getErrorType().getType(),
respond(session, request, response, createErrorBody(bindingError.getErrorType().getType(),
bindingError.getCondition()), request.getMethod());
}
else {
......@@ -261,11 +269,11 @@ public class HttpBindServlet extends HttpServlet {
if ("terminate".equals(type)) {
session.close();
respond(session, response, createEmptyBody(), request.getMethod());
respond(session, request, response, createEmptyBody(), request.getMethod());
}
else if ("true".equals(restartStream) && rootNode.elements().size() == 0) {
try {
respond(session, response, createSessionRestartResponse(session), request.getMethod());
respond(session, request, response, createSessionRestartResponse(session), request.getMethod());
}
catch (DocumentException e) {
Log.error("Error sending session restart response to client.", e);
......@@ -273,7 +281,7 @@ public class HttpBindServlet extends HttpServlet {
}
else if (pauseDuration > 0 && pauseDuration <= session.getMaxPause()) {
session.pause(pauseDuration);
respond(session, response, createEmptyBody(), request.getMethod());
respond(session, request, response, createEmptyBody(), request.getMethod());
session.setLastResponseEmpty(true);
}
else {
......@@ -325,7 +333,7 @@ public class HttpBindServlet extends HttpServlet {
if (JiveGlobals.getBooleanProperty("log.httpbind.enabled", false)) {
System.out.println(new Date()+": HTTP RECV(" + connection.getSession().getStreamID().getID() + "): " + rootNode.asXML());
}
respond(response, connection, request.getMethod());
respond(request, response, connection, request.getMethod());
}
catch (UnauthorizedException e) {
// Server wasn't initialized yet.
......@@ -338,7 +346,8 @@ public class HttpBindServlet extends HttpServlet {
}
private void respond(HttpServletResponse response, HttpConnection connection, String method)
// add request argument
private void respond(HttpServletRequest request, HttpServletResponse response, HttpConnection connection, String method)
throws IOException
{
String content;
......@@ -350,10 +359,11 @@ public class HttpBindServlet extends HttpServlet {
connection.getSession().setLastResponseEmpty(true);
}
respond(connection.getSession(), response, content, method);
respond(connection.getSession(), request, response, content, method);
}
private void respond(HttpSession session, HttpServletResponse response, String content, String method)
// add request argument
private void respond(HttpSession session, HttpServletRequest request, HttpServletResponse response, String content, String method)
throws IOException {
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("GET".equals(method) ? "text/javascript" : "text/xml");
......@@ -368,6 +378,8 @@ public class HttpBindServlet extends HttpServlet {
}
content = "_BOSH_(\"" + StringEscapeUtils.escapeJavaScript(content) + "\")";
}
addCORSHeaders(request, response);
if (JiveGlobals.getBooleanProperty("log.httpbind.enabled", false)) {
System.out.println(new Date()+": HTTP SENT(" + session.getStreamID().getID() + "): " + content);
......@@ -378,6 +390,27 @@ public class HttpBindServlet extends HttpServlet {
response.getOutputStream().close();
}
private void addCORSHeaders(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// add CORS headers
if (boshManager.isCORSEnabled()) {
if (boshManager.isAllOriginsAllowed())
// set the Access-Control-Allow-Origin header to * to allow all Origin to do the CORS
response.addHeader("Access-Control-Allow-Origin", HttpBindManager.HTTP_BIND_CORS_ALLOW_ORIGIN_DEFAULT);
else {
// get the Origin header from the request and check if it is in the allowed Origin Map.
// if it is allowed write it back to the Access-Control-Allow-Origin header of the respond.
String origin = request.getHeader("Origin");
if (boshManager.isThisOriginAllowed(origin)) {
response.addHeader("Access-Control-Allow-Origin", origin);
}
}
response.addHeader("Access-Control-Allow-Methods", HttpBindManager.HTTP_BIND_CORS_ALLOW_METHODS_DEFAULT);
response.addHeader("Access-Control-Allow-Headers", HttpBindManager.HTTP_BIND_CORS_ALLOW_HEADERS_DEFAULT);
response.addHeader("Access-Control-Max-Age", HttpBindManager.HTTP_BIND_CORS_MAX_AGE_DEFAULT);
}
}
private static String createEmptyBody() {
Element body = DocumentHelper.createElement("body");
body.addNamespace("", "http://jabber.org/protocol/httpbind");
......
......@@ -36,13 +36,21 @@
Map<String, String> errorMap = new HashMap<String, String>();
boolean isEnabled = ParamUtils.getBooleanParameter(request, "httpBindEnabled",
serverManager.isHttpBindEnabled());
// CORS
boolean isCORSEnabled = ParamUtils.getBooleanParameter(request, "CORSEnabled",
serverManager.isCORSEnabled());
if (isEnabled) {
int requestedPort = ParamUtils.getIntParameter(request, "port",
serverManager.getHttpBindUnsecurePort());
int requestedSecurePort = ParamUtils.getIntParameter(request, "securePort",
serverManager.getHttpBindSecurePort());
// CORS
String CORSDomains = ParamUtils.getParameter(request, "CORSDomains", true);
try {
serverManager.setHttpBindPorts(requestedPort, requestedSecurePort);
// CORS
serverManager.setCORSEnabled(isCORSEnabled);
serverManager.setCORSAllowOrigin(CORSDomains);
}
catch (Exception e) {
Log.error("An error has occured configuring the HTTP binding ports", e);
......@@ -71,6 +79,8 @@
int port = serverManager.getHttpBindUnsecurePort();
int securePort = serverManager.getHttpBindSecurePort();
boolean isScriptSyntaxEnabled = serverManager.isScriptSyntaxEnabled();
// CORS
boolean isCORSEnabled = serverManager.isCORSEnabled();
%>
<%@page import="org.jivesoftware.openfire.http.FlashCrossDomainServlet"%><html>
......@@ -86,6 +96,9 @@
$("securePort").disabled = !enabled;
$("rb03").disabled = !enabled;
$("rb04").disabled = !enabled;
$("rb05").disabled = !enabled;
$("rb06").disabled = !enabled;
$("CORSDomains").disabled = !enabled;
$("crossdomain").disabled = !enabled;
}
window.onload = setTimeout("setEnabled()", 500);
......@@ -198,6 +211,53 @@
</tbody>
</table>
</div>
<!-- CORS -->
<div class="jive-contentBoxHeader">Provides support for CORS (Cross-Origin Resource Sharing)</div>
<div class="jive-contentbox">
<table cellpadding="3" cellspacing="0" border="0">
<tbody>
<tr valign="top">
<td width="1%" nowrap>
<input type="radio" name="CORSEnabled" value="true" id="rb05"
<%= (isCORSEnabled ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb05">
<b>Enabled</b> - Activate CORS support for cross domain scripting
</label>
<table border="0">
<tr>
<td>
<label for="CORSDomains">
Enter domain list below separated by commas or * to allow any :
</label>
</td>
</tr>
<tr>
<td>
<input id="CORSDomains" type="text" size="80" name="CORSDomains" value="<%= serverManager.getCORSAllowOrigin() %>">
</td>
</tr>
</table>
</td>
</tr>
<tr valign="top">
<td width="1%" nowrap>
<input type="radio" name="CORSEnabled" value="false" id="rb06"
<%= (!isCORSEnabled ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb06">
<b>Disabled</b> - Disable CORS support
</label>
</td>
</tr>
</tbody>
</table>
</div>
<!-- CORS -->
<div class="jive-contentBoxHeader">Cross-domain policy</div>
<div class="jive-contentbox">
<p><fmt:message key="httpbind.settings.crossdomain.info.general" /></p>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment