1/*
2 * Copyright (C) 2011 Google Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27#include "config.h"
28#include "SecurityContext.h"
29
30#include "ContentSecurityPolicy.h"
31#include "HTMLParserIdioms.h"
32#include "SecurityOrigin.h"
33#include <wtf/text/StringBuilder.h>
34
35namespace WebCore {
36
37SecurityContext::SecurityContext()
38    : m_haveInitializedSecurityOrigin(false)
39    , m_sandboxFlags(SandboxNone)
40{
41}
42
43SecurityContext::~SecurityContext()
44{
45}
46
47void SecurityContext::setSecurityOrigin(PassRefPtr<SecurityOrigin> securityOrigin)
48{
49    m_securityOrigin = securityOrigin;
50    m_haveInitializedSecurityOrigin = true;
51}
52
53void SecurityContext::setContentSecurityPolicy(std::unique_ptr<ContentSecurityPolicy> contentSecurityPolicy)
54{
55    m_contentSecurityPolicy = WTF::move(contentSecurityPolicy);
56}
57
58bool SecurityContext::isSecureTransitionTo(const URL& url) const
59{
60    // If we haven't initialized our security origin by now, this is probably
61    // a new window created via the API (i.e., that lacks an origin and lacks
62    // a place to inherit the origin from).
63    if (!haveInitializedSecurityOrigin())
64        return true;
65
66    RefPtr<SecurityOrigin> other = SecurityOrigin::create(url);
67    return securityOrigin()->canAccess(other.get());
68}
69
70void SecurityContext::enforceSandboxFlags(SandboxFlags mask)
71{
72    m_sandboxFlags |= mask;
73
74    // The SandboxOrigin is stored redundantly in the security origin.
75    if (isSandboxed(SandboxOrigin) && securityOrigin() && !securityOrigin()->isUnique())
76        setSecurityOrigin(SecurityOrigin::createUnique());
77}
78
79SandboxFlags SecurityContext::parseSandboxPolicy(const String& policy, String& invalidTokensErrorMessage)
80{
81    // http://www.w3.org/TR/html5/the-iframe-element.html#attr-iframe-sandbox
82    // Parse the unordered set of unique space-separated tokens.
83    SandboxFlags flags = SandboxAll;
84    unsigned length = policy.length();
85    unsigned start = 0;
86    unsigned numberOfTokenErrors = 0;
87    StringBuilder tokenErrors;
88    while (true) {
89        while (start < length && isHTMLSpace(policy[start]))
90            ++start;
91        if (start >= length)
92            break;
93        unsigned end = start + 1;
94        while (end < length && !isHTMLSpace(policy[end]))
95            ++end;
96
97        // Turn off the corresponding sandbox flag if it's set as "allowed".
98        String sandboxToken = policy.substring(start, end - start);
99        if (equalIgnoringCase(sandboxToken, "allow-same-origin"))
100            flags &= ~SandboxOrigin;
101        else if (equalIgnoringCase(sandboxToken, "allow-forms"))
102            flags &= ~SandboxForms;
103        else if (equalIgnoringCase(sandboxToken, "allow-scripts")) {
104            flags &= ~SandboxScripts;
105            flags &= ~SandboxAutomaticFeatures;
106        } else if (equalIgnoringCase(sandboxToken, "allow-top-navigation"))
107            flags &= ~SandboxTopNavigation;
108        else if (equalIgnoringCase(sandboxToken, "allow-popups"))
109            flags &= ~SandboxPopups;
110        else if (equalIgnoringCase(sandboxToken, "allow-pointer-lock"))
111            flags &= ~SandboxPointerLock;
112        else {
113            if (numberOfTokenErrors)
114                tokenErrors.appendLiteral(", '");
115            else
116                tokenErrors.append('\'');
117            tokenErrors.append(sandboxToken);
118            tokenErrors.append('\'');
119            numberOfTokenErrors++;
120        }
121
122        start = end + 1;
123    }
124
125    if (numberOfTokenErrors) {
126        if (numberOfTokenErrors > 1)
127            tokenErrors.appendLiteral(" are invalid sandbox flags.");
128        else
129            tokenErrors.appendLiteral(" is an invalid sandbox flag.");
130        invalidTokensErrorMessage = tokenErrors.toString();
131    }
132
133    return flags;
134}
135
136}
137