94a9803e0fd66509d656480532447b8d3d24514c
[platform/framework/web/crosswalk.git] / src / xwalk / application / common / security_policy.cc
1 // Copyright (c) 2014 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "xwalk/application/common/security_policy.h"
6
7 #include <map>
8 #include <string>
9
10 #include "content/public/browser/render_process_host.h"
11 #include "xwalk/application/browser/application.h"
12 #include "xwalk/application/common/application_manifest_constants.h"
13 #include "xwalk/application/common/constants.h"
14 #include "xwalk/application/common/manifest_handlers/csp_handler.h"
15 #include "xwalk/application/common/manifest_handlers/navigation_handler.h"
16 #include "xwalk/application/common/manifest_handlers/warp_handler.h"
17 #include "xwalk/runtime/common/xwalk_common_messages.h"
18
19 namespace xwalk {
20
21 namespace keys = application_manifest_keys;
22 namespace widget_keys = application_widget_keys;
23
24 namespace application {
25
26 namespace {
27 const char kAsterisk[] = "*";
28
29 const char kDirectiveValueSelf[] = "'self'";
30 const char kDirectiveValueNone[] = "'none'";
31
32 const char kDirectiveNameDefault[] = "default-src";
33 const char kDirectiveNameScript[] = "script-src";
34 const char kDirectiveNameStyle[] = "style-src";
35 const char kDirectiveNameObject[] = "object-src";
36
37 // By default:
38 // default-src * ; script-src 'self' ; style-src 'self' ; object-src 'none'
39 CSPInfo* GetDefaultCSPInfo() {
40   static CSPInfo default_csp_info;
41   if (default_csp_info.GetDirectives().empty()) {
42     std::vector<std::string> directive_all;
43     std::vector<std::string> directive_self;
44     std::vector<std::string> directive_none;
45     directive_all.push_back(kAsterisk);
46     directive_self.push_back(kDirectiveValueSelf);
47     directive_none.push_back(kDirectiveValueNone);
48
49     default_csp_info.SetDirective(kDirectiveNameDefault, directive_all);
50     default_csp_info.SetDirective(kDirectiveNameScript, directive_self);
51     default_csp_info.SetDirective(kDirectiveNameStyle, directive_self);
52     default_csp_info.SetDirective(kDirectiveNameObject, directive_none);
53   }
54
55   return (new CSPInfo(default_csp_info));
56 }
57
58 }  // namespace
59
60 SecurityPolicy::WhitelistEntry::WhitelistEntry(const GURL& url, bool subdomains)
61   : url(url),
62     subdomains(subdomains) {
63 }
64
65 SecurityPolicy::SecurityPolicy(Application* app)
66   : app_(app),
67     enabled_(false) {
68 }
69
70 SecurityPolicy::~SecurityPolicy() {
71 }
72
73 bool SecurityPolicy::IsAccessAllowed(const GURL& url) const {
74   if (!enabled_)
75     return true;
76
77   // Accessing own resources is always allowed.
78   if (url.SchemeIs(application::kApplicationScheme) &&
79       url.host() == app_->id())
80     return true;
81
82   for (std::vector<WhitelistEntry>::const_iterator it =
83       whitelist_entries_.begin(); it != whitelist_entries_.end(); ++it) {
84     const GURL& policy = it->url;
85     bool subdomains = it->subdomains;
86     bool is_host_matched = subdomains ?
87         url.DomainIs(policy.host().c_str()) : url.host() == policy.host();
88     if (url.scheme() == policy.scheme() && is_host_matched)
89       return true;
90   }
91   return false;
92 }
93
94 void SecurityPolicy::Enforce() {
95 }
96
97 void SecurityPolicy::AddWhitelistEntry(const GURL& url, bool subdomains) {
98   GURL app_url = app_->data()->URL();
99   DCHECK(app_->render_process_host());
100   WhitelistEntry entry = WhitelistEntry(url, subdomains);
101
102   std::vector<WhitelistEntry>::iterator it =
103       std::find(whitelist_entries_.begin(), whitelist_entries_.end(), entry);
104   if (it != whitelist_entries_.end())
105     return;
106
107   app_->render_process_host()->Send(new ViewMsg_SetAccessWhiteList(
108       app_url, url, subdomains));
109   whitelist_entries_.push_back(entry);
110 }
111
112 SecurityPolicyWARP::SecurityPolicyWARP(Application* app)
113   : SecurityPolicy(app) {
114 }
115
116 SecurityPolicyWARP::~SecurityPolicyWARP() {
117 }
118
119 void SecurityPolicyWARP::Enforce() {
120   const WARPInfo* info = static_cast<WARPInfo*>(
121       app_->data()->GetManifestData(widget_keys::kAccessKey));
122   if (!info) {
123     enabled_ = true;
124     DCHECK(app_->render_process_host());
125     app_->render_process_host()->Send(
126         new ViewMsg_EnableSecurityMode(
127             ApplicationData::GetBaseURLFromApplicationId(app_->id()),
128             SecurityPolicy::WARP));
129     return;
130   }
131
132   const base::ListValue* whitelist = info->GetWARP();
133   for (base::ListValue::const_iterator it = whitelist->begin();
134        it != whitelist->end(); ++it) {
135     base::DictionaryValue* value = NULL;
136     (*it)->GetAsDictionary(&value);
137     std::string dest;
138     if (!value || !value->GetString(widget_keys::kAccessOriginKey, &dest) ||
139         dest.empty())
140       continue;
141     if (dest == "*") {
142       enabled_ = false;
143       break;
144     }
145
146     GURL dest_url(dest);
147     // The default subdomains attribute should be "false".
148     std::string subdomains = "false";
149     value->GetString(widget_keys::kAccessSubdomainsKey, &subdomains);
150     AddWhitelistEntry(dest_url, (subdomains == "true"));
151     enabled_ = true;
152   }
153
154   if (enabled_) {
155     DCHECK(app_->render_process_host());
156     app_->render_process_host()->Send(
157         new ViewMsg_EnableSecurityMode(
158             ApplicationData::GetBaseURLFromApplicationId(app_->id()),
159             SecurityPolicy::WARP));
160   }
161 }
162
163 SecurityPolicyCSP::SecurityPolicyCSP(Application* app)
164   : SecurityPolicy(app) {
165 }
166
167 SecurityPolicyCSP::~SecurityPolicyCSP() {
168 }
169
170 void SecurityPolicyCSP::Enforce() {
171   Manifest::Type manifest_type = app_->data()->manifest_type();
172   const char* scp_key = GetCSPKey(manifest_type);
173   CSPInfo* csp_info =
174       static_cast<CSPInfo*>(app_->data()->GetManifestData(scp_key));
175   if (manifest_type == Manifest::TYPE_WIDGET) {
176 #if defined(OS_TIZEN)
177     if (!csp_info || csp_info->GetDirectives().empty())
178        app_->data()->SetManifestData(scp_key, GetDefaultCSPInfo());
179     // Always enable security mode when under CSP mode.
180     enabled_ = true;
181     NavigationInfo* info = static_cast<NavigationInfo*>(
182         app_->data()->GetManifestData(widget_keys::kAllowNavigationKey));
183     if (info) {
184       const std::vector<std::string>& allowed_list = info->GetAllowedDomains();
185       for (std::vector<std::string>::const_iterator it = allowed_list.begin();
186            it != allowed_list.end(); ++it) {
187         // If the policy is "*", it represents that any external link is allowed
188         // to navigate to.
189         if ((*it) == kAsterisk) {
190           enabled_ = false;
191           return;
192         }
193
194         // If the policy start with "*.", like this: *.domain,
195         // means that can access to all subdomains for 'domain',
196         // otherwise, the host of request url should exactly the same
197         // as policy.
198         bool subdomains = ((*it).find("*.") == 0);
199         std::string host = subdomains ? (*it).substr(2) : (*it);
200         AddWhitelistEntry(GURL("http://" + host), subdomains);
201         AddWhitelistEntry(GURL("https://" + host), subdomains);
202       }
203     }
204 #endif
205   } else {
206     if (!csp_info || csp_info->GetDirectives().empty()) {
207       LOG(ERROR) << "Failed to obtain CSP directives from the manifest";
208       return;
209     }
210     enabled_ = true;
211     const std::map<std::string, std::vector<std::string> >& policies =
212         csp_info->GetDirectives();
213     std::map<std::string, std::vector<std::string> >::const_iterator it =
214         policies.begin();
215     for (; it != policies.end(); ++it) {
216       const std::vector<std::string>& allowed_list = it->second;
217       for (std::vector<std::string>::const_iterator it = allowed_list.begin();
218            it != allowed_list.end(); ++it) {
219         GURL url(*it);
220         if (url.is_valid())
221           AddWhitelistEntry(url, false);
222       }
223     }
224   }
225
226   if (enabled_) {
227     DCHECK(app_->render_process_host());
228     app_->render_process_host()->Send(
229         new ViewMsg_EnableSecurityMode(
230             ApplicationData::GetBaseURLFromApplicationId(app_->id()),
231             SecurityPolicy::CSP));
232   }
233 }
234
235 }  // namespace application
236 }  // namespace xwalk