summaryrefslogtreecommitdiffstats
path: root/dom/security/test/csp/test_frameancestors.html
blob: 8b44ba72fb47b106cccab9d081e6f941e70f0aef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<!DOCTYPE HTML>
<html>
<head>
  <title>Test for Content Security Policy Frame Ancestors directive</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<iframe style="width:100%;height:300px;" id='cspframe'></iframe>
<script class="testbody" type="text/javascript">

// These are test results: -1 means it hasn't run,
// true/false is the pass/fail result.
var framesThatShouldLoad = {
  aa_allow: -1,    /* innermost frame allows a *
  //aa_block: -1,    /* innermost frame denies a */
  ab_allow: -1,    /* innermost frame allows a */
  //ab_block: -1,    /* innermost frame denies a */
  aba_allow: -1,   /* innermost frame allows b,a */
  //aba_block: -1,   /* innermost frame denies b */
  //aba2_block: -1,  /* innermost frame denies a */
  abb_allow: -1,   /* innermost frame allows b,a */
  //abb_block: -1,   /* innermost frame denies b */
  //abb2_block: -1,  /* innermost frame denies a */
};

// we normally expect _6_ violations (6 test cases that cause blocks), but many
// of the cases cause violations due to the // origin of the test harness (same
// as 'a'). When the violation is cross-origin, the URI passed to the observers
// is null (see bug 846978).  This means we can't tell if it's part of the test
// case or if it is the test harness frame (also origin 'a').
// As a result, we'll get an extra violation for the following cases:
//  ab_block    "frame-ancestors 'none'" (outer frame and test harness)
//  aba2_block  "frame-ancestors b" (outer frame and test harness)
//  abb2_block   "frame-ancestors b" (outer frame and test harness)
//
// and while we can detect the test harness check for this one case since
// the violations are not cross-origin and we get the URI:
//  aba2_block  "frame-ancestors b" (outer frame and test harness)
//
// we can't for these other ones:
//  ab_block    "frame-ancestors 'none'" (outer frame and test harness)
//  abb2_block   "frame-ancestors b" (outer frame and test harness)
//
// so that results in 2 extra violation notifications due to the test harness.
// expected = 6, total = 8
//
// Number of tests that pass for this file should be 12 (8 violations 4 loads)
var expectedViolationsLeft = 8;

// CSP frame-ancestor checks happen in the parent, hence we have to
// proxy the csp violation notifications.
SpecialPowers.registerObservers("csp-on-violate-policy");

// This is used to watch the blocked data bounce off CSP and allowed data
// get sent out to the wire.
function examiner() {
  SpecialPowers.addObserver(this, "specialpowers-csp-on-violate-policy");
}
examiner.prototype  = {
  observe(subject, topic, data) {
    // subject should be an nsURI... though could be null since CSP
    // prohibits cross-origin URI reporting during frame ancestors checks.
    if (subject && !SpecialPowers.can_QI(subject))
      return;

    var asciiSpec = subject;

    try {
      asciiSpec = SpecialPowers.getPrivilegedProps(
                    SpecialPowers.do_QueryInterface(subject, "nsIURI"),
                    "asciiSpec");

      // skip checks on the test harness -- can't do this skipping for
      // cross-origin blocking since the observer doesn't get the URI.  This
      // can cause this test to over-succeed (but only in specific cases).
      if (asciiSpec.includes("test_frameancestors.html")) {
        return;
      }
    } catch (ex) {
      // was not an nsIURI, so it was probably a cross-origin report.
    }

    if (topic === "specialpowers-csp-on-violate-policy") {
      //these were blocked... record that they were blocked
      window.frameBlocked(asciiSpec, data);
    }
  },

  // must eventually call this to remove the listener,
  // or mochitests might get borked.
  remove() {
    SpecialPowers.removeObserver(this, "specialpowers-csp-on-violate-policy");
  }
}

// called when a frame is loaded
// -- if it's not enumerated above, it should not load!
var frameLoaded = function(testname, uri) {
  //test already complete.... forget it... remember the first result.
  if (window.framesThatShouldLoad[testname] != -1)
    return;

  if (typeof window.framesThatShouldLoad[testname] === 'undefined') {
    // uh-oh, we're not expecting this frame to load!
    ok(false, testname + ' framed site should not have loaded: ' + uri);
  } else {
    framesThatShouldLoad[testname] = true;
    ok(true, testname + ' framed site when allowed by csp (' + uri + ')');
  }
  checkTestResults();
}

// called when a frame is blocked
// -- we can't determine *which* frame was blocked, but at least we can count them
var frameBlocked = function(uri, policy) {
  ok(true, 'a CSP policy blocked frame from being loaded: ' + policy);
  expectedViolationsLeft--;
  checkTestResults();
}


// Check to see if all the tests have run
var checkTestResults = function() {
  // if any test is incomplete, keep waiting
  for (var v in framesThatShouldLoad)
    if(window.framesThatShouldLoad[v] == -1)
      return;

  if (window.expectedViolationsLeft > 0)
    return;

  // ... otherwise, finish
  window.examiner.remove();
  SimpleTest.finish();
}

window.addEventListener("message", receiveMessage);

function receiveMessage(event) {
  if (event.data.call && event.data.call == 'frameLoaded')
    frameLoaded(event.data.testname, event.data.uri);
}

//////////////////////////////////////////////////////////////////////
// set up and go
window.examiner = new examiner();
SimpleTest.waitForExplicitFinish();

// save this for last so that our listeners are registered.
// ... this loads the testbed of good and bad requests.
document.getElementById('cspframe').src = 'file_frameancestors_main.html';

</script>
</pre>
</body>
</html>