diff --git a/ext/java/nokogiri/XsltStylesheet.java b/ext/java/nokogiri/XsltStylesheet.java index b729696481..64e42e825b 100644 --- a/ext/java/nokogiri/XsltStylesheet.java +++ b/ext/java/nokogiri/XsltStylesheet.java @@ -356,4 +356,13 @@ public class XsltStylesheet extends RubyObject return context.getRuntime().getNil(); */ } + + @JRubyMethod(meta = true, rest = true) + public static IRubyObject + set_default_security_prefs(ThreadContext context, IRubyObject klazz, IRubyObject[] args) + { + // This method is not supported because the Java XML backend does not support the + // security controls supported by the libxml backend + throw context.getRuntime().newNotImplementedError("Nokogiri::XSLT.set_default_security_prefs method is not implemented"); + } } diff --git a/ext/nokogiri/nokogiri.h b/ext/nokogiri/nokogiri.h index 63549ecec5..cfbbedb5d4 100644 --- a/ext/nokogiri/nokogiri.h +++ b/ext/nokogiri/nokogiri.h @@ -49,6 +49,7 @@ #include #include #include +#include #include #include diff --git a/ext/nokogiri/xslt_stylesheet.c b/ext/nokogiri/xslt_stylesheet.c index d81a98124a..0264144767 100644 --- a/ext/nokogiri/xslt_stylesheet.c +++ b/ext/nokogiri/xslt_stylesheet.c @@ -345,6 +345,29 @@ registr(VALUE self, VALUE uri, VALUE obj) return self; } +int +add_sec_pref(VALUE key, VALUE val, VALUE in) +{ + xsltSecurityPrefsPtr xsltPrefs = (xsltSecurityPrefsPtr) in; + if (val == Qtrue) { + xsltSetSecurityPrefs(xsltPrefs, NUM2INT(key), xsltSecurityAllow); + } else if (val == Qfalse) { + xsltSetSecurityPrefs(xsltPrefs, NUM2INT(key), xsltSecurityForbid); + } + + return ST_CONTINUE; +} + +static VALUE +set_default_security_prefs(VALUE self, VALUE prefs) +{ + Check_Type(prefs, T_HASH); + xsltSecurityPrefsPtr xsltPrefs = xsltNewSecurityPrefs(); + rb_hash_foreach(prefs, add_sec_pref, (VALUE)xsltPrefs); + xsltSetDefaultSecurityPrefs(xsltPrefs); + return Qnil; +} + void noko_init_xslt_stylesheet() { @@ -356,6 +379,7 @@ noko_init_xslt_stylesheet() rb_undef_alloc_func(cNokogiriXsltStylesheet); rb_define_singleton_method(cNokogiriXsltStylesheet, "parse_stylesheet_doc", parse_stylesheet_doc, 1); + rb_define_singleton_method(cNokogiriXsltStylesheet, "set_default_security_prefs", set_default_security_prefs, 1); rb_define_method(cNokogiriXsltStylesheet, "serialize", serialize, 1); rb_define_method(cNokogiriXsltStylesheet, "transform", transform, -1); } diff --git a/lib/nokogiri/xslt.rb b/lib/nokogiri/xslt.rb index 77d8ffaa26..2a46edb810 100644 --- a/lib/nokogiri/xslt.rb +++ b/lib/nokogiri/xslt.rb @@ -1,6 +1,8 @@ # coding: utf-8 # frozen_string_literal: true +require_relative "xslt/security" + module Nokogiri class << self ### @@ -19,6 +21,8 @@ def XSLT(stylesheet, modules = {}) # See Nokogiri::XSLT::Stylesheet for creating and manipulating # Stylesheet object. module XSLT + include Nokogiri::XSLT::Security + class << self ### # Parse the stylesheet in +string+, register any +modules+ @@ -35,6 +39,13 @@ def parse(string, modules = {}) end end + ### + # Set the default security options used by libxslt + # +prefs+ should be an object of type Nokogiri::XSLT::Security::Config + def set_default_security_prefs(prefs) + Stylesheet.set_default_security_prefs(Security.keys.map { |k, v| { v => prefs.send(k) } }.reduce(:merge)) + end + # :call-seq: # quote_params(params) → Array # diff --git a/lib/nokogiri/xslt/security.rb b/lib/nokogiri/xslt/security.rb new file mode 100644 index 0000000000..730b11647c --- /dev/null +++ b/lib/nokogiri/xslt/security.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Nokogiri + module XSLT + module Security + class Config + attr_accessor :allow_read_file + attr_accessor :allow_write_file + attr_accessor :allow_create_directory + attr_accessor :allow_read_network + attr_accessor :allow_write_network + + def initialize + @allow_read_file = false + @allow_write_file = false + @allow_create_directory = false + @allow_read_network = false + @allow_write_network = false + end + end + + def self.keys + { + allow_read_file: 1, + allow_write_file: 2, + allow_create_directory: 3, + allow_read_network: 4, + allow_write_network: 5, + } + end + end + end +end diff --git a/nokogiri.gemspec b/nokogiri.gemspec index 77836a5560..9cc62a1d30 100644 --- a/nokogiri.gemspec +++ b/nokogiri.gemspec @@ -310,6 +310,7 @@ Gem::Specification.new do |spec| "lib/nokogiri/xml/xpath/syntax_error.rb", "lib/nokogiri/xml/xpath_context.rb", "lib/nokogiri/xslt.rb", + "lib/nokogiri/xslt/security.rb", "lib/nokogiri/xslt/stylesheet.rb", "lib/xsd/xmlparser/nokogiri.rb", ] diff --git a/test/files/xslt_included.xsl b/test/files/xslt_included.xsl new file mode 100644 index 0000000000..8d32d8df51 --- /dev/null +++ b/test/files/xslt_included.xsl @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/test/files/xslt_including.xsl b/test/files/xslt_including.xsl new file mode 100644 index 0000000000..57d1849663 --- /dev/null +++ b/test/files/xslt_including.xsl @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/test/helper.rb b/test/helper.rb index 002bcd6a50..da06ffa128 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -79,6 +79,7 @@ module TestBase XML_XINCLUDE_FILE = File.join(ASSETS_DIR, "xinclude.xml") XML_ATOM_FILE = File.join(ASSETS_DIR, "atom.xml") XSLT_FILE = File.join(ASSETS_DIR, "staff.xslt") + XSLT_INCLUDING_FILE = File.join(ASSETS_DIR, "xslt_including.xsl") XPATH_FILE = File.join(ASSETS_DIR, "slow-xpath.xml") def i_am_ruby_matching(gem_version_requirement_string) diff --git a/test/test_xslt_transforms.rb b/test/test_xslt_transforms.rb index 6c75b7d15c..51383f6333 100644 --- a/test/test_xslt_transforms.rb +++ b/test/test_xslt_transforms.rb @@ -187,6 +187,28 @@ def test_transform_with_quote_params assert_equal("Booyah", result_doc.at_css("h1").content) end + def test_set_default_security_prefs + sec_prefs = Nokogiri::XSLT::Security::Config.new + + if Nokogiri.jruby? + assert_raises(NotImplementedError) do + Nokogiri::XSLT.set_default_security_prefs(sec_prefs) + end + else + # Default should be secure + Nokogiri::XSLT.set_default_security_prefs(sec_prefs) + assert_raises(RuntimeError) { Nokogiri::XSLT(File.open(XSLT_INCLUDING_FILE)) } + + sec_prefs.allow_read_file = true + Nokogiri::XSLT.set_default_security_prefs(sec_prefs) + assert(doc = Nokogiri::XSLT(File.open(XSLT_INCLUDING_FILE))) + + sec_prefs.allow_read_file = false + Nokogiri::XSLT.set_default_security_prefs(sec_prefs) + assert_raises(RuntimeError) { Nokogiri::XSLT(File.open(XSLT_INCLUDING_FILE)) } + end + end + def test_exslt # see http://yokolet.blogspot.com/2010/10/pure-java-nokogiri-xslt-extension.html") skip_unless_libxml2("cannot get it working on JRuby")