@Test public void testDirectiveNameParsing() throws ParseException, TokeniserException { Policy p; p = parse("font-src a"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("form-action a"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("frame-ancestors 'none'"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("frame-src a"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("img-src a"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("media-src a"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("object-src a"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("plugin-types */*"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("report-uri https://example.com/report"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("sandbox allow-scripts"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("script-src a"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("style-src http://*.example.com:*"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); p = parse("style-src samba://*.example.com"); assertNotNull("policy should not be null", p); assertEquals("directive count", 1, p.getDirectives().size()); failsToParse("abc"); failsToParse("zzscript-src *; bla"); }
@Test public void testAncestorSource() throws ParseException, TokeniserException { assertEquals( "directive-name, no directive-value", "frame-ancestors", parse("frame-ancestors").getDirectiveByType(FrameAncestorsDirective.class).show()); assertEquals( "directive-name, directive-value", "frame-ancestors 'none'", parse("frame-ancestors 'none'").getDirectiveByType(FrameAncestorsDirective.class).show()); Policy p; p = parse("frame-ancestors 'self' https://example.com"); Policy q; q = parse("script-src abc; frame-ancestors http://example.com"); FrameAncestorsDirective d1 = p.getDirectiveByType(FrameAncestorsDirective.class); FrameAncestorsDirective d2 = q.getDirectiveByType(FrameAncestorsDirective.class); d1.union(d2); assertEquals( "ancestor-source union", "frame-ancestors 'self' https://example.com http://example.com", d1.show()); assertFalse("ancestor-source inequality", d1.equals(d2)); p = parse("frame-ancestors http://example.com"); q = parse("frame-ancestors http://example.com"); d1 = p.getDirectiveByType(FrameAncestorsDirective.class); d2 = q.getDirectiveByType(FrameAncestorsDirective.class); assertTrue("ancestor-source equality", d1.equals(d2)); assertEquals("ancestor-source hashcode equality", d1.hashCode(), d2.hashCode()); p = parse("frame-ancestors http:"); q = parse("frame-ancestors http:"); assertTrue("ancestor-source scheme-source equality", p.equals(q)); assertEquals("ancestor-source scheme-source equality", p.hashCode(), q.hashCode()); failsToParse("frame-ancestors scheme::"); failsToParse("frame-ancestors 'none' 'self'"); p = parse("frame-ancestors *"); q = parse("frame-ancestors http://example.com"); p.union(q); assertEquals("frame-ancestors *", p.show()); }
@Test() public void testPluginTypesParsing() throws ParseException, TokeniserException { failsToParse("plugin-types"); // XXX: technically allowed via ietf-token if an RFC introduces a type/subtype that is empty failsToParse("plugin-types /"); assertEquals( "directive-name, directive-value", "plugin-types a/b", parse("plugin-types a/b").getDirectiveByType(PluginTypesDirective.class).show()); assertEquals( "directive-name, directive-value", "plugin-types a/b c/d", parse("plugin-types a/b c/d").getDirectiveByType(PluginTypesDirective.class).show()); assertEquals( "directive-name, directive-value", "plugin-types x-a/x-b", parse("plugin-types x-a/x-b").getDirectiveByType(PluginTypesDirective.class).show()); assertEquals( "directive-name, directive-value", "plugin-types X-A/X-B", parse("plugin-types X-A/X-B").getDirectiveByType(PluginTypesDirective.class).show()); Policy p, q; p = parse("plugin-types a/b"); q = parse("plugin-types c/d; script-src *"); PluginTypesDirective d1 = p.getDirectiveByType(PluginTypesDirective.class); PluginTypesDirective d2 = q.getDirectiveByType(PluginTypesDirective.class); d1.union(d2); assertEquals("plugin-types union", "plugin-types a/b c/d", d1.show()); p = parse("plugin-types a/b"); q = parse("plugin-types a/c;"); d1 = p.getDirectiveByType(PluginTypesDirective.class); d2 = q.getDirectiveByType(PluginTypesDirective.class); assertFalse("plugin-type subtype inequality", d1.equals(d2)); p = parse("plugin-types a/b"); q = parse("plugin-types a/b;"); d1 = p.getDirectiveByType(PluginTypesDirective.class); d2 = q.getDirectiveByType(PluginTypesDirective.class); assertEquals("plugin-types hashcode equality", d1.hashCode(), d2.hashCode()); }
@Test public void testSandboxParsing() throws ParseException, TokeniserException { failsToParse("sandbox a!*\n"); failsToParse("sandbox a!*^:"); assertEquals( "sandbox is valid", "sandbox abc", parse("sandbox abc").getDirectiveByType(SandboxDirective.class).show()); Policy p; p = parse("sandbox a"); Policy q; q = parse("sandbox a"); SandboxDirective d1 = p.getDirectiveByType(SandboxDirective.class); assertTrue("sandbox equals", d1.equals(q.getDirectiveByType(SandboxDirective.class))); assertEquals("sandbox hashcode equality", p.hashCode(), q.hashCode()); q = parse("sandbox b; script-src a"); assertFalse( "sandbox directives equality", d1.equals(q.getDirectiveByType(SandboxDirective.class))); d1.union(q.getDirectiveByType(SandboxDirective.class)); assertEquals("sandbox union", "sandbox a b", d1.show()); assertNotEquals("sandbox hashcode inequality", p.hashCode(), q.hashCode()); ScriptSrcDirective d2 = q.getDirectiveByType(ScriptSrcDirective.class); }
@Test public void testReportUri() throws ParseException, TokeniserException { failsToParse("report-uri "); failsToParse("report-uri #"); failsToParse("report-uri a"); Policy p, q; p = parse("report-uri http://a"); q = parse("report-uri http://b"); ReportUriDirective d1 = p.getDirectiveByType(ReportUriDirective.class); assertFalse("report-uri inequality", d1.equals(q.getDirectiveByType(ReportUriDirective.class))); d1.union(q.getDirectiveByType(ReportUriDirective.class)); assertEquals("report-uri union", "report-uri http://a http://b", d1.show()); assertNotEquals("report-uri hashcode shouldn't match", p.hashCode(), q.hashCode()); p = parse("report-uri https://a"); q = parse("report-uri https://a; "); assertEquals("report-uri hashcode match", p.hashCode(), q.hashCode()); assertTrue("report-uri equals", p.equals(q)); q = parse("report-uri http://a; sandbox 4"); d1 = q.getDirectiveByType(ReportUriDirective.class); SandboxDirective d2 = q.getDirectiveByType(SandboxDirective.class); assertEquals("report-uri http://a", d1.show()); assertEquals("sandbox 4", d2.show()); }
@Test public void testSourceExpressionParsing() throws ParseException, TokeniserException { assertEquals("directive-name, no directive-value", "base-uri", parseAndShow("base-uri")); assertEquals("directive-name, <tab>", "base-uri", parseAndShow("base-uri\t")); assertEquals("directive-name, <space>", "base-uri", parseAndShow("base-uri ")); assertEquals("directive-name, 3*<space>", "base-uri", parseAndShow("base-uri ")); assertEquals("directive-name, scheme-part", "base-uri https:", parseAndShow("base-uri https:")); assertEquals( "directive-name, 2*scheme-part", "base-uri file: javascript:", parseAndShow("base-uri file: javascript: ")); assertEquals( "directive-name, eliminated scheme-part", "base-uri *", parseAndShow("base-uri * https:")); assertEquals("directive-name, host-part *", "base-uri *", parseAndShow("base-uri *")); assertEquals("directive-name, host-part *.", "base-uri *.a", parseAndShow("base-uri *.a")); assertEquals( "represent origin host-source as 'self' keyword-source", "default-src 'self'", parse("default-src http://example.com").show()); failsToParse("connect-src 'none' scheme:"); failsToParse("connect-src scheme: 'none'"); // XXX: these two tests are actually valid according to the CSP spec, but we choose not to // support paths other than path-abempty failsToParse("base-uri abc_"); failsToParse("base-uri abc.."); assertEquals("directive-name, port-part", "base-uri *:12", parseAndShow("base-uri *:12")); failsToParse("base-uri *:ee"); assertEquals("directive-name, path-part", "base-uri */abc", parseAndShow("base-uri */abc")); failsToParse("base-uri *\n"); assertEquals( "directive-name, full host source", "base-uri https://a.com:888/ert", parseAndShow("base-uri https://a.com:888/ert")); // GH-79 should pass assertEquals( "directive-name, host-source *:*", "script-src *:*", parseAndShow("script-src *:*")); assertEquals( "directive-name, host-source a:*", "script-src a:*", parseAndShow("script-src a:*")); assertEquals( "directive-name, host-source http://a:*", "script-src http://a:*", parseAndShow("script-src http://a:*")); // GH-81 should pass assertEquals("optimisation", "", parseAndShow("script-src example.com *")); assertEquals("optimisation", "", parseAndShow("script-src 'self' *")); }
@Test public void testParseMulti() throws ParseException, TokeniserException { List<Policy> pl; ArrayList<Warning> warnings; pl = Parser.parseMulti( "script-src a; script-src b, , script-src c; script-src d", "https://origin.com"); assertEquals(2, pl.size()); assertEquals("script-src a", pl.get(0).show()); assertEquals("script-src c", pl.get(1).show()); pl = Parser.parseMulti("script-src a,", URI.parse("https://origin.com")); assertEquals(2, pl.size()); assertEquals("script-src a", pl.get(0).show()); assertEquals("", pl.get(1).show()); warnings = new ArrayList<>(); pl = Parser.parseMulti("script-src a,", URI.parse("https://origin.com"), warnings); assertEquals(2, pl.size()); assertEquals("script-src a", pl.get(0).show()); assertEquals("", pl.get(1).show()); assertEquals(0, warnings.size()); warnings = new ArrayList<>(); pl = Parser.parseMulti("script-src a, sandbox", "https://origin.com", warnings); assertEquals(2, pl.size()); assertEquals("script-src a", pl.get(0).show()); assertEquals("sandbox", pl.get(1).show()); assertEquals(0, warnings.size()); warnings = new ArrayList<>(); pl = ParserWithLocation.parseMulti( " plugin-types a/b , script-src 'unsafe-redirect'", "https://origin.com", warnings); assertEquals(2, pl.size()); assertEquals("plugin-types a/b", pl.get(0).show()); assertEquals("script-src 'unsafe-redirect'", pl.get(1).show()); assertEquals(1, warnings.size()); assertEquals( "1:36: 'unsafe-redirect' has been removed from CSP as of version 2.0", warnings.get(0).show()); warnings = new ArrayList<>(); pl = ParserWithLocation.parseMulti( "script-src a, frame-src b", URI.parse("https://origin.com"), warnings); assertEquals(2, pl.size()); assertEquals("script-src a", pl.get(0).show()); assertEquals("frame-src b", pl.get(1).show()); assertEquals(1, warnings.size()); assertEquals( "1:15: The frame-src directive is deprecated as of CSP version 1.1. Authors who wish to govern nested browsing contexts SHOULD use the child-src directive instead.", warnings.get(0).show()); try { pl.clear(); pl = Parser.parseMulti("script-src a,b", "https://origin.com"); fail(); } catch (IllegalArgumentException e1) { assertEquals(0, pl.size()); assertEquals("Unrecognised directive name: b", e1.getMessage()); } try { ParserWithLocation.parse( "script-src a, script-src b", "https://origin.com", new ArrayList<>()); fail(); } catch (ParseException e1) { assertEquals(0, pl.size()); assertEquals("1:13: expecting end of policy but found ,", e1.getMessage()); } try { Parser.parse("script-src a, script-src b", "https://origin.com"); fail(); } catch (ParseException e1) { assertEquals(0, pl.size()); assertEquals("expecting end of policy but found ,", e1.getMessage()); } try { pl.clear(); pl = ParserWithLocation.parseMulti("allow 'none', options", "https://origin.com"); fail(); } catch (ParseException e1) { assertEquals(0, pl.size()); assertEquals( "1:1: The allow directive has been replaced with default-src and is not in the CSP specification.", e1.getMessage()); } try { pl.clear(); pl = ParserWithLocation.parseMulti("allow 'none', referrer", URI.parse("https://origin.com")); fail(); } catch (ParseException e1) { assertEquals(0, pl.size()); assertEquals( "1:1: The allow directive has been replaced with default-src and is not in the CSP specification.", e1.getMessage()); } failsToParse("script-src *, "); }
@Test public void testHashSource() throws ParseException, TokeniserException { failsToParse( "script-src 'self' https://example.com 'sha255-K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols'"); failsToParse( "script-src 'self' https://example.com 'sha256-K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols'"); assertEquals( "directive-name, directive-value", "script-src 'self' https://example.com 'sha256-K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols='", parse( "script-src 'self' https://example.com 'sha256-K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols='") .getDirectiveByType(ScriptSrcDirective.class) .show()); assertEquals( "directive-name, directive-value", "script-src 'self' https://example.com 'sha384-QXIS/RyLxYlv79jbWK+CRUXoWw0FRkCTZqMK73Jp+uJYFzvRhfsmLIbzu4b7oENo'", parse( "script-src 'self' https://example.com 'sha384-QXIS/RyLxYlv79jbWK+CRUXoWw0FRkCTZqMK73Jp+uJYFzvRhfsmLIbzu4b7oENo'") .getDirectiveByType(ScriptSrcDirective.class) .show()); assertEquals( "directive-name, directive-value", "script-src 'self' https://example.com 'sha512-vSsar3708Jvp9Szi2NWZZ02Bqp1qRCFpbcTZPdBhnWgs5WtNZKnvCXdhztmeD2cmW192CF5bDufKRpayrW/isg=='", parse( "script-src 'self' https://example.com 'sha512-vSsar3708Jvp9Szi2NWZZ02Bqp1qRCFpbcTZPdBhnWgs5WtNZKnvCXdhztmeD2cmW192CF5bDufKRpayrW/isg=='") .getDirectiveByType(ScriptSrcDirective.class) .show()); Policy p = parse( "script-src 'sha512-vSsar3708Jvp9Szi2NWZZ02Bqp1qRCFpbcTZPdBhnWgs5WtNZKnvCXdhztmeD2cmW192CF5bDufKRpayrW/isg=='"); Policy q = parse( "script-src 'sha512-vSsar3708Jvp9Szi2NWZZ02Bqp1qRCFpbcTZPdBhnWgs5WtNZKnvCXdhztmeD2cmW192CF5bDufKRpayrW/isg=='"); assertEquals("hash-source hashcode equality", p.hashCode(), q.hashCode()); ScriptSrcDirective d = p.getDirectiveByType(ScriptSrcDirective.class); assertTrue("hash-source equals", d.equals(q.getDirectiveByType(ScriptSrcDirective.class))); q = parse( "script-src 'sha512-HD6Xh+Y6oIZnXv4XqbKxrb6t3RkoPYv+NkqOBE8MwkssuATRE2aFBp8Nm9kp/Xn5a4l2Ki8QkX5qIUlbXQgO4Q=='"); assertFalse("hash-source inequality", d.equals(q.getDirectiveByType(ScriptSrcDirective.class))); try { parse("script-src 'sha256-gpw4BEAbByf3D3PUQV4WJADL5Xs='"); fail(); } catch (ParseException e) { assertEquals("Invalid SHA-256 value (wrong length): 20", e.getMessage()); } try { parse("script-src 'sha384-gpw4BEAbByf3D3PUQV4WJADL5Xs='"); fail(); } catch (ParseException e) { assertEquals("Invalid SHA-384 value (wrong length): 20", e.getMessage()); } try { parse("script-src 'sha512-gpw4BEAbByf3D3PUQV4WJADL5Xs='"); fail(); } catch (ParseException e) { assertEquals("Invalid SHA-512 value (wrong length): 20", e.getMessage()); } }