ruby-saml 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ruby-saml might be problematic. Click here for more details.
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/lib/onelogin/saml.rb +1 -0
- data/lib/onelogin/saml/response.rb +54 -19
- data/lib/onelogin/saml/validation_error.rb +7 -0
- data/lib/xml_security.rb +35 -21
- data/ruby-saml.gemspec +15 -4
- data/test/request_test.rb +33 -0
- data/test/{ruby-saml_test.rb → response_test.rb} +34 -56
- data/test/responses/adfs_response.xml.base64 +91 -0
- data/test/responses/open_saml_response.xml +56 -0
- data/test/responses/simple_saml_php.xml +71 -0
- data/test/settings_test.rb +23 -0
- data/test/test_helper.rb +10 -0
- data/test/xml_security_test.rb +1 -1
- metadata +29 -7
    
        data/Rakefile
    CHANGED
    
    | @@ -13,6 +13,7 @@ begin | |
| 13 13 | 
             
                gem.add_dependency("canonix","~> 0.1")
         | 
| 14 14 | 
             
                gem.add_dependency("uuid","~> 2.3")
         | 
| 15 15 | 
             
                gem.add_development_dependency "shoulda"
         | 
| 16 | 
            +
                gem.add_development_dependency "ruby-debug"
         | 
| 16 17 | 
             
                gem.add_development_dependency "mocha"
         | 
| 17 18 | 
             
                #gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
         | 
| 18 19 | 
             
              end
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0.4. | 
| 1 | 
            +
            0.4.6
         | 
    
        data/lib/onelogin/saml.rb
    CHANGED
    
    
| @@ -2,48 +2,38 @@ require "xml_security" | |
| 2 2 | 
             
            require "time"
         | 
| 3 3 |  | 
| 4 4 | 
             
            module Onelogin::Saml
         | 
| 5 | 
            +
             | 
| 5 6 | 
             
              class Response
         | 
| 6 7 | 
             
                ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
         | 
| 7 8 | 
             
                PROTOCOL  = "urn:oasis:names:tc:SAML:2.0:protocol"
         | 
| 8 9 | 
             
                DSIG      = "http://www.w3.org/2000/09/xmldsig#"
         | 
| 9 10 |  | 
| 10 | 
            -
                attr_accessor : | 
| 11 | 
            +
                attr_accessor :options, :response, :document, :settings
         | 
| 11 12 |  | 
| 12 | 
            -
                def initialize(response)
         | 
| 13 | 
            +
                def initialize(response, options = {})
         | 
| 13 14 | 
             
                  raise ArgumentError.new("Response cannot be nil") if response.nil?
         | 
| 15 | 
            +
                  self.options  = options
         | 
| 14 16 | 
             
                  self.response = response
         | 
| 15 17 | 
             
                  self.document = XMLSecurity::SignedDocument.new(Base64.decode64(response))
         | 
| 16 18 | 
             
                end
         | 
| 17 19 |  | 
| 18 20 | 
             
                def is_valid?
         | 
| 19 | 
            -
                   | 
| 20 | 
            -
             | 
| 21 | 
            -
                  return false if settings.idp_cert_fingerprint.nil?
         | 
| 22 | 
            -
                  return false if !check_conditions
         | 
| 21 | 
            +
                  validate(soft = true)
         | 
| 22 | 
            +
                end
         | 
| 23 23 |  | 
| 24 | 
            -
             | 
| 24 | 
            +
                def validate!
         | 
| 25 | 
            +
                  validate(soft = false)
         | 
| 25 26 | 
             
                end
         | 
| 26 27 |  | 
| 27 28 | 
             
                # The value of the user identifier as designated by the initialization request response
         | 
| 28 29 | 
             
                def name_id
         | 
| 29 30 | 
             
                  @name_id ||= begin
         | 
| 30 31 | 
             
                    node = REXML::XPath.first(document, "/p:Response/a:Assertion[@ID='#{document.signed_element_id[1,document.signed_element_id.size]}']/a:Subject/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
         | 
| 32 | 
            +
                    node ||=  REXML::XPath.first(document, "/p:Response[@ID='#{document.signed_element_id[1,document.signed_element_id.size]}']/a:Assertion/a:Subject/a:NameID", { "p" => PROTOCOL, "a" => ASSERTION })
         | 
| 31 33 | 
             
                    node.nil? ? nil : node.text
         | 
| 32 34 | 
             
                  end
         | 
| 33 35 | 
             
                end
         | 
| 34 36 |  | 
| 35 | 
            -
                def check_conditions
         | 
| 36 | 
            -
                  return true if conditions.nil?
         | 
| 37 | 
            -
             | 
| 38 | 
            -
                  not_before = parse_time(conditions, "NotBefore")
         | 
| 39 | 
            -
                  return false if not_before && Time.now.utc < not_before
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                  not_on_or_after = parse_time(conditions, "NotOnOrAfter")
         | 
| 42 | 
            -
                  return false if not_on_or_after && Time.now.utc >= not_on_or_after
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                  true
         | 
| 45 | 
            -
                end
         | 
| 46 | 
            -
             | 
| 47 37 | 
             
                # A hash of alle the attributes with the response. Assuming there is only one value for each key
         | 
| 48 38 | 
             
                def attributes
         | 
| 49 39 | 
             
                  @attr_statements ||= begin
         | 
| @@ -84,6 +74,51 @@ module Onelogin::Saml | |
| 84 74 |  | 
| 85 75 | 
             
                private
         | 
| 86 76 |  | 
| 77 | 
            +
                def validation_error(message)
         | 
| 78 | 
            +
                  raise ValidationError.new(message)
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                def validate(soft = true)
         | 
| 82 | 
            +
                  validate_response_state(soft) &&
         | 
| 83 | 
            +
                  validate_conditions(soft)     &&
         | 
| 84 | 
            +
                  document.validate(settings.idp_cert_fingerprint, soft)
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                def validate_response_state(soft = true)
         | 
| 88 | 
            +
                  if response.empty?
         | 
| 89 | 
            +
                    return soft ? false : validation_error("Blank response")
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  if settings.nil?
         | 
| 93 | 
            +
                    return soft ? false : validation_error("No settings on response")
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  if settings.idp_cert_fingerprint.nil?
         | 
| 97 | 
            +
                    return soft ? false : validation_error("No fingerprint on settings")
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  true
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                def validate_conditions(soft = true)
         | 
| 104 | 
            +
                  return true if conditions.nil?
         | 
| 105 | 
            +
                  return true if options[:skip_conditions]
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  if not_before = parse_time(conditions, "NotBefore")
         | 
| 108 | 
            +
                    if Time.now.utc < not_before
         | 
| 109 | 
            +
                      return soft ? false : validation_error("Current time is earlier than NotBefore condition")
         | 
| 110 | 
            +
                    end
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  if not_on_or_after = parse_time(conditions, "NotOnOrAfter")
         | 
| 114 | 
            +
                    if Time.now.utc >= not_on_or_after
         | 
| 115 | 
            +
                      return soft ? false : validation_error("Current time is on or after NotOnOrAfter condition")
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                  true
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 87 122 | 
             
                def parse_time(node, attribute)
         | 
| 88 123 | 
             
                  if node && node.attributes[attribute]
         | 
| 89 124 | 
             
                    Time.parse(node.attributes[attribute])
         | 
    
        data/lib/xml_security.rb
    CHANGED
    
    | @@ -28,11 +28,12 @@ require "rexml/xpath" | |
| 28 28 | 
             
            require "openssl"
         | 
| 29 29 | 
             
            require "xmlcanonicalizer"
         | 
| 30 30 | 
             
            require "digest/sha1"
         | 
| 31 | 
            +
            require "onelogin/saml/validation_error"
         | 
| 31 32 |  | 
| 32 33 | 
             
            module XMLSecurity
         | 
| 33 34 |  | 
| 34 35 | 
             
              class SignedDocument < REXML::Document
         | 
| 35 | 
            -
                DSIG | 
| 36 | 
            +
                DSIG = "http://www.w3.org/2000/09/xmldsig#"
         | 
| 36 37 |  | 
| 37 38 | 
             
                attr_accessor :signed_element_id
         | 
| 38 39 |  | 
| @@ -41,7 +42,7 @@ module XMLSecurity | |
| 41 42 | 
             
                  extract_signed_element_id
         | 
| 42 43 | 
             
                end
         | 
| 43 44 |  | 
| 44 | 
            -
                def validate | 
| 45 | 
            +
                def validate(idp_cert_fingerprint, soft = true)
         | 
| 45 46 | 
             
                  # get cert from response
         | 
| 46 47 | 
             
                  base64_cert = self.elements["//ds:X509Certificate"].text
         | 
| 47 48 | 
             
                  cert_text   = Base64.decode64(base64_cert)
         | 
| @@ -49,33 +50,44 @@ module XMLSecurity | |
| 49 50 |  | 
| 50 51 | 
             
                  # check cert matches registered idp cert
         | 
| 51 52 | 
             
                  fingerprint = Digest::SHA1.hexdigest(cert.to_der)
         | 
| 52 | 
            -
                  valid_flag  = fingerprint == idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
         | 
| 53 53 |  | 
| 54 | 
            -
                   | 
| 54 | 
            +
                  if fingerprint != idp_cert_fingerprint.gsub(/[^a-zA-Z0-9]/,"").downcase
         | 
| 55 | 
            +
                    return soft ? false : (raise Onelogin::Saml::ValidationError.new("Fingerprint mismatch"))
         | 
| 56 | 
            +
                  end
         | 
| 55 57 |  | 
| 56 | 
            -
                  validate_doc(base64_cert,  | 
| 58 | 
            +
                  validate_doc(base64_cert, soft)
         | 
| 57 59 | 
             
                end
         | 
| 58 60 |  | 
| 59 | 
            -
                def validate_doc(base64_cert,  | 
| 61 | 
            +
                def validate_doc(base64_cert, soft = true)
         | 
| 60 62 | 
             
                  # validate references
         | 
| 63 | 
            +
                  
         | 
| 64 | 
            +
                  # check for inclusive namespaces
         | 
| 65 | 
            +
                  
         | 
| 66 | 
            +
                  inclusive_namespaces            = []
         | 
| 67 | 
            +
                  inclusive_namespace_element     = REXML::XPath.first(self, "//ec:InclusiveNamespaces")
         | 
| 68 | 
            +
                  
         | 
| 69 | 
            +
                  if inclusive_namespace_element
         | 
| 70 | 
            +
                    prefix_list                   = inclusive_namespace_element.attributes.get_attribute('PrefixList').value
         | 
| 71 | 
            +
                    inclusive_namespaces          = prefix_list.split(" ")
         | 
| 72 | 
            +
                  end
         | 
| 61 73 |  | 
| 62 74 | 
             
                  # remove signature node
         | 
| 63 75 | 
             
                  sig_element = REXML::XPath.first(self, "//ds:Signature", {"ds"=>"http://www.w3.org/2000/09/xmldsig#"})
         | 
| 64 76 | 
             
                  sig_element.remove
         | 
| 65 77 |  | 
| 66 | 
            -
                  #check digests
         | 
| 67 | 
            -
                  REXML::XPath.each(sig_element, "//ds:Reference", {"ds"=>"http://www.w3.org/2000/09/xmldsig#"}) do | | 
| 68 | 
            -
             | 
| 69 | 
            -
                     | 
| 70 | 
            -
                     | 
| 71 | 
            -
                    canoner | 
| 72 | 
            -
                    canon_hashed_element | 
| 73 | 
            -
                    hash | 
| 74 | 
            -
                    digest_value | 
| 75 | 
            -
             | 
| 76 | 
            -
                     | 
| 77 | 
            -
             | 
| 78 | 
            -
                     | 
| 78 | 
            +
                  # check digests
         | 
| 79 | 
            +
                  REXML::XPath.each(sig_element, "//ds:Reference", {"ds"=>"http://www.w3.org/2000/09/xmldsig#"}) do |ref|
         | 
| 80 | 
            +
                    uri                           = ref.attributes.get_attribute("URI").value
         | 
| 81 | 
            +
                    hashed_element                = REXML::XPath.first(self, "//[@ID='#{uri[1,uri.size]}']")
         | 
| 82 | 
            +
                    canoner                       = XML::Util::XmlCanonicalizer.new(false, true)
         | 
| 83 | 
            +
                    canoner.inclusive_namespaces  = inclusive_namespaces if canoner.respond_to?(:inclusive_namespaces) && !inclusive_namespaces.empty?
         | 
| 84 | 
            +
                    canon_hashed_element          = canoner.canonicalize(hashed_element)
         | 
| 85 | 
            +
                    hash                          = Base64.encode64(Digest::SHA1.digest(canon_hashed_element)).chomp
         | 
| 86 | 
            +
                    digest_value                  = REXML::XPath.first(ref, "//ds:DigestValue", {"ds"=>"http://www.w3.org/2000/09/xmldsig#"}).text
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    if hash != digest_value
         | 
| 89 | 
            +
                      return soft ? false : (raise Onelogin::Saml::ValidationError.new("Digest mismatch"))
         | 
| 90 | 
            +
                    end
         | 
| 79 91 | 
             
                  end
         | 
| 80 92 |  | 
| 81 93 | 
             
                  # verify signature
         | 
| @@ -90,9 +102,11 @@ module XMLSecurity | |
| 90 102 | 
             
                  cert_text               = Base64.decode64(base64_cert)
         | 
| 91 103 | 
             
                  cert                    = OpenSSL::X509::Certificate.new(cert_text)
         | 
| 92 104 |  | 
| 93 | 
            -
                   | 
| 105 | 
            +
                  if !cert.public_key.verify(OpenSSL::Digest::SHA1.new, signature, canon_string)
         | 
| 106 | 
            +
                    return soft ? false : (raise ValidationError.new("Key validation error"))
         | 
| 107 | 
            +
                  end
         | 
| 94 108 |  | 
| 95 | 
            -
                  return  | 
| 109 | 
            +
                  return true
         | 
| 96 110 | 
             
                end
         | 
| 97 111 |  | 
| 98 112 | 
             
                private
         | 
    
        data/ruby-saml.gemspec
    CHANGED
    
    | @@ -5,11 +5,11 @@ | |
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |s|
         | 
| 7 7 | 
             
              s.name = %q{ruby-saml}
         | 
| 8 | 
            -
              s.version = "0.4. | 
| 8 | 
            +
              s.version = "0.4.6"
         | 
| 9 9 |  | 
| 10 10 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 11 | 
             
              s.authors = ["OneLogin LLC"]
         | 
| 12 | 
            -
              s.date = %q{2011-06- | 
| 12 | 
            +
              s.date = %q{2011-06-28}
         | 
| 13 13 | 
             
              s.description = %q{SAML toolkit for Ruby on Rails}
         | 
| 14 14 | 
             
              s.email = %q{support@onelogin.com}
         | 
| 15 15 | 
             
              s.extra_rdoc_files = [
         | 
| @@ -27,16 +27,22 @@ Gem::Specification.new do |s| | |
| 27 27 | 
             
                 "lib/onelogin/saml/authrequest.rb",
         | 
| 28 28 | 
             
                 "lib/onelogin/saml/response.rb",
         | 
| 29 29 | 
             
                 "lib/onelogin/saml/settings.rb",
         | 
| 30 | 
            +
                 "lib/onelogin/saml/validation_error.rb",
         | 
| 30 31 | 
             
                 "lib/ruby-saml.rb",
         | 
| 31 32 | 
             
                 "lib/xml_security.rb",
         | 
| 32 33 | 
             
                 "ruby-saml.gemspec",
         | 
| 34 | 
            +
                 "test/request_test.rb",
         | 
| 35 | 
            +
                 "test/response_test.rb",
         | 
| 36 | 
            +
                 "test/responses/adfs_response.xml.base64",
         | 
| 33 37 | 
             
                 "test/responses/certificate1",
         | 
| 38 | 
            +
                 "test/responses/open_saml_response.xml",
         | 
| 34 39 | 
             
                 "test/responses/response1.xml.base64",
         | 
| 35 40 | 
             
                 "test/responses/response2.xml.base64",
         | 
| 36 41 | 
             
                 "test/responses/response3.xml.base64",
         | 
| 37 42 | 
             
                 "test/responses/response4.xml.base64",
         | 
| 38 43 | 
             
                 "test/responses/response5.xml.base64",
         | 
| 39 | 
            -
                 "test/ | 
| 44 | 
            +
                 "test/responses/simple_saml_php.xml",
         | 
| 45 | 
            +
                 "test/settings_test.rb",
         | 
| 40 46 | 
             
                 "test/test_helper.rb",
         | 
| 41 47 | 
             
                 "test/xml_security_test.rb"
         | 
| 42 48 | 
             
              ]
         | 
| @@ -46,7 +52,9 @@ Gem::Specification.new do |s| | |
| 46 52 | 
             
              s.rubygems_version = %q{1.3.7}
         | 
| 47 53 | 
             
              s.summary = %q{SAML Ruby Tookit}
         | 
| 48 54 | 
             
              s.test_files = [
         | 
| 49 | 
            -
                "test/ | 
| 55 | 
            +
                "test/request_test.rb",
         | 
| 56 | 
            +
                 "test/response_test.rb",
         | 
| 57 | 
            +
                 "test/settings_test.rb",
         | 
| 50 58 | 
             
                 "test/test_helper.rb",
         | 
| 51 59 | 
             
                 "test/xml_security_test.rb"
         | 
| 52 60 | 
             
              ]
         | 
| @@ -59,17 +67,20 @@ Gem::Specification.new do |s| | |
| 59 67 | 
             
                  s.add_runtime_dependency(%q<canonix>, ["~> 0.1"])
         | 
| 60 68 | 
             
                  s.add_runtime_dependency(%q<uuid>, ["~> 2.3"])
         | 
| 61 69 | 
             
                  s.add_development_dependency(%q<shoulda>, [">= 0"])
         | 
| 70 | 
            +
                  s.add_development_dependency(%q<ruby-debug>, [">= 0"])
         | 
| 62 71 | 
             
                  s.add_development_dependency(%q<mocha>, [">= 0"])
         | 
| 63 72 | 
             
                else
         | 
| 64 73 | 
             
                  s.add_dependency(%q<canonix>, ["~> 0.1"])
         | 
| 65 74 | 
             
                  s.add_dependency(%q<uuid>, ["~> 2.3"])
         | 
| 66 75 | 
             
                  s.add_dependency(%q<shoulda>, [">= 0"])
         | 
| 76 | 
            +
                  s.add_dependency(%q<ruby-debug>, [">= 0"])
         | 
| 67 77 | 
             
                  s.add_dependency(%q<mocha>, [">= 0"])
         | 
| 68 78 | 
             
                end
         | 
| 69 79 | 
             
              else
         | 
| 70 80 | 
             
                s.add_dependency(%q<canonix>, ["~> 0.1"])
         | 
| 71 81 | 
             
                s.add_dependency(%q<uuid>, ["~> 2.3"])
         | 
| 72 82 | 
             
                s.add_dependency(%q<shoulda>, [">= 0"])
         | 
| 83 | 
            +
                s.add_dependency(%q<ruby-debug>, [">= 0"])
         | 
| 73 84 | 
             
                s.add_dependency(%q<mocha>, [">= 0"])
         | 
| 74 85 | 
             
              end
         | 
| 75 86 | 
             
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class RequestTest < Test::Unit::TestCase
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              context "Authrequest" do
         | 
| 6 | 
            +
                should "create the deflated SAMLRequest URL parameter" do
         | 
| 7 | 
            +
                  settings = Onelogin::Saml::Settings.new
         | 
| 8 | 
            +
                  settings.idp_sso_target_url = "http://stuff.com"
         | 
| 9 | 
            +
                  auth_url = Onelogin::Saml::Authrequest.new.create(settings)
         | 
| 10 | 
            +
                  assert auth_url =~ /^http:\/\/stuff\.com\?SAMLRequest=/
         | 
| 11 | 
            +
                  payload  = CGI.unescape(auth_url.split("=").last)
         | 
| 12 | 
            +
                  decoded  = Base64.decode64(payload)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  zstream  = Zlib::Inflate.new(-Zlib::MAX_WBITS)
         | 
| 15 | 
            +
                  inflated = zstream.inflate(decoded)
         | 
| 16 | 
            +
                  zstream.finish
         | 
| 17 | 
            +
                  zstream.close
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  assert_match /^<samlp:AuthnRequest/, inflated
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                should "accept extra parameters" do
         | 
| 23 | 
            +
                  settings = Onelogin::Saml::Settings.new
         | 
| 24 | 
            +
                  settings.idp_sso_target_url = "http://stuff.com"
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  auth_url = Onelogin::Saml::Authrequest.new.create(settings, { :hello => "there" })
         | 
| 27 | 
            +
                  assert auth_url =~ /&hello=there$/
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  auth_url = Onelogin::Saml::Authrequest.new.create(settings, { :hello => nil })
         | 
| 30 | 
            +
                  assert auth_url =~ /&hello=$/
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -2,30 +2,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper")) | |
| 2 2 |  | 
| 3 3 | 
             
            class RubySamlTest < Test::Unit::TestCase
         | 
| 4 4 |  | 
| 5 | 
            -
              context "Settings" do
         | 
| 6 | 
            -
                setup do
         | 
| 7 | 
            -
                  @settings = Onelogin::Saml::Settings.new
         | 
| 8 | 
            -
                end
         | 
| 9 | 
            -
                should "should provide getters and settings" do
         | 
| 10 | 
            -
                  accessors = [
         | 
| 11 | 
            -
                    :assertion_consumer_service_url, :issuer, :sp_name_qualifier, :sp_name_qualifier,
         | 
| 12 | 
            -
                    :idp_sso_target_url, :idp_cert_fingerprint, :name_identifier_format
         | 
| 13 | 
            -
                  ]
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  accessors.each do |accessor|
         | 
| 16 | 
            -
                    value = Kernel.rand
         | 
| 17 | 
            -
                    @settings.send("#{accessor}=".to_sym, value)
         | 
| 18 | 
            -
                    assert_equal value, @settings.send(accessor)
         | 
| 19 | 
            -
                  end
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
              end
         | 
| 22 | 
            -
             | 
| 23 5 | 
             
              context "Response" do
         | 
| 24 | 
            -
                should "provide setter for a logger" do
         | 
| 25 | 
            -
                  response = Onelogin::Saml::Response.new('')
         | 
| 26 | 
            -
                  assert response.logger = 'hello'
         | 
| 27 | 
            -
                end
         | 
| 28 | 
            -
             | 
| 29 6 | 
             
                should "raise an exception when response is initialized with nil" do
         | 
| 30 7 | 
             
                  assert_raises(ArgumentError) { Onelogin::Saml::Response.new(nil) }
         | 
| 31 8 | 
             
                end
         | 
| @@ -39,6 +16,15 @@ class RubySamlTest < Test::Unit::TestCase | |
| 39 16 | 
             
                  assert !response.name_id.nil?
         | 
| 40 17 | 
             
                end
         | 
| 41 18 |  | 
| 19 | 
            +
                context "#validate!" do
         | 
| 20 | 
            +
                  should "raise when encountering a condition that prevents the document from being valid" do
         | 
| 21 | 
            +
                    response = Onelogin::Saml::Response.new(response_document)
         | 
| 22 | 
            +
                    assert_raise(Onelogin::Saml::ValidationError) do
         | 
| 23 | 
            +
                      response.validate!
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 42 28 | 
             
                context "#is_valid?" do
         | 
| 43 29 | 
             
                  should "return false when response is initialized with blank data" do
         | 
| 44 30 | 
             
                    response = Onelogin::Saml::Response.new('')
         | 
| @@ -52,7 +38,7 @@ class RubySamlTest < Test::Unit::TestCase | |
| 52 38 |  | 
| 53 39 | 
             
                  should "return true when the response is initialized with valid data" do
         | 
| 54 40 | 
             
                    response = Onelogin::Saml::Response.new(response_document_4)
         | 
| 55 | 
            -
                    response. | 
| 41 | 
            +
                    response.stubs(:conditions).returns(nil)
         | 
| 56 42 | 
             
                    assert !response.is_valid?
         | 
| 57 43 | 
             
                    settings = Onelogin::Saml::Settings.new
         | 
| 58 44 | 
             
                    assert !response.is_valid?
         | 
| @@ -64,13 +50,22 @@ class RubySamlTest < Test::Unit::TestCase | |
| 64 50 |  | 
| 65 51 | 
             
                  should "not allow signature wrapping attack" do
         | 
| 66 52 | 
             
                    response = Onelogin::Saml::Response.new(response_document_4)
         | 
| 67 | 
            -
                    response. | 
| 53 | 
            +
                    response.stubs(:conditions).returns(nil)
         | 
| 68 54 | 
             
                    settings = Onelogin::Saml::Settings.new
         | 
| 69 55 | 
             
                    settings.idp_cert_fingerprint = signature_fingerprint_1
         | 
| 70 56 | 
             
                    response.settings = settings
         | 
| 71 57 | 
             
                    assert response.is_valid?
         | 
| 72 58 | 
             
                    assert response.name_id == "test@onelogin.com"
         | 
| 73 59 | 
             
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  should_eventually "validate ADFS assertions" do
         | 
| 62 | 
            +
                    response = Onelogin::Saml::Response.new(fixture(:adfs_response))
         | 
| 63 | 
            +
                    response.stubs(:conditions).returns(nil)
         | 
| 64 | 
            +
                    settings = Onelogin::Saml::Settings.new
         | 
| 65 | 
            +
                    settings.idp_cert_fingerprint = "17:54:07:27:53:55:D1:93:67:A4:95:0A:6A:E4:D6:1E:FA:4A:94:1D"
         | 
| 66 | 
            +
                    response.settings = settings
         | 
| 67 | 
            +
                    assert response.validate!
         | 
| 68 | 
            +
                  end
         | 
| 74 69 | 
             
                end
         | 
| 75 70 |  | 
| 76 71 | 
             
                context "#name_id" do
         | 
| @@ -81,18 +76,28 @@ class RubySamlTest < Test::Unit::TestCase | |
| 81 76 | 
             
                    response = Onelogin::Saml::Response.new(response_document_3)
         | 
| 82 77 | 
             
                    assert_equal "someone@example.com", response.name_id
         | 
| 83 78 | 
             
                  end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  should_eventually "be extractable from an OpenSAML response" do
         | 
| 81 | 
            +
                    response = Onelogin::Saml::Response.new(fixture(:open_saml))
         | 
| 82 | 
            +
                    assert_equal "someone@example.org", response.name_id
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  should_eventually "be extractable from a Simple SAML PHP response" do
         | 
| 86 | 
            +
                    response = Onelogin::Saml::Response.new(fixture(:simple_saml_php))
         | 
| 87 | 
            +
                    assert_equal "someone@example.com", response.name_id
         | 
| 88 | 
            +
                  end
         | 
| 84 89 | 
             
                end
         | 
| 85 90 |  | 
| 86 91 | 
             
                context "#check_conditions" do
         | 
| 87 92 | 
             
                  should "check time conditions" do
         | 
| 88 93 | 
             
                    response = Onelogin::Saml::Response.new(response_document)
         | 
| 89 | 
            -
                    assert !response. | 
| 94 | 
            +
                    assert !response.send(:validate_conditions, true)
         | 
| 90 95 | 
             
                    response = Onelogin::Saml::Response.new(response_document_6)
         | 
| 91 | 
            -
                    assert response. | 
| 96 | 
            +
                    assert response.send(:validate_conditions, true)
         | 
| 92 97 | 
             
                    time     = Time.parse("2011-06-14T18:25:01.516Z")
         | 
| 93 98 | 
             
                    Time.stubs(:now).returns(time)
         | 
| 94 99 | 
             
                    response = Onelogin::Saml::Response.new(response_document_5)
         | 
| 95 | 
            -
                    assert response. | 
| 100 | 
            +
                    assert response.send(:validate_conditions, true)
         | 
| 96 101 | 
             
                  end
         | 
| 97 102 | 
             
                end
         | 
| 98 103 |  | 
| @@ -133,34 +138,7 @@ class RubySamlTest < Test::Unit::TestCase | |
| 133 138 | 
             
                    assert response.session_expires_at.nil?
         | 
| 134 139 | 
             
                  end
         | 
| 135 140 | 
             
                end
         | 
| 136 | 
            -
              end
         | 
| 137 | 
            -
             | 
| 138 | 
            -
              context "Authrequest" do
         | 
| 139 | 
            -
                should "create the deflated SAMLRequest URL parameter" do
         | 
| 140 | 
            -
                  settings = Onelogin::Saml::Settings.new
         | 
| 141 | 
            -
                  settings.idp_sso_target_url = "http://stuff.com"
         | 
| 142 | 
            -
                  auth_url = Onelogin::Saml::Authrequest.new.create(settings)
         | 
| 143 | 
            -
                  assert auth_url =~ /^http:\/\/stuff\.com\?SAMLRequest=/
         | 
| 144 | 
            -
                  payload  = CGI.unescape(auth_url.split("=").last)
         | 
| 145 | 
            -
                  decoded  = Base64.decode64(payload)
         | 
| 146 | 
            -
             | 
| 147 | 
            -
                  zstream  = Zlib::Inflate.new(-Zlib::MAX_WBITS)
         | 
| 148 | 
            -
                  inflated = zstream.inflate(decoded)
         | 
| 149 | 
            -
                  zstream.finish
         | 
| 150 | 
            -
                  zstream.close
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                  assert_match /^<samlp:AuthnRequest/, inflated
         | 
| 153 | 
            -
                end
         | 
| 154 | 
            -
             | 
| 155 | 
            -
                should "accept extra parameters" do
         | 
| 156 | 
            -
                  settings = Onelogin::Saml::Settings.new
         | 
| 157 | 
            -
                  settings.idp_sso_target_url = "http://stuff.com"
         | 
| 158 141 |  | 
| 159 | 
            -
                  auth_url = Onelogin::Saml::Authrequest.new.create(settings, { :hello => "there" })
         | 
| 160 | 
            -
                  assert auth_url =~ /&hello=there$/
         | 
| 161 | 
            -
             | 
| 162 | 
            -
                  auth_url = Onelogin::Saml::Authrequest.new.create(settings, { :hello => nil })
         | 
| 163 | 
            -
                  assert auth_url =~ /&hello=$/
         | 
| 164 | 
            -
                end
         | 
| 165 142 | 
             
              end
         | 
| 143 | 
            +
             | 
| 166 144 | 
             
            end
         | 
| @@ -0,0 +1,91 @@ | |
| 1 | 
            +
            PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzYW1scDpSZXNwb25zZSB4bWxuczpz
         | 
| 2 | 
            +
            YW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBJ
         | 
| 3 | 
            +
            RD0iXzAyNjNhMDdiLTIwNWYtNDc5Yy05MGZjLTc0OTU3MTVlY2JiZiIgVmVy
         | 
| 4 | 
            +
            c2lvbj0iMi4wIiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDYtMjJUMTI6NDk6MzAu
         | 
| 5 | 
            +
            MzQ4WiIgRGVzdGluYXRpb249Imh0dHBzOi8vc29tZW9uZS5leGFtcGxlLmNv
         | 
| 6 | 
            +
            bS9lbmRwb2ludCIgQ29uc2VudD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6
         | 
| 7 | 
            +
            Mi4wOmNvbnNlbnQ6dW5zcGVjaWZpZWQiIEluUmVzcG9uc2VUbz0iX2ZjNGEz
         | 
| 8 | 
            +
            NGIwLTdlZmItMDEyZS1jYWFlLTc4MmJjYjEzYmIzOCI+CiAgPElzc3VlciB4
         | 
| 9 | 
            +
            bWxucz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI+
         | 
| 10 | 
            +
            aHR0cDovL2xvZ2luLmV4YW1wbGUuY29tL2lzc3VlcjwvSXNzdWVyPgogIDxz
         | 
| 11 | 
            +
            YW1scDpTdGF0dXM+CiAgICA8c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJu
         | 
| 12 | 
            +
            Om9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+CiAg
         | 
| 13 | 
            +
            PC9zYW1scDpTdGF0dXM+CiAgPEFzc2VydGlvbiB4bWxucz0idXJuOm9hc2lz
         | 
| 14 | 
            +
            Om5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgSUQ9Il83MjFiNGE1YS1k
         | 
| 15 | 
            +
            N2UxLTQ4NjEtOTc1NC1hOWIxOTdiNmY5YWIiIElzc3VlSW5zdGFudD0iMjAx
         | 
| 16 | 
            +
            MS0wNi0yMlQxMjo0OTozMC4zNDhaIiBWZXJzaW9uPSIyLjAiPgogICAgPElz
         | 
| 17 | 
            +
            c3Vlcj5odHRwOi8vbG9naW4uZXhhbXBsZS5jb20vaXNzdWVyPC9Jc3N1ZXI+
         | 
| 18 | 
            +
            CiAgICA8ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9y
         | 
| 19 | 
            +
            Zy8yMDAwLzA5L3htbGRzaWcjIj4KICAgICAgPGRzOlNpZ25lZEluZm8+CiAg
         | 
| 20 | 
            +
            ICAgICAgPGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJo
         | 
| 21 | 
            +
            dHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz4KICAg
         | 
| 22 | 
            +
            ICAgICA8ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3
         | 
| 23 | 
            +
            dy53My5vcmcvMjAwMS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1NiIvPgog
         | 
| 24 | 
            +
            ICAgICAgIDxkczpSZWZlcmVuY2UgVVJJPSIjXzcyMWI0YTVhLWQ3ZTEtNDg2
         | 
| 25 | 
            +
            MS05NzU0LWE5YjE5N2I2ZjlhYiI+CiAgICAgICAgICA8ZHM6VHJhbnNmb3Jt
         | 
| 26 | 
            +
            cz4KICAgICAgICAgICAgPGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6
         | 
| 27 | 
            +
            Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0
         | 
| 28 | 
            +
            dXJlIi8+CiAgICAgICAgICAgIDxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJo
         | 
| 29 | 
            +
            dHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz4KICAg
         | 
| 30 | 
            +
            ICAgICAgIDwvZHM6VHJhbnNmb3Jtcz4KICAgICAgICAgIDxkczpEaWdlc3RN
         | 
| 31 | 
            +
            ZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3ht
         | 
| 32 | 
            +
            bGVuYyNzaGEyNTYiLz4KICAgICAgICAgIDxkczpEaWdlc3RWYWx1ZT52NTN3
         | 
| 33 | 
            +
            cW80ZllESzhVY3JPVWNPV2cyemxKL2NIVnVtWVMwS2pycm5WdUprPTwvZHM6
         | 
| 34 | 
            +
            RGlnZXN0VmFsdWU+CiAgICAgICAgPC9kczpSZWZlcmVuY2U+CiAgICAgIDwv
         | 
| 35 | 
            +
            ZHM6U2lnbmVkSW5mbz4KICAgICAgPGRzOlNpZ25hdHVyZVZhbHVlPlowOXBl
         | 
| 36 | 
            +
            d1k3ekZ2OTFobjkwbHgwRUVubE1HTkw5elVKWk14SVI2cW9mTFpPWk1sVG5Y
         | 
| 37 | 
            +
            TjV6RnNmKzFYUFBJWVpMdzVsQ0dqanRtZE5seGR2NzJ6TkZsTVROUnFaN0lp
         | 
| 38 | 
            +
            SXd2azVHUk0zenZBV3NOT1k2ZEI0YzVxamU0UkhxL2ZySkdCZ04vZ2VWeFZt
         | 
| 39 | 
            +
            bjNMWmQ1WmNrdWh1UzFzN0ZKQW9MVWNaRUxKL25jZ1JEZGdqQUUrcjhHdGFO
         | 
| 40 | 
            +
            a3U0VVRCUkdBZnRsMFBXbUFTMDdsbGU2bGFTVVBSQmRCRE5sVlN6R0FQT3lY
         | 
| 41 | 
            +
            UDE2ZUkxOWJvbllMaGpiOHVoY0N0bWdicnJhbkpVVGxZc1htcnhvaGNGdW4r
         | 
| 42 | 
            +
            eWZxVFdXd2l4OW1SUXRBdEFFOW5nSUUwVkRkTC9reFR0NktOb1B6d2tlajVW
         | 
| 43 | 
            +
            eFNMRkFncTJ1M3JaTWN1WUdadTFIUT09PC9kczpTaWduYXR1cmVWYWx1ZT4K
         | 
| 44 | 
            +
            ICAgICAgPEtleUluZm8geG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAv
         | 
| 45 | 
            +
            MDkveG1sZHNpZyMiPgogICAgICAgIDxkczpYNTA5RGF0YT4KICAgICAgICAg
         | 
| 46 | 
            +
            IDxkczpYNTA5Q2VydGlmaWNhdGU+TUlJQzVEQ0NBY3lnQXdJQkFnSVFOQlRr
         | 
| 47 | 
            +
            dDdxaWNhcEtOc0lYTWNrOHhUQU5CZ2txaGtpRzl3MEJBUXNGQURBdU1Td3dL
         | 
| 48 | 
            +
            Z1lEVlFRREV5TkJSRVpUSUZOcFoyNXBibWNnTFNCc2IyZHBiaTVrY21WemIz
         | 
| 49 | 
            +
            VnlZMlZ6TG1OdmJUQWVGdzB4TVRBMk1UQXhPRFUyTURGYUZ3MHhNakEyTURr
         | 
| 50 | 
            +
            eE9EVTJNREZhTUM0eExEQXFCZ05WQkFNVEkwRkVSbE1nVTJsbmJtbHVaeUF0
         | 
| 51 | 
            +
            SUd4dloybHVMbVJ5WlhOdmRYSmpaWE11WTI5dE1JSUJJakFOQmdrcWhraUc5
         | 
| 52 | 
            +
            dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBcTdBTURHbkJISUd3dDlLUHRM
         | 
| 53 | 
            +
            RDBNMEVYR3VabldHQW1iNXAyRkRjRnp0SkhPSThXWVBxZVJwaHpWU0VrZ1h0
         | 
| 54 | 
            +
            UEloNUp4M2VsUzZoVm43SFZqMld2eklENmpwQjQ1bzhpRGs4UFdnaTE0ZnhH
         | 
| 55 | 
            +
            V0U1bzFQaUI4WHJlMWM1dnMySUc1YVBXSUQ1dUM2YkQwWGduTDk1TWdPOUhH
         | 
| 56 | 
            +
            UFBTUVJGbnVqS05xekZRZHRvQkpJSmF3QWVEL2kveHM3RmpGazl4MWZBMEV5
         | 
| 57 | 
            +
            TENuaCtlYWZmSXBvcmIrMXh4VzJENkQzbVJUZ2ZIeFhyV1I4VzRqSG5pZ2da
         | 
| 58 | 
            +
            aHFkRGhVeHZFYWlRRlRiSU4yRCt6eUI3YVF3UUNIU0ZwZXJCYytSNUZsbGdu
         | 
| 59 | 
            +
            R0FhK3NqYjZnMUZYYmVobUVHd1NheHdSWklEQWhqSVFtYTV3WDV5V0pEeEZ6
         | 
| 60 | 
            +
            UjRwc1RlRlJRSURBUUFCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCekFQ
         | 
| 61 | 
            +
            QzJRUStVdHZrcVFZMm8vam9IR3RudUx5Zmt3ZDc2NERjR0RsY1lLVktFYURD
         | 
| 62 | 
            +
            dm5KeDNneXdSVU9ERVJoRGh1Zkpid3I3T29YVmRodzcwTnRURU11Z0pGcjI5
         | 
| 63 | 
            +
            U2d4bjNDaVRpeVBGU0RHang5MTFhYkt4dEpTQkludkkwMEFqWCtWbElaaG95
         | 
| 64 | 
            +
            ODNZWU9SWEZjeWIrVXZoMnIyU1pVM0FDTnA4TTNjWlI2SjFFREJoUEtZd0VF
         | 
| 65 | 
            +
            VWs4TlRNbVpMM3ZXanFMWldUeVRUaFRyUUYvbEg5UENsdzlPMjl1d2lmaXEy
         | 
| 66 | 
            +
            WHpTeVNyMy9QSHh6cE1Sa0w5YzRFaTQ1UURtYWdlckFVUndlcTVwVVc4QzNV
         | 
| 67 | 
            +
            QVVqTExWY1hrLzJwZXZaRU43MFlndDVwMmZBZ3M4NE9KaERSS2lIR3BhcmlF
         | 
| 68 | 
            +
            bWo0THNKR1pzcDdxRkpwbjErTWlqUmU8L2RzOlg1MDlDZXJ0aWZpY2F0ZT4K
         | 
| 69 | 
            +
            ICAgICAgICA8L2RzOlg1MDlEYXRhPgogICAgICA8L0tleUluZm8+CiAgICA8
         | 
| 70 | 
            +
            L2RzOlNpZ25hdHVyZT4KICAgIDxTdWJqZWN0PgogICAgICA8TmFtZUlEIEZv
         | 
| 71 | 
            +
            cm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3Jt
         | 
| 72 | 
            +
            YXQ6ZW1haWxBZGRyZXNzIj5oZWxsb0BleGFtcGxlLmNvbTwvTmFtZUlEPgog
         | 
| 73 | 
            +
            ICAgICA8U3ViamVjdENvbmZpcm1hdGlvbiBNZXRob2Q9InVybjpvYXNpczpu
         | 
| 74 | 
            +
            YW1lczp0YzpTQU1MOjIuMDpjbTpiZWFyZXIiPgogICAgICAgIDxTdWJqZWN0
         | 
| 75 | 
            +
            Q29uZmlybWF0aW9uRGF0YSBJblJlc3BvbnNlVG89Il9mYzRhMzRiMC03ZWZi
         | 
| 76 | 
            +
            LTAxMmUtY2FhZS03ODJiY2IxM2JiMzgiIE5vdE9uT3JBZnRlcj0iMjAxMS0w
         | 
| 77 | 
            +
            Ni0yMlQxMjo1NDozMC4zNDhaIiBSZWNpcGllbnQ9Imh0dHBzOi8vc29tZW9u
         | 
| 78 | 
            +
            ZS5leGFtcGxlLmNvbS9lbmRwb2ludCIvPgogICAgICA8L1N1YmplY3RDb25m
         | 
| 79 | 
            +
            aXJtYXRpb24+CiAgICA8L1N1YmplY3Q+CiAgICA8Q29uZGl0aW9ucyBOb3RC
         | 
| 80 | 
            +
            ZWZvcmU9IjIwMTEtMDYtMjJUMTI6NDk6MzAuMzMyWiIgTm90T25PckFmdGVy
         | 
| 81 | 
            +
            PSIyMDExLTA2LTIyVDEzOjQ5OjMwLjMzMloiPgogICAgICA8QXVkaWVuY2VS
         | 
| 82 | 
            +
            ZXN0cmljdGlvbj4KICAgICAgICA8QXVkaWVuY2U+ZXhhbXBsZS5jb208L0F1
         | 
| 83 | 
            +
            ZGllbmNlPgogICAgICA8L0F1ZGllbmNlUmVzdHJpY3Rpb24+CiAgICA8L0Nv
         | 
| 84 | 
            +
            bmRpdGlvbnM+CiAgICA8QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIy
         | 
| 85 | 
            +
            MDExLTA2LTIyVDEyOjQ5OjMwLjExMloiIFNlc3Npb25JbmRleD0iXzcyMWI0
         | 
| 86 | 
            +
            YTVhLWQ3ZTEtNDg2MS05NzU0LWE5YjE5N2I2ZjlhYiI+CiAgICAgIDxBdXRo
         | 
| 87 | 
            +
            bkNvbnRleHQ+CiAgICAgICAgPEF1dGhuQ29udGV4dENsYXNzUmVmPnVybjpv
         | 
| 88 | 
            +
            YXNpczpuYW1lczp0YzpTQU1MOjIuMDphYzpjbGFzc2VzOlBhc3N3b3JkUHJv
         | 
| 89 | 
            +
            dGVjdGVkVHJhbnNwb3J0PC9BdXRobkNvbnRleHRDbGFzc1JlZj4KICAgICAg
         | 
| 90 | 
            +
            PC9BdXRobkNvbnRleHQ+CiAgICA8L0F1dGhuU3RhdGVtZW50PgogIDwvQXNz
         | 
| 91 | 
            +
            ZXJ0aW9uPgo8L3NhbWxwOlJlc3BvbnNlPgo=
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            <?xml version="1.0" encoding="UTF-8"?>
         | 
| 2 | 
            +
            <saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="https://example.hello.com/access/saml" ID="jVFQbyEpSfUwqhZtJtarIaGoshwuAQMDwLoiMhzJXsv" InResponseTo="cfeooghajnhofcmogakmlhpkohnmikicnfhdnjlc" IssueInstant="2011-06-21T13:54:38.661Z" Version="2.0">
         | 
| 3 | 
            +
              <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://idm.orademo.com</saml2:Issuer>
         | 
| 4 | 
            +
              <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
         | 
| 5 | 
            +
                <ds:SignedInfo>
         | 
| 6 | 
            +
                  <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
         | 
| 7 | 
            +
                  <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
         | 
| 8 | 
            +
                  <ds:Reference URI="#jVFQbyEpSfUwqhZtJtarIaGoshwuAQMDwLoiMhzJXsv">
         | 
| 9 | 
            +
                    <ds:Transforms>
         | 
| 10 | 
            +
                      <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
         | 
| 11 | 
            +
                      <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
         | 
| 12 | 
            +
                        <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
         | 
| 13 | 
            +
                      </ds:Transform>
         | 
| 14 | 
            +
                    </ds:Transforms>
         | 
| 15 | 
            +
                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
         | 
| 16 | 
            +
                    <ds:DigestValue>uHuSry39P16Yh7srS32xESmj4Lw=</ds:DigestValue>
         | 
| 17 | 
            +
                  </ds:Reference>
         | 
| 18 | 
            +
                </ds:SignedInfo>
         | 
| 19 | 
            +
                <ds:SignatureValue>fdghdfggfd=</ds:SignatureValue>
         | 
| 20 | 
            +
                <ds:KeyInfo>
         | 
| 21 | 
            +
                  <ds:X509Data>
         | 
| 22 | 
            +
                    <ds:X509Certificate>dfghjkl</ds:X509Certificate>
         | 
| 23 | 
            +
                  </ds:X509Data>
         | 
| 24 | 
            +
                </ds:KeyInfo>
         | 
| 25 | 
            +
              </ds:Signature>
         | 
| 26 | 
            +
              <saml2p:Status>
         | 
| 27 | 
            +
                <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
         | 
| 28 | 
            +
              </saml2p:Status>
         | 
| 29 | 
            +
              <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="emmCjammnYdAbMWDuMAJeZvQIMBayeeYqqwvQoDclKE" IssueInstant="2011-06-21T13:54:38.676Z" Version="2.0">
         | 
| 30 | 
            +
                <saml2:Issuer>https://idm.orademo.com</saml2:Issuer>
         | 
| 31 | 
            +
                <saml2:Subject>
         | 
| 32 | 
            +
                  <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" NameQualifier="idp.example.org">someone@example.org</saml2:NameID>
         | 
| 33 | 
            +
                  <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
         | 
| 34 | 
            +
                    <saml2:SubjectConfirmationData InResponseTo="cfeooghajnhofcmogakmlhpkohnmikicnfhdnjlc" NotOnOrAfter="2011-06-21T14:09:38.676Z" Recipient="https://example.hello.com/access/saml"/>
         | 
| 35 | 
            +
                  </saml2:SubjectConfirmation>
         | 
| 36 | 
            +
                </saml2:Subject>
         | 
| 37 | 
            +
                <saml2:Conditions NotBefore="2011-06-21T13:54:38.683Z" NotOnOrAfter="2011-06-21T14:09:38.683Z">
         | 
| 38 | 
            +
                  <saml2:AudienceRestriction>
         | 
| 39 | 
            +
                    <saml2:Audience>hello.com</saml2:Audience>
         | 
| 40 | 
            +
                  </saml2:AudienceRestriction>
         | 
| 41 | 
            +
                </saml2:Conditions>
         | 
| 42 | 
            +
                <saml2:AuthnStatement AuthnInstant="2011-06-21T13:54:38.685Z" SessionIndex="perdkjfskdjfksdiertusfsdfsddeurtherukjdfgkdffg">
         | 
| 43 | 
            +
                  <saml2:AuthnContext>
         | 
| 44 | 
            +
                    <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
         | 
| 45 | 
            +
                  </saml2:AuthnContext>
         | 
| 46 | 
            +
                </saml2:AuthnStatement>
         | 
| 47 | 
            +
                <saml2:AttributeStatement>
         | 
| 48 | 
            +
                  <saml2:Attribute Name="FirstName">
         | 
| 49 | 
            +
                    <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Someone</saml2:AttributeValue>
         | 
| 50 | 
            +
                  </saml2:Attribute>
         | 
| 51 | 
            +
                  <saml2:Attribute Name="LastName">
         | 
| 52 | 
            +
                    <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Special</saml2:AttributeValue>
         | 
| 53 | 
            +
                  </saml2:Attribute>
         | 
| 54 | 
            +
                </saml2:AttributeStatement>
         | 
| 55 | 
            +
              </saml2:Assertion>
         | 
| 56 | 
            +
            </saml2p:Response>
         | 
| @@ -0,0 +1,71 @@ | |
| 1 | 
            +
            <?xml version="1.0"?>
         | 
| 2 | 
            +
            <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="pfxc32aed67-820f-4296-0c20-205a10dd5787" Version="2.0" IssueInstant="2011-06-17T14:54:14Z" Destination="https://example.hello.com/access/saml" InResponseTo="_57bcbf70-7b1f-012e-c821-782bcb13bb38">
         | 
| 3 | 
            +
              <saml:Issuer>https://federate.example.net/saml/saml2/idp/metadata.php</saml:Issuer>
         | 
| 4 | 
            +
              <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
         | 
| 5 | 
            +
                <ds:SignedInfo>
         | 
| 6 | 
            +
                  <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
         | 
| 7 | 
            +
                  <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
         | 
| 8 | 
            +
                  <ds:Reference URI="#pfxc32aed67-820f-4296-0c20-205a10dd5787">
         | 
| 9 | 
            +
                    <ds:Transforms>
         | 
| 10 | 
            +
                      <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
         | 
| 11 | 
            +
                      <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
         | 
| 12 | 
            +
                    </ds:Transforms>
         | 
| 13 | 
            +
                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
         | 
| 14 | 
            +
                    <ds:DigestValue>dVJ592k5xPjCHBCMiJ8eZkPUiT8=</ds:DigestValue>
         | 
| 15 | 
            +
                  </ds:Reference>
         | 
| 16 | 
            +
                </ds:SignedInfo>
         | 
| 17 | 
            +
                <ds:SignatureValue>LHNK1FJfcOIUuWVKJmGABQ+W98+pQ==</ds:SignatureValue>
         | 
| 18 | 
            +
                <ds:KeyInfo>
         | 
| 19 | 
            +
                  <ds:X509Data>
         | 
| 20 | 
            +
                    <ds:X509Certificate>MIIQmS6WmmIht3k=</ds:X509Certificate>
         | 
| 21 | 
            +
                  </ds:X509Data>
         | 
| 22 | 
            +
                </ds:KeyInfo>
         | 
| 23 | 
            +
              </ds:Signature>
         | 
| 24 | 
            +
              <samlp:Status>
         | 
| 25 | 
            +
                <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
         | 
| 26 | 
            +
              </samlp:Status>
         | 
| 27 | 
            +
              <saml:Assertion xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="pfx7841991c-c73f-4035-e2ee-c170c0e1d3e4" Version="2.0" IssueInstant="2011-06-17T14:54:14Z">
         | 
| 28 | 
            +
                <saml:Issuer>https://federate.example.net/saml/saml2/idp/metadata.php</saml:Issuer>
         | 
| 29 | 
            +
                <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
         | 
| 30 | 
            +
                  <ds:SignedInfo>
         | 
| 31 | 
            +
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
         | 
| 32 | 
            +
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
         | 
| 33 | 
            +
                    <ds:Reference URI="#pfx7841991c-c73f-4035-e2ee-c170c0e1d3e4">
         | 
| 34 | 
            +
                      <ds:Transforms>
         | 
| 35 | 
            +
                        <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
         | 
| 36 | 
            +
                        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
         | 
| 37 | 
            +
                      </ds:Transforms>
         | 
| 38 | 
            +
                      <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
         | 
| 39 | 
            +
                      <ds:DigestValue>mi0IAultZkpsZa1XxGx9X4iAPQg=</ds:DigestValue>
         | 
| 40 | 
            +
                    </ds:Reference>
         | 
| 41 | 
            +
                  </ds:SignedInfo>
         | 
| 42 | 
            +
                  <ds:SignatureValue>LqkW39SOYbttYxlGhIBw==</ds:SignatureValue>
         | 
| 43 | 
            +
                  <ds:KeyInfo>
         | 
| 44 | 
            +
                    <ds:X509Data>
         | 
| 45 | 
            +
                      <ds:X509Certificate>MIIGmmIht3k=</ds:X509Certificate>
         | 
| 46 | 
            +
                    </ds:X509Data>
         | 
| 47 | 
            +
                  </ds:KeyInfo>
         | 
| 48 | 
            +
                </ds:Signature>
         | 
| 49 | 
            +
                <saml:Subject>
         | 
| 50 | 
            +
                  <saml:NameID SPNameQualifier="hello.com" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">someone@example.com</saml:NameID>
         | 
| 51 | 
            +
                  <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
         | 
| 52 | 
            +
                    <saml:SubjectConfirmationData NotOnOrAfter="2011-06-17T14:59:14Z" Recipient="https://example.hello.com/access/saml" InResponseTo="_57bcbf70-7b1f-012e-c821-782bcb13bb38"/>
         | 
| 53 | 
            +
                  </saml:SubjectConfirmation>
         | 
| 54 | 
            +
                </saml:Subject>
         | 
| 55 | 
            +
                <saml:Conditions NotBefore="2011-06-17T14:53:44Z" NotOnOrAfter="2011-06-17T14:59:14Z">
         | 
| 56 | 
            +
                  <saml:AudienceRestriction>
         | 
| 57 | 
            +
                    <saml:Audience>hello.com</saml:Audience>
         | 
| 58 | 
            +
                  </saml:AudienceRestriction>
         | 
| 59 | 
            +
                </saml:Conditions>
         | 
| 60 | 
            +
                <saml:AuthnStatement AuthnInstant="2011-06-17T14:54:07Z" SessionNotOnOrAfter="2011-06-17T22:54:14Z" SessionIndex="_51be37965feb5579d803141076936dc2e9d1d98ebf">
         | 
| 61 | 
            +
                  <saml:AuthnContext>
         | 
| 62 | 
            +
                    <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
         | 
| 63 | 
            +
                  </saml:AuthnContext>
         | 
| 64 | 
            +
                </saml:AuthnStatement>
         | 
| 65 | 
            +
                <saml:AttributeStatement>
         | 
| 66 | 
            +
                  <saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
         | 
| 67 | 
            +
                    <saml:AttributeValue xsi:type="xs:string">someone@example.com</saml:AttributeValue>
         | 
| 68 | 
            +
                  </saml:Attribute>
         | 
| 69 | 
            +
                </saml:AttributeStatement>
         | 
| 70 | 
            +
              </saml:Assertion>
         | 
| 71 | 
            +
            </samlp:Response>
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class SettingsTest < Test::Unit::TestCase
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              context "Settings" do
         | 
| 6 | 
            +
                setup do
         | 
| 7 | 
            +
                  @settings = Onelogin::Saml::Settings.new
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
                should "should provide getters and settings" do
         | 
| 10 | 
            +
                  accessors = [
         | 
| 11 | 
            +
                    :assertion_consumer_service_url, :issuer, :sp_name_qualifier, :sp_name_qualifier,
         | 
| 12 | 
            +
                    :idp_sso_target_url, :idp_cert_fingerprint, :name_identifier_format
         | 
| 13 | 
            +
                  ]
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  accessors.each do |accessor|
         | 
| 16 | 
            +
                    value = Kernel.rand
         | 
| 17 | 
            +
                    @settings.send("#{accessor}=".to_sym, value)
         | 
| 18 | 
            +
                    assert_equal value, @settings.send(accessor)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            end
         | 
    
        data/test/test_helper.rb
    CHANGED
    
    | @@ -2,12 +2,22 @@ require 'rubygems' | |
| 2 2 | 
             
            require 'test/unit'
         | 
| 3 3 | 
             
            require 'shoulda'
         | 
| 4 4 | 
             
            require 'mocha'
         | 
| 5 | 
            +
            require 'ruby-debug'
         | 
| 5 6 |  | 
| 6 7 | 
             
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         | 
| 7 8 | 
             
            $LOAD_PATH.unshift(File.dirname(__FILE__))
         | 
| 8 9 | 
             
            require 'ruby-saml'
         | 
| 9 10 |  | 
| 10 11 | 
             
            class Test::Unit::TestCase
         | 
| 12 | 
            +
              def fixture(document, base64 = true)
         | 
| 13 | 
            +
                response = Dir.glob(File.join(File.dirname(__FILE__), "responses", "#{document}*")).first
         | 
| 14 | 
            +
                if base64 && response =~ /\.xml$/
         | 
| 15 | 
            +
                  Base64.encode64(File.read(response))
         | 
| 16 | 
            +
                else
         | 
| 17 | 
            +
                  File.read(response)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 11 21 | 
             
              def response_document
         | 
| 12 22 | 
             
                @response_document ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response1.xml.base64'))
         | 
| 13 23 | 
             
              end
         | 
    
        data/test/xml_security_test.rb
    CHANGED
    
    | @@ -10,7 +10,7 @@ class XmlSecurityTest < Test::Unit::TestCase | |
| 10 10 |  | 
| 11 11 | 
             
                should "should run validate without throwing NS related exceptions" do
         | 
| 12 12 | 
             
                  base64cert = @document.elements["//ds:X509Certificate"].text
         | 
| 13 | 
            -
                  @document.validate_doc(base64cert,  | 
| 13 | 
            +
                  @document.validate_doc(base64cert, true)
         | 
| 14 14 | 
             
                end
         | 
| 15 15 | 
             
              end
         | 
| 16 16 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: ruby-saml
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 3
         | 
| 5 5 | 
             
              prerelease: false
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 0
         | 
| 8 8 | 
             
              - 4
         | 
| 9 | 
            -
              -  | 
| 10 | 
            -
              version: 0.4. | 
| 9 | 
            +
              - 6
         | 
| 10 | 
            +
              version: 0.4.6
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - OneLogin LLC
         | 
| @@ -15,7 +15,7 @@ autorequire: | |
| 15 15 | 
             
            bindir: bin
         | 
| 16 16 | 
             
            cert_chain: []
         | 
| 17 17 |  | 
| 18 | 
            -
            date: 2011-06- | 
| 18 | 
            +
            date: 2011-06-28 00:00:00 +02:00
         | 
| 19 19 | 
             
            default_executable: 
         | 
| 20 20 | 
             
            dependencies: 
         | 
| 21 21 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -63,7 +63,7 @@ dependencies: | |
| 63 63 | 
             
              type: :development
         | 
| 64 64 | 
             
              version_requirements: *id003
         | 
| 65 65 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 66 | 
            -
              name:  | 
| 66 | 
            +
              name: ruby-debug
         | 
| 67 67 | 
             
              prerelease: false
         | 
| 68 68 | 
             
              requirement: &id004 !ruby/object:Gem::Requirement 
         | 
| 69 69 | 
             
                none: false
         | 
| @@ -76,6 +76,20 @@ dependencies: | |
| 76 76 | 
             
                    version: "0"
         | 
| 77 77 | 
             
              type: :development
         | 
| 78 78 | 
             
              version_requirements: *id004
         | 
| 79 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 80 | 
            +
              name: mocha
         | 
| 81 | 
            +
              prerelease: false
         | 
| 82 | 
            +
              requirement: &id005 !ruby/object:Gem::Requirement 
         | 
| 83 | 
            +
                none: false
         | 
| 84 | 
            +
                requirements: 
         | 
| 85 | 
            +
                - - ">="
         | 
| 86 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 87 | 
            +
                    hash: 3
         | 
| 88 | 
            +
                    segments: 
         | 
| 89 | 
            +
                    - 0
         | 
| 90 | 
            +
                    version: "0"
         | 
| 91 | 
            +
              type: :development
         | 
| 92 | 
            +
              version_requirements: *id005
         | 
| 79 93 | 
             
            description: SAML toolkit for Ruby on Rails
         | 
| 80 94 | 
             
            email: support@onelogin.com
         | 
| 81 95 | 
             
            executables: []
         | 
| @@ -96,16 +110,22 @@ files: | |
| 96 110 | 
             
            - lib/onelogin/saml/authrequest.rb
         | 
| 97 111 | 
             
            - lib/onelogin/saml/response.rb
         | 
| 98 112 | 
             
            - lib/onelogin/saml/settings.rb
         | 
| 113 | 
            +
            - lib/onelogin/saml/validation_error.rb
         | 
| 99 114 | 
             
            - lib/ruby-saml.rb
         | 
| 100 115 | 
             
            - lib/xml_security.rb
         | 
| 101 116 | 
             
            - ruby-saml.gemspec
         | 
| 117 | 
            +
            - test/request_test.rb
         | 
| 118 | 
            +
            - test/response_test.rb
         | 
| 119 | 
            +
            - test/responses/adfs_response.xml.base64
         | 
| 102 120 | 
             
            - test/responses/certificate1
         | 
| 121 | 
            +
            - test/responses/open_saml_response.xml
         | 
| 103 122 | 
             
            - test/responses/response1.xml.base64
         | 
| 104 123 | 
             
            - test/responses/response2.xml.base64
         | 
| 105 124 | 
             
            - test/responses/response3.xml.base64
         | 
| 106 125 | 
             
            - test/responses/response4.xml.base64
         | 
| 107 126 | 
             
            - test/responses/response5.xml.base64
         | 
| 108 | 
            -
            - test/ | 
| 127 | 
            +
            - test/responses/simple_saml_php.xml
         | 
| 128 | 
            +
            - test/settings_test.rb
         | 
| 109 129 | 
             
            - test/test_helper.rb
         | 
| 110 130 | 
             
            - test/xml_security_test.rb
         | 
| 111 131 | 
             
            has_rdoc: true
         | 
| @@ -143,6 +163,8 @@ signing_key: | |
| 143 163 | 
             
            specification_version: 3
         | 
| 144 164 | 
             
            summary: SAML Ruby Tookit
         | 
| 145 165 | 
             
            test_files: 
         | 
| 146 | 
            -
            - test/ | 
| 166 | 
            +
            - test/request_test.rb
         | 
| 167 | 
            +
            - test/response_test.rb
         | 
| 168 | 
            +
            - test/settings_test.rb
         | 
| 147 169 | 
             
            - test/test_helper.rb
         | 
| 148 170 | 
             
            - test/xml_security_test.rb
         |