cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bhais...@apache.org
Subject git commit: updated refs/heads/master to 20bcb4b
Date Sat, 28 Feb 2015 12:44:56 GMT
Repository: cloudstack
Updated Branches:
  refs/heads/master 843c0f891 -> 20bcb4b67


CLOUDSTACK-7063, CLOUDSTACK-7064: Add security headers on HTTP response

- Adds X-XSS-Protection header
- Adds X-Content-Type-Options header
- Fixes to use json content type defined from global settings
- Uses secure cookie if enabled in global settings

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
(cherry picked from commit b6b3494782d8bc1033941b802380ba1d5ebd464c)
Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/20bcb4b6
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/20bcb4b6
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/20bcb4b6

Branch: refs/heads/master
Commit: 20bcb4b673ea83dd3d4e301705425632daa226ca
Parents: 843c0f8
Author: Rohit Yadav <rohit.yadav@shapeblue.com>
Authored: Sat Feb 28 18:12:37 2015 +0530
Committer: Rohit Yadav <rohit.yadav@shapeblue.com>
Committed: Sat Feb 28 18:14:49 2015 +0530

----------------------------------------------------------------------
 server/src/com/cloud/api/ApiServer.java        | 21 ++++++++++++-----
 server/src/com/cloud/api/ApiServlet.java       | 24 ++++++++++++-------
 server/src/com/cloud/configuration/Config.java | 15 +++++++++---
 utils/src/com/cloud/utils/HttpUtils.java       | 26 ++++++++++++++++++---
 4 files changed, 66 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/20bcb4b6/server/src/com/cloud/api/ApiServer.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java
index daf24ef..cf719c0 100644
--- a/server/src/com/cloud/api/ApiServer.java
+++ b/server/src/com/cloud/api/ApiServer.java
@@ -181,7 +181,8 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler,
ApiSer
     private static final Logger s_accessLogger = Logger.getLogger("apiserver." + ApiServer.class.getName());
 
     public static boolean encodeApiResponse = false;
-    public static String jsonContentType = "text/javascript";
+    public static boolean s_enableSecureCookie = false;
+    public static String s_jsonContentType = HttpUtils.JSON_CONTENT_TYPE;
 
     /**
      * Non-printable ASCII characters - numbers 0 to 31 and 127 decimal
@@ -362,9 +363,13 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler,
ApiSer
         }
 
         setEncodeApiResponse(Boolean.valueOf(_configDao.getValue(Config.EncodeApiResponse.key())));
-        final String jsonType = _configDao.getValue(Config.JavaScriptDefaultContentType.key());
+        final String jsonType = _configDao.getValue(Config.JSONDefaultContentType.key());
         if (jsonType != null) {
-            jsonContentType = jsonType;
+            s_jsonContentType = jsonType;
+        }
+        final Boolean enableSecureSessionCookie = Boolean.valueOf(_configDao.getValue(Config.EnableSecureSessionCookie.key()));
+        if (enableSecureSessionCookie != null) {
+            s_enableSecureCookie = enableSecureSessionCookie;
         }
 
         if (apiPort != null) {
@@ -1136,7 +1141,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler,
ApiSer
             final BasicHttpEntity body = new BasicHttpEntity();
             if (HttpUtils.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) {
                 // JSON response
-                body.setContentType(jsonContentType);
+                body.setContentType(getJSONContentType());
                 if (responseText == null) {
                     body.setContent(new ByteArrayInputStream("{ \"error\" : { \"description\"
: \"Internal Server Error\" } }".getBytes(HttpUtils.UTF_8)));
                 }
@@ -1367,7 +1372,11 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler,
ApiSer
         ApiServer.encodeApiResponse = encodeApiResponse;
     }
 
-    public static String getJsonContentType() {
-        return jsonContentType;
+    public static boolean isSecureSessionCookieEnabled() {
+        return s_enableSecureCookie;
+    }
+
+    public static String getJSONContentType() {
+        return s_jsonContentType;
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/20bcb4b6/server/src/com/cloud/api/ApiServlet.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiServlet.java b/server/src/com/cloud/api/ApiServlet.java
index 3c73375..5628d98 100644
--- a/server/src/com/cloud/api/ApiServlet.java
+++ b/server/src/com/cloud/api/ApiServlet.java
@@ -155,12 +155,20 @@ public class ApiServlet extends HttpServlet {
         try {
 
             if (HttpUtils.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) {
-                resp.setContentType(HttpUtils.JSON_CONTENT_TYPE);
+                resp.setContentType(ApiServer.getJSONContentType());
             } else if (HttpUtils.RESPONSE_TYPE_XML.equalsIgnoreCase(responseType)){
                 resp.setContentType(HttpUtils.XML_CONTENT_TYPE);
             }
 
             HttpSession session = req.getSession(false);
+            if (ApiServer.isSecureSessionCookieEnabled()) {
+                resp.setHeader("SET-COOKIE", "JSESSIONID=" + session.getId() + ";Secure;Path=/client");
+                if (s_logger.isDebugEnabled()) {
+                    if (s_logger.isDebugEnabled()) {
+                        s_logger.debug("Session cookie is marked secure!");
+                    }
+                }
+            }
             final Object[] responseTypeParam = params.get(ApiConstants.RESPONSE);
             if (responseTypeParam != null) {
                 responseType = (String)responseTypeParam[0];
@@ -213,7 +221,7 @@ public class ApiServlet extends HttpServlet {
                             }
                         }
                     }
-                    HttpUtils.writeHttpResponse(resp, responseString, httpResponseCode, responseType);
+                    HttpUtils.writeHttpResponse(resp, responseString, httpResponseCode, responseType,
ApiServer.getJSONContentType());
                     return;
                 }
             }
@@ -240,7 +248,7 @@ public class ApiServlet extends HttpServlet {
                     auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " +
"unable to verify user credentials");
                     final String serializedResponse =
                         _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED,
"unable to verify user credentials", params, responseType);
-                    HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED,
responseType);
+                    HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED,
responseType, ApiServer.getJSONContentType());
                     return;
                 }
 
@@ -251,7 +259,7 @@ public class ApiServlet extends HttpServlet {
                         s_logger.info("missing command, ignoring request...");
                         auditTrailSb.append(" " + HttpServletResponse.SC_BAD_REQUEST + "
" + "no command specified");
                         final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST,
"no command specified", params, responseType);
-                        HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST,
responseType);
+                        HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST,
responseType, ApiServer.getJSONContentType());
                         return;
                     }
                     final User user = _entityMgr.findById(User.class, userId);
@@ -267,7 +275,7 @@ public class ApiServlet extends HttpServlet {
                     auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " +
"unable to verify user credentials");
                     final String serializedResponse =
                         _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED,
"unable to verify user credentials", params, responseType);
-                    HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED,
responseType);
+                    HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED,
responseType, ApiServer.getJSONContentType());
                     return;
                 }
             } else {
@@ -281,7 +289,7 @@ public class ApiServlet extends HttpServlet {
                 // Add the HTTP method (GET/POST/PUT/DELETE) as well into the params map.
                 params.put("httpmethod", new String[] {req.getMethod()});
                 final String response = _apiServer.handleRequest(params, responseType, auditTrailSb);
-                HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK,
responseType);
+                HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK,
responseType, ApiServer.getJSONContentType());
             } else {
                 if (session != null) {
                     try {
@@ -294,13 +302,13 @@ public class ApiServlet extends HttpServlet {
                 final String serializedResponse =
                     _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED,
"unable to verify user credentials and/or request signature", params,
                         responseType);
-                HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED,
responseType);
+                HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED,
responseType, ApiServer.getJSONContentType());
 
             }
         } catch (final ServerApiException se) {
             final String serializedResponseText = _apiServer.getSerializedApiError(se, params,
responseType);
             resp.setHeader("X-Description", se.getDescription());
-            HttpUtils.writeHttpResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(),
responseType);
+            HttpUtils.writeHttpResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(),
responseType, ApiServer.getJSONContentType());
             auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription());
         } catch (final Exception ex) {
             s_logger.error("unknown exception writing api response", ex);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/20bcb4b6/server/src/com/cloud/configuration/Config.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index dd9bfc0..982958e 100644
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -1592,13 +1592,22 @@ public enum Config {
             "Percentage (as a value between 0 and 1) of connected agents after which agent
load balancing will start happening",
             null),
 
-    JavaScriptDefaultContentType(
+    JSONDefaultContentType(
             "Advanced",
             ManagementServer.class,
             String.class,
             "json.content.type",
-            "text/javascript",
-            "Http response content type for .js files (default is text/javascript)",
+            "application/json; charset=UTF-8",
+            "Http response content type for JSON",
+            null),
+
+    EnableSecureSessionCookie(
+            "Advanced",
+            ManagementServer.class,
+            Boolean.class,
+            "enable.secure.session.cookie",
+            "false",
+            "Session cookie's secure flag is enabled if true. Use this only when using HTTPS",
             null),
 
     DefaultMaxDomainUserVms("Domain Defaults", ManagementServer.class, Long.class, "max.domain.user.vms",
"40", "The default maximum number of user VMs that can be deployed for a domain", null),

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/20bcb4b6/utils/src/com/cloud/utils/HttpUtils.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/HttpUtils.java b/utils/src/com/cloud/utils/HttpUtils.java
index 0ed2afa..58768dc 100644
--- a/utils/src/com/cloud/utils/HttpUtils.java
+++ b/utils/src/com/cloud/utils/HttpUtils.java
@@ -31,20 +31,40 @@ public class HttpUtils {
     public static final String UTF_8 = "UTF-8";
     public static final String RESPONSE_TYPE_JSON = "json";
     public static final String RESPONSE_TYPE_XML = "xml";
-    public static final String JSON_CONTENT_TYPE = "text/javascript; charset=UTF-8";
+    public static final String JSON_CONTENT_TYPE = "application/json; charset=UTF-8";
     public static final String XML_CONTENT_TYPE = "text/xml; charset=UTF-8";
 
+    public static void addSecurityHeaders(final HttpServletResponse resp) {
+        if (resp.containsHeader("X-Content-Type-Options")) {
+            resp.setHeader("X-Content-Type-Options", "nosniff");
+        }
+        else {
+            resp.addHeader("X-Content-Type-Options", "nosniff");
+        }
+        if (resp.containsHeader("X-XSS-Protection")) {
+            resp.setHeader("X-XSS-Protection", "1;mode=block");
+        }
+        else {
+            resp.addHeader("X-XSS-Protection", "1;mode=block");
+        }
+    }
+
     public static void writeHttpResponse(final HttpServletResponse resp, final String response,
-                                         final Integer responseCode, final String responseType)
{
+                                         final Integer responseCode, final String responseType,
final String jsonContentType) {
         try {
             if (RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) {
-                resp.setContentType(JSON_CONTENT_TYPE);
+                if (jsonContentType != null && !jsonContentType.isEmpty()) {
+                    resp.setContentType(jsonContentType);
+                } else {
+                    resp.setContentType(JSON_CONTENT_TYPE);
+                }
             } else if (RESPONSE_TYPE_XML.equalsIgnoreCase(responseType)){
                 resp.setContentType(XML_CONTENT_TYPE);
             }
             if (responseCode != null) {
                 resp.setStatus(responseCode);
             }
+            addSecurityHeaders(resp);
             resp.getWriter().print(response);
         } catch (final IOException ioex) {
             if (s_logger.isTraceEnabled()) {


Mime
View raw message