Upstream version 7.36.153.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / common / security_policy.cc
index f5da81f..3f29070 100644 (file)
 
 #include "xwalk/application/common/security_policy.h"
 
+#include <map>
+#include <string>
+
+#include "content/public/browser/render_process_host.h"
+#include "xwalk/application/browser/application.h"
+#include "xwalk/application/common/application_manifest_constants.h"
+#include "xwalk/application/common/constants.h"
+#include "xwalk/application/common/manifest_handlers/csp_handler.h"
+#include "xwalk/application/common/manifest_handlers/navigation_handler.h"
+#include "xwalk/application/common/manifest_handlers/warp_handler.h"
+#include "xwalk/runtime/common/xwalk_common_messages.h"
+
 namespace xwalk {
+
+namespace keys = application_manifest_keys;
+namespace widget_keys = application_widget_keys;
+
 namespace application {
 
-SecurityPolicy::SecurityPolicy(const GURL& url, bool subdomains)
-    : url_(url),
-      subdomains_(subdomains) {
+namespace {
+const char kAsterisk[] = "*";
+
+const char kDirectiveValueSelf[] = "'self'";
+const char kDirectiveValueNone[] = "'none'";
+
+const char kDirectiveNameDefault[] = "default-src";
+const char kDirectiveNameScript[] = "script-src";
+const char kDirectiveNameStyle[] = "style-src";
+const char kDirectiveNameObject[] = "object-src";
+
+// By default:
+// default-src * ; script-src 'self' ; style-src 'self' ; object-src 'none'
+CSPInfo* GetDefaultCSPInfo() {
+  static CSPInfo default_csp_info;
+  if (default_csp_info.GetDirectives().empty()) {
+    std::vector<std::string> directive_all;
+    std::vector<std::string> directive_self;
+    std::vector<std::string> directive_none;
+    directive_all.push_back(kAsterisk);
+    directive_self.push_back(kDirectiveValueSelf);
+    directive_none.push_back(kDirectiveValueNone);
+
+    default_csp_info.SetDirective(kDirectiveNameDefault, directive_all);
+    default_csp_info.SetDirective(kDirectiveNameScript, directive_self);
+    default_csp_info.SetDirective(kDirectiveNameStyle, directive_self);
+    default_csp_info.SetDirective(kDirectiveNameObject, directive_none);
+  }
+
+  return (new CSPInfo(default_csp_info));
+}
+
+}  // namespace
+
+SecurityPolicy::WhitelistEntry::WhitelistEntry(const GURL& url, bool subdomains)
+  : url(url),
+    subdomains(subdomains) {
+}
+
+SecurityPolicy::SecurityPolicy(Application* app)
+  : app_(app),
+    enabled_(false) {
+}
+
+SecurityPolicy::~SecurityPolicy() {
+}
+
+bool SecurityPolicy::IsAccessAllowed(const GURL& url) const {
+  if (!enabled_)
+    return true;
+
+  // Accessing own resources is always allowed.
+  if (url.SchemeIs(application::kApplicationScheme) &&
+      url.host() == app_->id())
+    return true;
+
+  for (std::vector<WhitelistEntry>::const_iterator it =
+      whitelist_entries_.begin(); it != whitelist_entries_.end(); ++it) {
+    const GURL& policy = it->url;
+    bool subdomains = it->subdomains;
+    bool is_host_matched = subdomains ?
+        url.DomainIs(policy.host().c_str()) : url.host() == policy.host();
+    if (url.scheme() == policy.scheme() && is_host_matched)
+      return true;
+  }
+  return false;
+}
+
+void SecurityPolicy::Enforce() {
+}
+
+void SecurityPolicy::AddWhitelistEntry(const GURL& url, bool subdomains) {
+  GURL app_url = app_->data()->URL();
+  DCHECK(app_->render_process_host());
+  WhitelistEntry entry = WhitelistEntry(url, subdomains);
+
+  std::vector<WhitelistEntry>::iterator it =
+      std::find(whitelist_entries_.begin(), whitelist_entries_.end(), entry);
+  if (it != whitelist_entries_.end())
+    return;
+
+  app_->render_process_host()->Send(new ViewMsg_SetAccessWhiteList(
+      app_url, url, subdomains));
+  whitelist_entries_.push_back(entry);
+}
+
+SecurityPolicyWARP::SecurityPolicyWARP(Application* app)
+  : SecurityPolicy(app) {
+}
+
+SecurityPolicyWARP::~SecurityPolicyWARP() {
+}
+
+void SecurityPolicyWARP::Enforce() {
+  const WARPInfo* info = static_cast<WARPInfo*>(
+      app_->data()->GetManifestData(widget_keys::kAccessKey));
+  if (!info) {
+    enabled_ = true;
+    DCHECK(app_->render_process_host());
+    app_->render_process_host()->Send(
+        new ViewMsg_EnableSecurityMode(
+            ApplicationData::GetBaseURLFromApplicationId(app_->id()),
+            SecurityPolicy::WARP));
+    return;
+  }
+
+  const base::ListValue* whitelist = info->GetWARP();
+  for (base::ListValue::const_iterator it = whitelist->begin();
+       it != whitelist->end(); ++it) {
+    base::DictionaryValue* value = NULL;
+    (*it)->GetAsDictionary(&value);
+    std::string dest;
+    if (!value || !value->GetString(widget_keys::kAccessOriginKey, &dest) ||
+        dest.empty())
+      continue;
+    if (dest == "*") {
+      enabled_ = false;
+      break;
+    }
+
+    GURL dest_url(dest);
+    // The default subdomains attribute should be "false".
+    std::string subdomains = "false";
+    value->GetString(widget_keys::kAccessSubdomainsKey, &subdomains);
+    AddWhitelistEntry(dest_url, (subdomains == "true"));
+    enabled_ = true;
+  }
+
+  if (enabled_) {
+    DCHECK(app_->render_process_host());
+    app_->render_process_host()->Send(
+        new ViewMsg_EnableSecurityMode(
+            ApplicationData::GetBaseURLFromApplicationId(app_->id()),
+            SecurityPolicy::WARP));
+  }
+}
+
+SecurityPolicyCSP::SecurityPolicyCSP(Application* app)
+  : SecurityPolicy(app) {
+}
+
+SecurityPolicyCSP::~SecurityPolicyCSP() {
+}
+
+void SecurityPolicyCSP::Enforce() {
+  Package::Type package_type = app_->data()->GetPackageType();
+  const char* scp_key = GetCSPKey(package_type);
+  CSPInfo* csp_info =
+      static_cast<CSPInfo*>(app_->data()->GetManifestData(scp_key));
+  if (package_type = Package::WGT) {
+#if defined(OS_TIZEN)
+    if (!csp_info || csp_info->GetDirectives().empty())
+       app_->data()->SetManifestData(scp_key, GetDefaultCSPInfo());
+    // Always enable security mode when under CSP mode.
+    enabled_ = true;
+    NavigationInfo* info = static_cast<NavigationInfo*>(
+        app_->data()->GetManifestData(widget_keys::kAllowNavigationKey));
+    if (info) {
+      const std::vector<std::string>& allowed_list = info->GetAllowedDomains();
+      for (std::vector<std::string>::const_iterator it = allowed_list.begin();
+           it != allowed_list.end(); ++it) {
+        // If the policy is "*", it represents that any external link is allowed
+        // to navigate to.
+        if ((*it) == kAsterisk) {
+          enabled_ = false;
+          return;
+        }
+
+        // If the policy start with "*.", like this: *.domain,
+        // means that can access to all subdomains for 'domain',
+        // otherwise, the host of request url should exactly the same
+        // as policy.
+        bool subdomains = ((*it).find("*.") == 0);
+        std::string host = subdomains ? (*it).substr(2) : (*it);
+        AddWhitelistEntry(GURL("http://" + host), subdomains);
+        AddWhitelistEntry(GURL("https://" + host), subdomains);
+      }
+    }
+#endif
+  } else {
+    if (!csp_info || csp_info->GetDirectives().empty()) {
+      LOG(ERROR) << "Failed to obtain CSP directives from the manifest";
+      return;
+    }
+    enabled_ = true;
+    const std::map<std::string, std::vector<std::string> >& policies =
+        csp_info->GetDirectives();
+    std::map<std::string, std::vector<std::string> >::const_iterator it =
+        policies.begin();
+    for (; it != policies.end(); ++it) {
+      const std::vector<std::string>& allowed_list = it->second;
+      for (std::vector<std::string>::const_iterator it = allowed_list.begin();
+           it != allowed_list.end(); ++it) {
+        GURL url(*it);
+        if (url.is_valid())
+          AddWhitelistEntry(url, false);
+      }
+    }
+  }
+
+  if (enabled_) {
+    DCHECK(app_->render_process_host());
+    app_->render_process_host()->Send(
+        new ViewMsg_EnableSecurityMode(
+            ApplicationData::GetBaseURLFromApplicationId(app_->id()),
+            SecurityPolicy::CSP));
+  }
 }
 
 }  // namespace application