Skip to content

Commit

Permalink
feat: Add support for configuration of XSLT security
Browse files Browse the repository at this point in the history
  • Loading branch information
maths22 authored and flavorjones committed Aug 28, 2022
1 parent dbb228a commit 92fd2fc
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 0 deletions.
9 changes: 9 additions & 0 deletions ext/java/nokogiri/XsltStylesheet.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
1 change: 1 addition & 0 deletions ext/nokogiri/nokogiri.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include <libxslt/extensions.h>
#include <libxslt/xsltconfig.h>
#include <libxslt/xsltutils.h>
#include <libxslt/security.h>
#include <libxslt/transform.h>
#include <libxslt/xsltInternals.h>

Expand Down
24 changes: 24 additions & 0 deletions ext/nokogiri/xslt_stylesheet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand All @@ -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);
}
11 changes: 11 additions & 0 deletions lib/nokogiri/xslt.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# coding: utf-8
# frozen_string_literal: true

require_relative "xslt/security"

module Nokogiri
class << self
###
Expand All @@ -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+
Expand All @@ -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
#
Expand Down
33 changes: 33 additions & 0 deletions lib/nokogiri/xslt/security.rb
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions nokogiri.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
Expand Down
6 changes: 6 additions & 0 deletions test/files/xslt_included.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version='1.0' encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'>
<xsl:output method="text" indent="no" encoding="UTF-8"/>

</xsl:stylesheet>
7 changes: 7 additions & 0 deletions test/files/xslt_including.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'>
<xsl:output method="text" indent="no" encoding="UTF-8"/>

<xsl:include href="./xslt_included.xsl"/>
</xsl:stylesheet>
1 change: 1 addition & 0 deletions test/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
22 changes: 22 additions & 0 deletions test/test_xslt_transforms.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down

0 comments on commit 92fd2fc

Please sign in to comment.